/*
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)
{
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);
}
{
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;
}
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);
}
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);
+