Added preliminary command support. From Ildefond Magrans <ildefons@ifae.es>
authorDavid Schleef <ds@schleef.org>
Tue, 15 Jan 2002 11:25:42 +0000 (11:25 +0000)
committerDavid Schleef <ds@schleef.org>
Tue, 15 Jan 2002 11:25:42 +0000 (11:25 +0000)
comedi/drivers/ni_pcidio.c

index 9d39ccbd50ebcdc150cd7e458086a4dd4a317858..09d3f3eb15d012ceabdbdc7ad206790848f97940 100644 (file)
@@ -58,6 +58,8 @@ AT-MIO96.
 
  */
 
+//#define USE_CMD 1
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/comedidev.h>
@@ -167,6 +169,8 @@ AT-MIO96.
 #define ClockSpeed                     Protocol_Register_14
 #define DAQOptions                     Protocol_Register_15
 
+#define IntEn 3
+
 static int nidio_attach(comedi_device *dev,comedi_devconfig *it);
 static int nidio_detach(comedi_device *dev);
 comedi_driver driver_pcidio={
@@ -263,10 +267,12 @@ typedef struct{
 }nidio96_private;
 #define devpriv ((nidio96_private *)dev->private)
 
-static int nidio_find_device(comedi_device *dev,int bus,int slot);
-#if 0
-static int setup_mite(comedi_device *dev);
+#ifdef USE_CMD
+static int ni_pcidio_cmdtest(comedi_device *dev,comedi_subdevice *s,
+                                 comedi_cmd *cmd);
+static int ni_pcidio_cmd(comedi_device *dev,comedi_subdevice *s);
 #endif
+static int nidio_find_device(comedi_device *dev,int bus,int slot);
 
 static int nidio96_8255_cb(int dir,int port,int data,unsigned long iobase)
 {
@@ -278,15 +284,157 @@ static int nidio96_8255_cb(int dir,int port,int data,unsigned long iobase)
        }
 }
 
-#ifdef not_working
+#ifdef USE_CMD
 static void nidio_interrupt(int irq, void *d, struct pt_regs *regs)
 {
        comedi_device *dev=d;
-       //comedi_subdevice *s=dev->subdevices;
+       comedi_subdevice *s=dev->subdevices;
        int a,b;
        static int n_int=0;
-       //int i;
+       int i;
        struct timeval tv;
+       //int tag=0;
+       long int AuxData = 0;
+       sampl_t MyData1 = 0;
+       sampl_t MyData2 = 0;
+       comedi_async *async;
+       int Flags;
+       int Status;
+       int j;
+
+
+       //writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
+       
+
+       async = s->async;
+       async->events = 0;      
+       
+       //printk("%d ",async->buf_int_count);
+       
+       //writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
+
+       Flags = readb(dev->iobase+Group_Flags);
+       
+       //IntEn es un parametre!!!!
+       
+       Status = readb(dev->iobase+Interrupt_And_Window_Status);
+       
+       //interrupcions parasites
+        if(dev->attached == 0)
+          {
+            comedi_error(dev,"premature interrupt");
+            async->events |= COMEDI_CB_ERROR|COMEDI_CB_EOA;    
+          }
+        
+        if((Flags & (TransferReady | CountExpired | Waited | PrimaryTC | SecondaryTC))==0)
+          {
+            comedi_error(dev,"spurious interrupt");
+            async->events |= COMEDI_CB_ERROR|COMEDI_CB_EOA;    
+          }
+        // printk("IntEn=%d,Flags=%d,Status=%d\n",IntEn,Flags,Status);
+        
+        while(Status&1)
+          {
+            //printk("1)IntEn=%d,Flags=%d,Status=%d\n",IntEn,Flags,Status);
+            //printk("hola11\n");
+           
+           if(Flags & IntEn & CountExpired)
+             {
+               printk("count expired ");
+               writeb(CountExpired,dev->iobase+Group_First_Clear);
+               async->events |= COMEDI_CB_EOA; 
+               async->events |= COMEDI_CB_BLOCK;
+               //for(i=0;i<16;i++)
+               //{
+                   AuxData = readl(dev->iobase+Group_FIFO);
+                   MyData1 = AuxData & 0xffff;
+                   MyData2 = (AuxData & 0xffff0000) >> 16;
+                   comedi_buf_put(async,MyData1);
+                   comedi_buf_put(async,MyData2);
+                   //printk("lectura:%d, %d\n",MyData1,MyData2);
+                   //}
+               
+               writeb(0x00,dev->iobase+OpMode);
+               writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
+               writeb(0xff,dev->iobase+Group_First_Clear);
+               writeb(0xff,dev->iobase+Group_First_Clear);
+               break;
+             }
+           
+           else if(Flags & IntEn & TransferReady)
+             {
+               //aixo no surt en el manual de NI
+               writeb(TransferReady,dev->iobase+Group_First_Clear);
+               //printk("transfer ready 1ยบ");
+               //for(i=0;i<16;i++)
+               //{
+               /*Flags = 0;
+                   j=0;
+                   while(!(Flags & TransferReady) && j<320)
+                      {
+                       Flags = readb(dev->iobase+Group_Flags);
+                       //printk("Flags:%d ",Flags);
+                       j++;
+                       }*/
+                   AuxData = readl(dev->iobase+Group_FIFO);
+                   MyData1 = AuxData & 0xffff;
+                   MyData2 = (AuxData & 0xffff0000) >> 16;
+                   comedi_buf_put(async,MyData1);
+                   comedi_buf_put(async,MyData2);
+                   //printk("lectura:%d, %d\n",MyData1,MyData2);
+                   //Flags = readb(dev->iobase+Group_Flags);
+                   //}
+               //  Flags = readb(dev->iobase+Group_Flags);
+               // }
+               //printk("%d ",async->buf_int_count);
+               //printk("1)IntEn=%d,Flags=%d,Status=%d\n",IntEn,Flags,Status);
+               async->events |= COMEDI_CB_BLOCK;
+             }
+           
+           else if(Flags & IntEn & Waited)
+             {
+               printk("waited\n");
+               writeb(Waited,dev->iobase+Group_First_Clear);
+               writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
+             }
+           
+           else if(Flags & IntEn & PrimaryTC)
+             {
+               printk("primaryTC\n");
+               writeb(PrimaryTC,dev->iobase+Group_First_Clear);
+               async->events |= COMEDI_CB_EOA;
+               writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
+             }
+           
+           else if(Flags & IntEn & SecondaryTC)
+             {
+               printk("secondaryTC\n");
+               writeb(SecondaryTC,dev->iobase+Group_First_Clear);
+               async->events |= COMEDI_CB_EOA;
+               writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
+             }
+           
+           /*else
+             {
+               printk("interrupcio desconeguda\n");
+               async->events |= COMEDI_CB_ERROR|COMEDI_CB_EOA;
+               writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
+               }*/
+       
+           Flags = readb(dev->iobase+Group_Flags);
+           Status = readb(dev->iobase+Interrupt_And_Window_Status);
+           //printk("2) IntEn=%d,Flags=%d,Status=%d\n",IntEn,Flags,Status);
+          }
+
+       comedi_event(dev,s,async->events);
+       async->events = 0;
+           
+       //printk("hola2\n");
+
+       //if  (!tag) 
+       //  writeb(0x03,dev->iobase+Master_DMA_And_Interrupt_Control);
+
+       /*
 
        do_gettimeofday(&tv);
        a=readb(dev->iobase+Group_Status);
@@ -306,7 +454,8 @@ static void nidio_interrupt(int irq, void *d, struct pt_regs *regs)
        if(n_int < 10){
                DPRINTK("new status 0x%02x\n",b);
                n_int++;
-       }
+               }*/
+       return;
 }
 #endif
 
@@ -343,7 +492,198 @@ static int ni_pcidio_insn_bits(comedi_device *dev,comedi_subdevice *s,
        return 2;
 }
 
-#ifdef not_working
+#ifdef USE_CMD
+static int ni_pcidio_cmdtest(comedi_device *dev,comedi_subdevice *s,
+       comedi_cmd *cmd)
+{
+       int err=0;
+       int tmp;
+
+       /* cmdtest tests a particular command to see if it is valid.
+        * Using the cmdtest ioctl, a user can create a valid cmd
+        * and then have it executes by the cmd ioctl.
+        *
+        * cmdtest returns 1,2,3,4 or 0, depending on which tests
+        * the command passes. */
+
+       /* step 1: make sure trigger sources are trivially valid */
+
+       tmp=cmd->start_src;
+       cmd->start_src &= TRIG_NOW;
+       if(!cmd->start_src || tmp!=cmd->start_src)err++;
+
+       tmp=cmd->scan_begin_src;
+       cmd->scan_begin_src &= TRIG_TIMER|TRIG_EXT;
+       if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++;
+
+       tmp=cmd->convert_src;
+       cmd->convert_src &= TRIG_TIMER|TRIG_EXT;
+       if(!cmd->convert_src || tmp!=cmd->convert_src)err++;
+
+       tmp=cmd->scan_end_src;
+       cmd->scan_end_src &= TRIG_COUNT;
+       if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++;
+
+       tmp=cmd->stop_src;
+       cmd->stop_src &= TRIG_COUNT|TRIG_NONE;
+       if(!cmd->stop_src || tmp!=cmd->stop_src)err++;
+
+       if(err)return 1;
+
+       /* step 2: make sure trigger sources are unique and mutually compatible */
+
+       /* note that mutual compatiblity is not an issue here */
+       if(cmd->scan_begin_src!=TRIG_TIMER &&
+          cmd->scan_begin_src!=TRIG_EXT)err++;
+       if(cmd->convert_src!=TRIG_TIMER &&
+          cmd->convert_src!=TRIG_EXT)err++;
+       if(cmd->stop_src!=TRIG_COUNT &&
+          cmd->stop_src!=TRIG_NONE)err++;
+
+       if(err)return 2;
+
+       /* step 3: make sure arguments are trivially compatible */
+
+       if(cmd->start_arg!=0){
+               cmd->start_arg=0;
+               err++;
+       }
+
+#define MAX_SPEED      10000           /* in nanoseconds */
+#define MIN_SPEED      1000000000      /* in nanoseconds */
+
+       if(cmd->scan_begin_src==TRIG_TIMER){
+               if(cmd->scan_begin_arg<MAX_SPEED){
+                       cmd->scan_begin_arg=MAX_SPEED;
+                       err++;
+               }
+               if(cmd->scan_begin_arg>MIN_SPEED){
+                       cmd->scan_begin_arg=MIN_SPEED;
+                       err++;
+               }
+       }else{
+               /* external trigger */
+               /* should be level/edge, hi/lo specification here */
+               /* should specify multiple external triggers */
+               if(cmd->scan_begin_arg>9){
+                       cmd->scan_begin_arg=9;
+                       err++;
+               }
+       }
+       if(cmd->convert_src==TRIG_TIMER){
+               if(cmd->convert_arg<MAX_SPEED){
+                       cmd->convert_arg=MAX_SPEED;
+                       err++;
+               }
+               if(cmd->convert_arg>MIN_SPEED){
+                       cmd->convert_arg=MIN_SPEED;
+                       err++;
+               }
+       }else{
+               /* external trigger */
+               /* see above */
+               if(cmd->convert_arg>9){
+                       cmd->convert_arg=9;
+                       err++;
+               }
+       }
+
+       if(cmd->scan_end_arg!=cmd->chanlist_len){
+               cmd->scan_end_arg=cmd->chanlist_len;
+               err++;
+       }
+       if(cmd->stop_src==TRIG_COUNT){
+               if(cmd->stop_arg>0x00ffffff){
+                       cmd->stop_arg=0x00ffffff;
+                       err++;
+               }
+       }else{
+               /* TRIG_NONE */
+               if(cmd->stop_arg!=0){
+                       cmd->stop_arg=0;
+                       err++;
+               }
+       }
+
+       if(err)return 3;
+
+       /* step 4: fix up any arguments */
+       
+
+       if(err)return 4;
+
+       return 0;
+}
+
+
+static int ni_pcidio_cmd(comedi_device *dev,comedi_subdevice *s)
+{
+  int i;
+
+  writeb(  0 ,dev->iobase+OpMode);
+
+  /*ho vui per entrada(els ports)*/
+  writel(0x0000,dev->iobase+Port_Pin_Directions(0));
+  
+  /* choose chan A,B (grup in,i 4 fifos sense funneling) */
+  writeb(0x0F,dev->iobase+Data_Path);
+  
+  /* set transfer width a 32 bits*/
+  writeb(0x00,dev->iobase+Transfer_Size_Control);
+
+
+  /* protocol configuration */
+  writeb(0x00,dev->iobase+ClockReg);
+  writeb(  0 ,dev->iobase+Sequence);
+  writeb(0x00,dev->iobase+ReqReg);
+  writeb(  4 ,dev->iobase+BlockMode);
+  writeb(  0 ,dev->iobase+LinePolarities);
+  writeb(0x00,dev->iobase+AckSer);
+  writeb(  1 ,dev->iobase+StartDelay);
+  writeb(  1 ,dev->iobase+ReqDelay);
+  writeb(  1 ,dev->iobase+ReqNotDelay);
+  writeb(  1 ,dev->iobase+AckDelay);
+  writeb(0x0C,dev->iobase+AckNotDelay);
+  writeb(0x10,dev->iobase+Data1Delay);
+  writew(  0 ,dev->iobase+ClockSpeed);
+  writeb(0x60,dev->iobase+DAQOptions);
+
+  /* ReadyLevel */
+  /*writeb(  0 ,dev->iobase+FIFO_Control);*/
+  
+  /*for(i=0;i<16;i++){
+    writew(i,dev->iobase+Group_FIFO);
+    }*/
+  //printk("arg:%d\n",s->async->cmd.stop_arg);
+  writel(s->async->cmd.stop_arg,dev->iobase+Transfer_Count);
+  
+#define USEDMA 0
+  if(USEDMA){
+    writeb(0x05,dev->iobase+DMA_Line_Control);
+    writeb(0x30,dev->iobase+Group_First_Clear);
+    
+    mite_dma_prep(devpriv->mite,s);
+  }else{
+    writeb(0x00,dev->iobase+DMA_Line_Control);
+  }
+  
+  /* clear and enable interrupts */
+  writeb(0xff,dev->iobase+Group_First_Clear);
+  /* interrupcions degudas a FIFO ple, s'ha fet totes les transferencies
+     primaryTC=1??? secondaryTC=1???*/
+  writeb(IntEn,dev->iobase+Interrupt_Enable);
+  writeb(0x03,dev->iobase+Master_DMA_And_Interrupt_Control);
+  
+  /* start */
+  /*amb aixo ja s'esta dient numbered=1 + runmode=7*/
+  writeb(0x0f,dev->iobase+OpMode);
+  
+  printk("\nhas configurat la tarja chaval\n");
+  return 0;
+}
+#endif
+
+#ifdef unused
 static int nidio_dio_cmd(comedi_device *dev,comedi_subdevice *s)
 {
        int i;
@@ -463,6 +803,7 @@ static int nidio_attach(comedi_device *dev,comedi_devconfig *it)
        
                s=dev->subdevices+0;
 
+               dev->read_subdev = s;
                s->type=COMEDI_SUBD_DIO;
                s->subdev_flags=SDF_READABLE|SDF_WRITEABLE|SDF_RT;
                s->n_chan=32;
@@ -470,13 +811,17 @@ static int nidio_attach(comedi_device *dev,comedi_devconfig *it)
                s->maxdata=1;
                s->insn_config = ni_pcidio_insn_config;
                s->insn_bits = ni_pcidio_insn_bits;
+#ifdef USE_CMD
+               s->do_cmd = ni_pcidio_cmd;
+               s->do_cmdtest = ni_pcidio_cmdtest;
+#endif
                s->len_chanlist=32;             /* XXX */
 
                writel(0,dev->iobase+Port_IO(0));
                writel(0,dev->iobase+Port_Pin_Directions(0));
                writel(0,dev->iobase+Port_Pin_Mask(0));
 
-#ifdef not_working
+#ifdef USE_CMD
                /* disable interrupts on board */
                writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);