updates from Michal Dobes
authorDavid Schleef <ds@schleef.org>
Fri, 21 Jul 2000 22:37:53 +0000 (22:37 +0000)
committerDavid Schleef <ds@schleef.org>
Fri, 21 Jul 2000 22:37:53 +0000 (22:37 +0000)
comedi/drivers/pcl726.c

index 36f3c8a9e40c016e90c650946061f98ab8ffb06f..826727c32ac4d848698ed700c337a325c2b27177 100644 (file)
@@ -1,11 +1,16 @@
 /*
     module/pcl726.c
-    hardware driver for PC-LabCard PCL-726 and compatibles
-      ACL-6126
 
+    hardware driver for Advantech cards:
+     card:   PCL-726, PCL-727, PCL-728
+     driver: pcl726,  pcl727,  pcl728
+    and for ADLink cards:
+     card:   ACL-6126, ACL-6128
+     driver: acl6126,  acl6128
+              
     COMEDI - Linux Control and Measurement Device Interface
     Copyright (C) 1998 David A. Schleef <ds@stm.lbl.gov>
-
+    
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
 
 */
 
+/*
+    Options for PCL-726:
+     [0] - IO Base
+     [1]...[6] - D/A output range for channel 1-6: 
+               0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, 
+              4: 4-20mA, 5: unknow (external reference)
+              
+    Options for PCL-727:
+     [0] - IO Base
+     [1]...[12] - D/A output range for channel 1-12: 
+               0: 0-5V, 1: 0-10V, 2: +/-5V, 
+              3: 4-20mA
+              
+    Options for PCL-728 and ACL-6128:
+     [0] - IO Base
+     [1], [2] - D/A output range for channel 1 and 2: 
+               0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, 
+              4: 4-20mA, 5: 0-20mA
+              
+    Options for ACL-6126:
+     [0] - IO Base
+     [1] - IRQ (0=disable, 3, 5, 6, 7, 9, 10, 11, 12, 15)
+     [2]...[7] - D/A output range for channel 1-6: 
+               0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, 
+              4: 4-20mA
+     NOTE: IRQ operations isn't now supported.
+*/
 
 /*
     Thanks to Circuit Specialists for having programming info (!) on
 #include <comedi_module.h>
 
 
-#undef PCL726_IRQ      /* no interrupt support (yet) */
+#undef ACL6126_IRQ     /* no interrupt support (yet) */
 
 
 #define PCL726_SIZE 16
+#define PCL727_SIZE 32
+#define PCL728_SIZE 8
 
 #define PCL726_DAC0_HI 0
 #define PCL726_DAC0_LO 1
 #define PCL726_DI_HI 14
 #define PCL726_DI_LO 15
 
+#define PCL727_DO_HI 24
+#define PCL727_DO_LO 25
+#define PCL727_DI_HI  0
+#define PCL727_DI_LO  1
+
+#define RANGE_mA(a,b)          {(a)*1e6,(b)*1e6,UNIT_mA}
+
+comedi_lrange range_4_20mA={ 1, {RANGE_mA(4,20)}};
+comedi_lrange range_0_20mA={ 1, {RANGE_mA(0,20)}};
+
+static comedi_lrange *rangelist_726[]={
+       &range_unipolar5, &range_unipolar10, 
+       &range_bipolar5,  &range_bipolar10,
+       &range_4_20mA,    &range_unknown
+};
+
+static comedi_lrange *rangelist_727[]={
+       &range_unipolar5, &range_unipolar10, 
+       &range_bipolar5,  
+       &range_4_20mA
+};
+
+static comedi_lrange *rangelist_728[]={
+       &range_unipolar5, &range_unipolar10, 
+       &range_bipolar5,  &range_bipolar10,
+       &range_4_20mA,    &range_0_20mA
+};
 
 static int pcl726_attach(comedi_device *dev,comedi_devconfig *it);
 static int pcl726_detach(comedi_device *dev);
+static int pcl726_recognize(char *name);
+
 comedi_driver driver_pcl726={
        driver_name:    "pcl726",
        module:         THIS_MODULE,
        attach:         pcl726_attach,
        detach:         pcl726_detach,
+       recognize:      pcl726_recognize,
 };
 
+typedef struct {
+       char            *name;          // driver name
+       int             n_aochan;       // num of D/A chans
+       int             num_of_ranges;  // num of ranges
+       unsigned int    IRQbits;        // allowed interrupts
+       int             io_range;       // len of IO space
+       char            have_dio;       // 1=card have DI/DO ports
+       int             di_hi;          // ports for DI/DO operations
+       int             di_lo;
+       int             do_hi;
+       int             do_lo;
+       comedi_lrange   **range_type_list;// list of supported ranges
+} boardtype;
+
+static boardtype boardtypes[] =
+{
+       {"pcl726",   6, 6, 0x0000, PCL726_SIZE, 1, 
+        PCL726_DI_HI, PCL726_DI_LO, PCL726_DO_HI, PCL726_DO_LO, 
+        &rangelist_726[0], },
+       {"pcl727",  12, 4, 0x0000, PCL727_SIZE, 1, 
+        PCL727_DI_HI, PCL727_DI_LO, PCL727_DO_HI, PCL727_DO_LO, 
+        &rangelist_727[0], },
+       {"pcl728",   2, 6, 0x0000, PCL728_SIZE, 0, 
+        0, 0, 0, 0, 
+        &rangelist_728[0], },
+       {"acl6126",  6, 5, 0x96e8, PCL726_SIZE, 1,
+        PCL726_DI_HI, PCL726_DI_LO, PCL726_DO_HI, PCL726_DO_LO, 
+        &rangelist_726[0], },
+       {"acl6128",  2, 6, 0x0000, PCL728_SIZE, 0,
+        0, 0, 0, 0,
+        &rangelist_728[0], },
+};
+#define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype))
 
 typedef struct{
-       int bipolar[6];
+       int bipolar[12];
+       comedi_lrange *rangelist[12];
 }pcl726_private;
 #define devpriv ((pcl726_private *)dev->private)
 
@@ -95,8 +193,8 @@ static int pcl726_di(comedi_device *dev,comedi_subdevice *s,comedi_trig *it)
 {
        unsigned int bits;
        
-       bits=inb(dev->iobase+PCL726_DI_LO)|
-               (inb(dev->iobase+PCL726_DI_HI)<<8);
+       bits=inb(dev->iobase+boardtypes[dev->board].di_lo)|
+               (inb(dev->iobase+boardtypes[dev->board].di_hi)<<8);
        
        return di_unpack(bits,it);
 }
@@ -105,8 +203,8 @@ static int pcl726_do(comedi_device *dev,comedi_subdevice *s,comedi_trig *it)
 {
        do_pack(&s->state,it);
        
-       outb(s->state&0xff,dev->iobase+PCL726_DO_LO);
-       outb((s->state>>8),dev->iobase+PCL726_DO_HI);
+       outb(s->state&0xff,dev->iobase+boardtypes[dev->board].do_lo);
+       outb((s->state>>8),dev->iobase+boardtypes[dev->board].do_hi);
        
        return it->n_chan;
 }
@@ -114,83 +212,124 @@ static int pcl726_do(comedi_device *dev,comedi_subdevice *s,comedi_trig *it)
 static int pcl726_attach(comedi_device *dev,comedi_devconfig *it)
 {
        comedi_subdevice *s;
-       int ret;
+        int board,iobase,iorange;
+       int ret,i,fstch;
        
-       dev->iobase=it->options[0];
-       printk("comedi%d: pcl726: 0x%04x ",dev->minor,dev->iobase);
-       if(check_region(dev->iobase,PCL726_SIZE)<0){
+        board=dev->board;
+
+        iobase=it->options[0];
+        iorange=boardtypes[board].io_range;
+       printk("comedi%d: pcl726: board=%s, 0x%03x ",dev->minor,boardtypes[board].name,iobase);
+       if(check_region(iobase,iorange)<0){
                printk("I/O port conflict\n");
                return -EIO;
        }
        
-       dev->board_name="pcl726";
-       
-#ifdef PCL726_IRQ
-       irq=dev->options[1];
-       if(!is_b)irq=0;
-       if(irq<0 || irq==1 || irq>7){
-               printk("irq out of range\n");
-               return -EIO;
+        request_region(iobase, iorange, "pcl726");
+        dev->iobase=iobase;
+        dev->iosize=iorange;
+    
+       dev->board_name = boardtypes[board].name;
+
+       if((ret=alloc_private(dev,sizeof(pcl726_private)))<0)
+               return -ENOMEM;
+
+       for (i=0; i<12; i++) {
+               devpriv->bipolar[i]=0;
+               devpriv->rangelist[i]=&range_unknown;
        }
-       if(irq){
-               if(request_irq(irq,pcl726_interrupt,SA_INTERRUPT,"pcl726",dev)){
-                       printk("unable to allocate irq %d\n",irq);
-                       irq=0;
-               }else{
-                       printk("( irq = %d )\n",irq);
+
+#ifdef ACL6126_IRQ
+        irq=0;
+        if (boardtypes[board].IRQbits!=0) { /* board support IRQ */
+               irq=it->options[1];
+               devpriv->first_chan=2;
+               if (irq>0)  {/* we want to use IRQ */
+                       if (((1<<irq)&boardtypes[board].IRQbits)==0) {
+                               rt_printk(", IRQ %d is out of allowed range, DISABLING IT",irq);
+                               irq=0; /* Bad IRQ */
+                       } else { 
+                               if (request_irq(irq, interrupt_pcl818, SA_INTERRUPT, "pcl726", dev)) {
+                                       rt_printk(", unable to allocate IRQ %d, DISABLING IT", irq);
+                                       irq=0; /* Can't use IRQ */
+                               } else {
+                                       rt_printk(", irq=%d", irq);
+                               }    
+                       }  
                }
        }
-       dev->irq=irq;
+
+        dev->irq = irq;
 #endif
        
-       request_region(dev->iobase,PCL726_SIZE,"pcl726");
-       dev->iosize=PCL726_SIZE;
-
-       if((ret=alloc_private(dev,sizeof(pcl726_private)))<0)
-               return -ENOMEM;
+       printk("\n");
 
-       dev->n_subdevices=3;
+       dev->n_subdevices=1;
+       if (boardtypes[board].have_dio)
+               dev->n_subdevices=3;
+       
        if((ret=alloc_subdevices(dev))<0)
                return ret;
 
        s=dev->subdevices+0;
        /* ao */
        s->type=COMEDI_SUBD_AO;
-       s->subdev_flags=SDF_WRITEABLE;
-       s->n_chan=6;
+       s->subdev_flags=SDF_WRITEABLE|SDF_GROUND;
+       s->n_chan=boardtypes[board].n_aochan;
        s->maxdata=0xfff;
+       s->len_chanlist=1;
        s->trig[0]=pcl726_ao;
-       s->range_table=&range_unknown;  /* XXX */
+       /*s->range_table=&range_unknown;*/      /* XXX */
+       s->range_table_list = devpriv->rangelist;
+       fstch=1;
+       if (board==3) fstch=2;
+       for (i=0; i<boardtypes[board].n_aochan; i++) {
+               if ((it->options[fstch+i]<0)||(it->options[fstch+i]>=boardtypes[board].num_of_ranges)) {
+                       printk("Invalid range for channel %d! Must be 0<=%d<%d\n",i+1,it->options[fstch+i],boardtypes[board].num_of_ranges-1);
+                       it->options[fstch+i]=0;
+               }
+               devpriv->rangelist[i]=boardtypes[board].range_type_list[it->options[fstch+i]];
+               if (devpriv->rangelist[i]->range[0].min==-devpriv->rangelist[i]->range[0].max)
+                       devpriv->bipolar[i]=1;  /* bipolar range */
+       }
+
+       if (dev->n_subdevices<2) {
+               return 0;
+       }
 
        s=dev->subdevices+1;
        /* di */
        s->type=COMEDI_SUBD_DI;
-       s->subdev_flags=SDF_READABLE;
+       s->subdev_flags=SDF_READABLE|SDF_GROUND;
        s->n_chan=16;
        s->maxdata=1;
+       s->len_chanlist=1;
        s->trig[0]=pcl726_di;
        s->range_table=&range_digital;
 
+       if (dev->n_subdevices<3) {
+               return 0;
+       }
+
        s=dev->subdevices+2;
        /* do */
        s->type=COMEDI_SUBD_DO;
-       s->subdev_flags=SDF_WRITEABLE;
+       s->subdev_flags=SDF_WRITEABLE|SDF_GROUND;
        s->n_chan=16;
        s->maxdata=1;
+       s->len_chanlist=1;
        s->trig[0]=pcl726_do;
        s->range_table=&range_digital;
 
-       printk("\n");
-       
        return 0;
 }
 
 
 static int pcl726_detach(comedi_device *dev)
 {
-       printk("comedi%d: pcl726: remove\n",dev->minor);
+//     printk("comedi%d: pcl726: remove\n",dev->minor);
        
-#ifdef PCL726_IRQ
+#ifdef ACL6126_IRQ
        if(dev->irq){
                free_irq(dev->irq,dev);
        }
@@ -201,18 +340,20 @@ static int pcl726_detach(comedi_device *dev)
        return 0;
 }
 
+static int pcl726_recognize(char *name) 
+{
+        int i;
 
+        for (i = 0; i < n_boardtypes; i++) {
+               if (!strcmp(boardtypes[i].name, name)) {
+                       return i;
+               }
+       }
 
-#ifdef MODULE
-int init_module(void)
-{
-       comedi_driver_register(&driver_pcl726);
-       
-       return 0;
+        return -1;
 }
 
-void cleanup_module(void)
-{
-       comedi_driver_unregister(&driver_pcl726);
-}
-#endif
+
+
+COMEDI_INITCLEANUP(driver_pcl726);
+