Added Intelligent Instruments PCI-200001C driver
authorDavid Schleef <ds@schleef.org>
Fri, 25 Feb 2000 20:07:31 +0000 (20:07 +0000)
committerDavid Schleef <ds@schleef.org>
Fri, 25 Feb 2000 20:07:31 +0000 (20:07 +0000)
comedi/drivers/ii-pci20kc.c [new file with mode: 0644]

diff --git a/comedi/drivers/ii-pci20kc.c b/comedi/drivers/ii-pci20kc.c
new file mode 100644 (file)
index 0000000..869e82c
--- /dev/null
@@ -0,0 +1,476 @@
+/*
+ *
+ *     PCI20xxx.c
+ *
+ *     Linux device driver for COMEDI
+ *     Intelligent Instrumentation
+ *     PCI-20001 C-2A Carrier Board
+ *     PCI-20341 M-1A 16-Bit analog input module
+ *                             - differential
+ *                             - range (-5V - +5V)
+ *                             - 16 bit
+ *     PCI-20006 M-2 16-Bit analog output module
+ *                             - ranges (-10V - +10V) (0V - +10V) (-5V - +5V)
+ *                             - 16 bit
+ *     
+ *     only ONE PCI-20341 module possible
+ *     only ONE PCI-20006 module possible
+ *     no extern trigger implemented
+ *     only 4 on-board differential channels supported
+ *     only ONE di-port and ONE do-port supported instead of 4 digital ports
+ *     di-port == Port 0
+ *     do-port == Port 1
+ *
+ *     The state of this driver is only a starting point for a complete
+ *     COMEDI-driver. The final driver should support all features of the 
+ *     carrier board and modules.
+ *
+ *     The test configuration:
+ *
+ *     kernel 2.2.13 with RTAI v1.1 (realtime not yet tested)
+ *     COMEDI 0.7.39
+ *     COMEDILIB 0.7.8
+ *
+ *     COMEDI - Linux Control and Measurement Device Interface
+ *     Copyright (C) 1997-8 David A. Schleef <ds@stm.lbl.gov>
+ *
+ *     pci20xxx by Markus Kempf <kempf@matsci.uni-sb.de>
+ *             (GPL)
+ *     25.2.2000       
+ */
+
+#include <linux/module.h>      /* modularer Kernel */
+#include <linux/kernel.h>      /* printk() */
+#include <linux/fs.h>          /* character device definition */
+#include <linux/errno.h>       /* error codes */
+
+#include <asm/io.h>                    /* readb() ... */
+#include <asm/uaccess.h>       /* copy_to/from_user */
+
+#include "comedi_module.h"
+
+
+#define PCI20000_ID                            0x1d
+#define PCI20341_ID                            0x77
+#define PCI20006_ID                    0xe3
+#define PCI20000_OFFSET                0x100
+#define PCI20000_MODULES               3
+#define PCI20341_OPTION                        0x00
+#define PCI20000_DI_PORT               0       /* only ONE di-port is supported */
+#define PCI20000_DO_PORT               1       /* only ONE do-port is supported */
+#define PCI20341_REPMODE               0x00    /* single shot mode */
+#define PCI20341_PACER                 0x00    /* Hardware Pacer disabled */
+#define PCI20341_CHAN_NR               2       /* number of input channels */
+#define CHANNEL_READ                   0x01
+#define CHANNEL_WRITE                  0x01
+
+
+
+typedef struct { 
+               unsigned int ai_mod_pos;                        /* block address of ai module */
+               unsigned int ao_mod_pos;                        /* block address of ao module */
+               unsigned int ao_range_list[2];          /* range of channels of ao module */
+               int dio_port[PCI20000_MODULES+1];       /* port address */
+               int timebase;                                           /* timebase ai module */
+               int settling_time;                                      /* settling time ai module */
+               int ai_gain;                                            /* analog input gain */
+               }pci20xxx_private;
+               
+#define devpriv ((pci20xxx_private *)dev->private)
+#define CHAN (CR_CHAN(it->chanlist[0]))
+
+static int pci20xxx_attach(comedi_device *dev, comedi_devconfig *it);
+static int pci20xxx_detach(comedi_device *dev);
+static int pci20xxx_recognize(char *name);
+
+comedi_driver driver_pci20xxx={
+               driver_name:    "pci20xxx",
+               module:         &__this_module,
+               attach:         pci20xxx_attach,
+               detach:         pci20xxx_detach,
+               recognize:      pci20xxx_recognize,
+               };
+               
+static int pci20xxx_ai_mode0(comedi_device *dev, comedi_subdevice *s, comedi_trig *it);
+static int pci20xxx_ao(comedi_device *dev, comedi_subdevice *s, comedi_trig *it);              
+static int pci20xxx_di(comedi_device *dev, comedi_subdevice *s, comedi_trig *it);
+static int pci20xxx_do(comedi_device *dev, comedi_subdevice *s, comedi_trig *it);
+
+static int pci20xxx_init(comedi_device *dev);
+static int pci20xxx_ai_init(comedi_device *dev);
+static int pci20xxx_di_init(comedi_device *dev);
+static int pci20xxx_do_init(comedi_device *dev);
+
+static int pci20xxx_recognize(char *name)
+       {
+       if(!strcmp("pci20xxx",name))
+               return 0;
+       return -1;
+       }
+
+/*
+  options[0]   Board base address
+  options[1]   IRQ
+  options[2]   Analog input gain configuration
+                1
+                       10
+                       100
+                       200
+  options[3]   Analog output channel 0 range configuration
+                 0 == bipolar 10  (-10V -- +10V)
+                 1 == unipolar 10V  (0V -- +10V)
+                 2 == bipolar 5V  (-5V -- +5V)
+  options[4]   Analog output channel 1 range configuration
+                 0 == bipolar 10  (-10V -- +10V)
+                 1 == unipolar 10V  (0V -- +10V)
+                 2 == bipolar 5V  (-5V -- +5V)
+*/
+static int pci20xxx_attach(comedi_device * dev, comedi_devconfig * it)
+       {
+       unsigned char i;
+       int ret;
+       int isthere = 0;
+       comedi_subdevice *s;
+
+       dev->n_subdevices = 4;
+       if ((ret = alloc_subdevices(dev)) < 0)
+               return ret;
+       if ((ret = alloc_private(dev, sizeof(pci20xxx_private))) < 0)
+               return ret;
+
+       dev->iobase = it->options[0];
+       
+       /* Check PCI-20001 C-2A Carrier Board ID */     
+       if((readb(dev->iobase) & PCI20000_ID) != PCI20000_ID)
+               {
+               printk("comedi%d: \n", dev->minor);
+               printk("PCI-20001 C-2A Carrier Board at base=0x%05x not found !\n", dev->iobase);
+               return -EINVAL;
+               }
+
+       /* looking for input module PCI-20341 M-1A*/    
+       for (i=1; i <= PCI20000_MODULES; i++)
+               {
+               if ( readb(dev->iobase+i*PCI20000_OFFSET) == PCI20341_ID)
+                       {
+                       devpriv->ai_mod_pos = dev->iobase + i*PCI20000_OFFSET;                  
+                       printk("comedi%d: module PCI-20341 opened!\n", dev->minor);
+                       isthere = 1;
+                       }       
+               }
+       if (!isthere)
+               {
+               printk("comedi%d: module PCI-20341 not found!\n", dev->minor);
+               return -EINVAL;
+               }
+
+       /* look for output module PCI-20006 M-2 */
+       for (i=1; i<= PCI20000_MODULES; i++)
+               {
+               if ( readb(dev->iobase+i*PCI20000_OFFSET) == PCI20006_ID)
+                       {
+                       devpriv->ao_mod_pos = dev->iobase + i*PCI20000_OFFSET;
+                       printk("comedi%d: module PCI-20006 opened!\n", dev->minor);
+                       isthere = 1;
+                       }
+               }
+       if (!isthere)
+               {
+               printk("comedi%d: module PCI-20006 not found!\n", dev->minor);
+               return -EINVAL;
+               }
+
+
+       printk("comedi%d: pci20xxx: base=0x%05x\n", dev->minor, dev->iobase);
+
+       dev->board_name = "pci20xxx";
+
+       /* initialize pci20xxx_private */
+       pci20xxx_init(dev);     
+
+       /* options handling */
+       switch (it->options[2])         /* gain */
+               {
+               case 1:         devpriv->ai_gain = 0;                   /* gain 1 */
+                                       devpriv->timebase = 0x00;               /* timebase ai-module */
+                                       devpriv->settling_time = 0x58;  /* settling time ai-modlue */                           
+                                       break;
+               case 10:        devpriv->ai_gain = 1;                   /* gain 10 */
+                                       devpriv->timebase = 0x00;               /* timebase ai-module */
+                                       devpriv->settling_time = 0x58;  /* settling time ai-modlue */                           
+                                       break;          
+               case 100:       devpriv->ai_gain = 2;                   /* gain 100 */
+                                       devpriv->timebase = 0x00;               /* timebase ai-module */
+                                       devpriv->settling_time = 0x93;  /* settling time ai-modlue */                           
+                                       break;          
+               case 200:       devpriv->ai_gain = 3;                   /* gain 200 */
+                                       devpriv->timebase = 0x04;               /* timebase ai-module */
+                                       devpriv->settling_time = 0x99;  /* settling time ai-modlue */                           
+                                       break;
+               default:        devpriv->ai_gain = 0;                   /* gain 1 */
+                                       devpriv->timebase = 0x00;               /* timebase ai-module */
+                                       devpriv->settling_time = 0x58;  /* settling time ai-modlue */                           
+                                       printk("comedi%d: ai default gain = 1 !\n", dev->minor);
+                                       break;
+               }
+       switch  (it->options[3])
+               {
+               case 0: devpriv->ao_range_list[0] = RANGE_bipolar10; break;
+               case 1: devpriv->ao_range_list[0] = RANGE_unipolar10; break;
+               case 2: devpriv->ao_range_list[0] = RANGE_bipolar5; break;
+               default:        devpriv->ao_range_list[0] = RANGE_bipolar10; break;
+               }
+       switch  (it->options[4])
+               {
+               case 0: devpriv->ao_range_list[1] = RANGE_bipolar10; break;
+               case 1: devpriv->ao_range_list[1] = RANGE_unipolar10; break;
+               case 2: devpriv->ao_range_list[1] = RANGE_bipolar5; break;
+               default:        devpriv->ao_range_list[1] = RANGE_bipolar10; break;
+               }               
+               
+       /* initialize the analog subdevices */
+       /* ai subdevice */
+       s = dev->subdevices + 0;
+       s->type = COMEDI_SUBD_AI;
+       s->subdev_flags = SDF_READABLE;
+       s->n_chan = 4;
+       s->trig[0] = pci20xxx_ai_mode0;
+       s->maxdata = 0xffff;
+       s->range_type = RANGE_bipolar5;
+       pci20xxx_ai_init(dev);
+
+       /* ao subdevice */      
+       s = dev->subdevices + 1;
+       s->type = COMEDI_SUBD_AO;
+       s->subdev_flags = SDF_WRITEABLE;
+       s->n_chan = 2;
+       s->trig[0] = pci20xxx_ao;
+       s->maxdata = 0xffff;
+       s->range_type_list = devpriv->ao_range_list;
+
+       /* di subdevice */
+       s = dev->subdevices + 2;
+       s->type = COMEDI_SUBD_DI;
+       s->subdev_flags = SDF_READABLE;
+       s->n_chan = 8;                  /* every bit of a port is one channel */
+       s->trig[0] = pci20xxx_di;
+       s->maxdata = 1;
+       s->range_type = RANGE_digital;
+       pci20xxx_di_init(dev);
+
+       /* do subdevice */
+       s = dev->subdevices + 3;
+       s->type = COMEDI_SUBD_DO;
+       s->subdev_flags = SDF_WRITEABLE;
+       s->n_chan = 8;                  /* every bit of a port is one channel */
+       s->trig[0] = pci20xxx_do;
+       s->maxdata = 1;
+       s->state = 0;           
+       s->range_type = RANGE_digital;
+       pci20xxx_do_init(dev);
+
+       return 1;
+       }
+
+static int pci20xxx_detach(comedi_device * dev)
+       {
+       printk("comedi%d: pci20xxx: remove\n", dev->minor);
+
+       return 0;
+       }
+
+/* initialize pci20xxx_private */
+static int pci20xxx_init(comedi_device *dev)
+       {
+       devpriv->dio_port[0] = 0x80;
+       devpriv->dio_port[1] = 0x81;
+       devpriv->dio_port[2] = 0xc0;
+       devpriv->dio_port[3] = 0xc1;
+
+       return 0;
+       }
+
+
+/* initialize digital output */
+static int pci20xxx_do_init(comedi_device *dev)
+       {
+       unsigned char port;
+
+       /* only ONE do port supported: port1 ! */
+       switch (PCI20000_DO_PORT)
+               {
+               case 0: port = readb(dev->iobase + 0x83);
+                       writeb( (port & 0x82)| 0x80, dev->iobase + 0x83);                       /* port direction */
+                       writeb( 0xff, dev->iobase + devpriv->dio_port[PCI20000_DO_PORT]);       /* write 0xff to port */
+                       port = readb(dev->iobase + 0x82);
+                       writeb( (port & 0xfe)| 0x04, dev->iobase + 0x82);                       /* enable port */
+                       break;
+               case 1: port = readb(dev->iobase + 0x83);
+                       writeb( (port & 0x90)| 0x80, dev->iobase + 0x83);
+                       writeb( 0xff, dev->iobase + devpriv->dio_port[PCI20000_DO_PORT]);
+                       port = readb(dev->iobase + 0x82);
+                       writeb( (port & 0xfd)| 0x08, dev->iobase + 0x82);
+                       break;
+               case 2: port = readb(dev->iobase + 0xc3);
+                       writeb( (port & 0x82)| 0x80, dev->iobase + 0xc3);
+                       writeb( 0xff, dev->iobase + devpriv->dio_port[PCI20000_DO_PORT]);
+                       port = readb(dev->iobase + 0x82);
+                       writeb( (port & 0xef)| 0x40, dev->iobase + 0x82);
+                       break;
+               case 3: port = readb(dev->iobase + 0xc3);
+                       writeb( (port & 0x90)| 0x80, dev->iobase + 0xc3);
+                       writeb( 0xff, dev->iobase + devpriv->dio_port[PCI20000_DO_PORT]);
+                       port = readb(dev->iobase + 0x82);
+                       writeb( (port & 0xdf)| 0x80, dev->iobase + 0x82);
+                       break;
+               default: printk("comedi%d: wrong DO-port in pci20xxx_do_init()", dev->minor);
+                               return -EINVAL;
+               }
+       writeb( 0xff, dev->iobase + devpriv->dio_port[PCI20000_DO_PORT]);               
+       
+       return 0;
+       }
+
+/* initialize digital input */
+static int pci20xxx_di_init(comedi_device *dev)
+       {
+       unsigned char port;
+
+       /* only ONE di port supported: port0 ! */
+       switch (PCI20000_DI_PORT)
+               {
+               case 0: port = readb(dev->iobase + 0x83);
+                       writeb( port|0x90, dev->iobase + 0x83);
+                       port = readb(dev->iobase + 0x82);
+                       writeb( port & 0xfa, dev->iobase + 0x82);
+                       break;
+               case 1: port = readb(dev->iobase + 0x83);
+                       writeb( port|0x82, dev->iobase + 0x83);
+                       port = readb(dev->iobase + 0x82);
+                       writeb( port & 0xf5, dev->iobase + 0x82);
+                       break;
+               case 2: port = readb(dev->iobase + 0xc3);
+                       writeb( port|0x90, dev->iobase + 0xc3);
+                       port = readb(dev->iobase + 0x82);
+                       writeb( port & 0xaf, dev->iobase + 0x82);
+                       break;
+               case 3: port = readb(dev->iobase + 0xc3);
+                       writeb( port|0x82, dev->iobase + 0xc3);
+                       port = readb(dev->iobase + 0x82);
+                       writeb( port & 0x5f, dev->iobase + 0x82);
+                       break;
+               default: printk("comedi%d: wrong DI-port in pci20xxx_di_init()", dev->minor);
+                               return -EINVAL;
+               }
+
+       return 0;
+       }
+
+/* initialize analog input */
+static int pci20xxx_ai_init(comedi_device *dev)
+       {
+       int option = PCI20341_OPTION;           /* depends on gain, trigger, repetition mode */
+
+       option = devpriv->timebase | PCI20341_REPMODE;  
+               
+       writeb( 0x04, devpriv->ai_mod_pos + 0x10);                                              /* initialize Module */
+       writeb( PCI20341_PACER, devpriv->ai_mod_pos + 0x01);                            /* set Pacer */
+       writeb( option, devpriv->ai_mod_pos + 0x11);                                    /* option register */
+       writeb( devpriv->settling_time, devpriv->ai_mod_pos + 0x15);    /* settling time counter */
+       /* trigger not implemented */
+       /* Burst mode disabled, only one channel is read */
+       writeb( CHANNEL_READ, devpriv->ai_mod_pos + 0x13);                              /* write number of input channels */
+
+       return 0;
+       }
+
+static int pci20xxx_ao(comedi_device *dev, comedi_subdevice *s, comedi_trig *it)
+       {
+       int hi, lo;
+       
+       lo = (it->data[0] & 0xff);
+       hi = ((it->data[0] >>8) & 0xff);
+        
+       switch (CHAN)
+               {
+               case 0: writeb( lo, devpriv->ao_mod_pos + 0x0d);                
+                               writeb( hi, devpriv->ao_mod_pos + 0x0d + 1);
+                               writeb( 0x00, devpriv->ao_mod_pos + 0x0b);
+                               break;
+               case 1: writeb( lo, devpriv->ao_mod_pos + 0x15);                
+                               writeb( hi, devpriv->ao_mod_pos + 0x15 + 1);
+                               writeb( 0x00, devpriv->ao_mod_pos + 0x13);
+                               break;          
+               default: printk(" comedi%d: pci20xxx: ao channel Error!\n", dev->minor);
+                                return -EINVAL;
+               }                               
+       return CHANNEL_WRITE;   /* return value == number of written datas */
+       }
+
+static int pci20xxx_do(comedi_device *dev, comedi_subdevice *s, comedi_trig *it)
+       {
+       do_pack(&s->state, it);
+
+       writeb(s->state, dev->iobase + devpriv->dio_port[PCI20000_DO_PORT]);
+
+       return it->n_chan;
+       }
+
+static int pci20xxx_ai_mode0(comedi_device *dev, comedi_subdevice *s, comedi_trig *it)
+       {
+       int     i=0, 
+               j=0; 
+       int lo, hi;
+       writeb( (0x24|(devpriv->ai_gain<<3)|CHAN), devpriv->ai_mod_pos + 0x80); 
+       writeb( 0x00, devpriv->ai_mod_pos + 0x1b);                                              /* reset settling time counter and trigger delay counter */
+       writeb( 0x00, devpriv->ai_mod_pos + 0x19);      
+
+       i = readb( devpriv->ai_mod_pos + 0x04); /* generate Pacer */
+
+       /* data polling isn't the niciest way to get the data, I know,
+        * but there are only 6 cycles (mean) and it is easier than
+        * the whole interrupt stuff 
+        */
+       while ( (i<0x80) && j<100)              /* poll Interrupt Flag */
+               {
+               j++;
+               i = readb(devpriv->ai_mod_pos + 0x12);
+               }
+       if (j>=100)
+               {
+               printk("comedi%d:  pci20xxx: AI interrupt polling exit !\n", dev->minor);
+               return -EINVAL;
+               }
+       lo = readb(devpriv->ai_mod_pos + 0x02);
+       hi = readb(devpriv->ai_mod_pos + 0x03);
+
+       it->data[0] = lo + 0x100 * hi;
+       
+       return CHANNEL_READ;    /* return value == number of read datas !!*/
+       }               
+
+static int pci20xxx_di(comedi_device *dev, comedi_subdevice *s, comedi_trig *it)
+       {
+       unsigned int bits;
+
+       bits = readb(dev->iobase + devpriv->dio_port[PCI20000_DI_PORT]);
+       
+       return di_unpack(bits, it);
+       }       
+
+#ifdef MODULE
+int init_module(void)
+       {
+       comedi_driver_register(&driver_pci20xxx);
+
+       return 0;
+       }
+
+void cleanup_module(void)
+       {
+       comedi_driver_unregister(&driver_pci20xxx);
+       }
+#endif 
+
+
+