#include <8255.h>
+#define DAS16_SIZE 20
+
/*
cio-das16.pdf
#define DAS1600_CLK (1<<0)
+
+static comedi_lrange range_das1x01_bip = { 4, {
+ BIP_RANGE( 10 ),
+ BIP_RANGE( 1 ),
+ BIP_RANGE( 0.1 ),
+ BIP_RANGE( 0.01 ),
+}};
+static comedi_lrange range_das1x01_unip = { 4, {
+ UNI_RANGE( 10 ),
+ UNI_RANGE( 1 ),
+ UNI_RANGE( 0.1 ),
+ UNI_RANGE( 0.01 ),
+}};
+static comedi_lrange range_das1x02_bip = { 4, {
+ BIP_RANGE( 10 ),
+ BIP_RANGE( 5 ),
+ BIP_RANGE( 2.5 ),
+ BIP_RANGE( 1.25 ),
+}};
+static comedi_lrange range_das1x02_unip = { 4, {
+ UNI_RANGE( 10 ),
+ UNI_RANGE( 5 ),
+ UNI_RANGE( 2.5 ),
+ UNI_RANGE( 1.25 ),
+}};
+static comedi_lrange range_das16jr = { 9, {
+ // also used by 16/330
+ BIP_RANGE( 10 ),
+ BIP_RANGE( 5 ),
+ BIP_RANGE( 2.5 ),
+ BIP_RANGE( 1.25 ),
+ BIP_RANGE( 0.625 ),
+ UNI_RANGE( 10 ),
+ UNI_RANGE( 5 ),
+ UNI_RANGE( 2.5 ),
+ UNI_RANGE( 1.25 ),
+}};
+
+
static int das16jr_gainlist[] = { 8, 0, 1, 2, 3, 4, 5, 6, 7 };
static int das1600_gainlist[] = { 0, 1, 2, 3 };
+enum {
+ das16_pg_none = 0,
+ das16_pg_16jr,
+ das16_pg_1601,
+ das16_pg_1602,
+};
+static int *das16_gainlists[] = {
+ NULL,
+ das16jr_gainlist,
+ das1600_gainlist,
+ das1600_gainlist,
+};
+static comedi_lrange *das16_ai_uni_lranges[]={
+ &range_bipolar10, /* XXX guess */
+ &range_das16jr,
+ &range_das1x01_unip,
+ &range_das1x02_unip,
+};
+static comedi_lrange *das16_ai_bip_lranges[]={
+ &range_unipolar10, /* XXX guess */
+ &range_das16jr,
+ &range_das1x01_bip,
+ &range_das1x02_bip,
+};
static int das16_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn);
static int das16_do_wbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn);
static int das16_di_rbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn);
static int das16_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn);
-static int das08jr16_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn);
-
-
-struct das_board_struct{
+struct das16_board_struct{
char *name;
void *ai;
unsigned int ai_nbits;
+ unsigned int ai_pg;
void *ao;
unsigned int ao_nbits;
void *di;
void *do_;
- unsigned int ai_type;
- unsigned int i8255_offset;
- unsigned int i8254_offset;
+ unsigned int i8255_offset;
+ unsigned int i8254_offset;
+
+ unsigned int size;
+};
+enum{ /* must match following array */
+ das16_board_das16,
+ das16_board_das16f,
+ das16_board_das16jr,
+ das16_board_das1401_12,
+ das16_board_das1402_12,
+ das16_board_das1402_16,
+ das16_board_das1601_12,
+ das16_board_das1602_12,
+ das16_board_das1602_16,
+ das16_board_das16_330,
};
-static struct das_board_struct boards[]={
+static struct das16_board_struct das16_boards[]={
{
name: "das16", // cio-das16.pdf
ai: das16_ai_rinsn,
ai_nbits: 12,
+ ai_pg: das16_pg_none,
+ ao: das16_ao_winsn,
+ ao_nbits: 12,
+ di: das16_di_rbits,
+ do_: das16_do_wbits,
+ i8255_offset: 0x10,
+ i8254_offset: 0x0c,
+ size: 0x14,
+ },
+ {
+ name: "das16/f", // das16.pdf
+ ai: das16_ai_rinsn,
+ ai_nbits: 12,
+ ai_pg: das16_pg_none,
ao: das16_ao_winsn,
ao_nbits: 12,
di: das16_di_rbits,
do_: das16_do_wbits,
i8255_offset: 0x10,
i8254_offset: 0x0c,
+ size: 0x14,
},
{
name: "das16/jr", // cio-das16jr.pdf
ai: das16_ai_rinsn,
ai_nbits: 12,
+ ai_pg: das16_pg_16jr,
ao: NULL,
ao_nbits: 12,
di: das16_di_rbits,
do_: das16_do_wbits,
i8255_offset: 0,
i8254_offset: 0x0c,
+ size: 0x10,
},
{
name: "das1401/12", // cio-das1400_series.pdf
ai: das16_ai_rinsn,
ai_nbits: 12,
+ ai_pg: das16_pg_1601,
ao: NULL,
ao_nbits: 12,
di: das16_di_rbits,
do_: das16_do_wbits,
i8255_offset: 0,
i8254_offset: 0x0c,
+ size: 0x408,
},
{
name: "das1402/12", // cio-das1400_series.pdf
ai: das16_ai_rinsn,
ai_nbits: 12,
+ ai_pg: das16_pg_1602,
ao: NULL,
ao_nbits: 12,
di: das16_di_rbits,
do_: das16_do_wbits,
i8255_offset: 0,
i8254_offset: 0x0c,
+ size: 0x408,
},
{
name: "das1402/16", // cio-das1400_series.pdf
ai: das16_ai_rinsn,
ai_nbits: 16,
+ ai_pg: das16_pg_1602,
ao: NULL,
ao_nbits: 12,
di: das16_di_rbits,
do_: das16_do_wbits,
i8255_offset: 0,
i8254_offset: 0x0c,
+ size: 0x408,
},
{
name: "das1601/12", // cio-das160x-1x.pdf
ai: das16_ai_rinsn,
ai_nbits: 12,
+ ai_pg: das16_pg_1601,
ao: das16_ao_winsn,
ao_nbits: 12,
di: das16_di_rbits,
do_: das16_do_wbits,
i8255_offset: 0x400,
i8254_offset: 0x0c,
+ size: 0x408,
},
{
name: "das1602/12", // cio-das160x-1x.pdf
ai: das16_ai_rinsn,
ai_nbits: 12,
+ ai_pg: das16_pg_1602,
ao: das16_ao_winsn,
ao_nbits: 12,
di: das16_di_rbits,
do_: das16_do_wbits,
i8255_offset: 0x400,
i8254_offset: 0x0c,
+ size: 0x408,
},
{
name: "das1602/16", // cio-das160x-1x.pdf
ai: das16_ai_rinsn,
ai_nbits: 16,
+ ai_pg: das16_pg_1602,
ao: das16_ao_winsn,
ao_nbits: 12,
di: das16_di_rbits,
do_: das16_do_wbits,
i8255_offset: 0x400,
i8254_offset: 0x0c,
+ size: 0x408,
},
{
name: "das16/330", // ?
ai: das16_ai_rinsn,
ai_nbits: 12,
+ ai_pg: das16_pg_16jr,
ao: das16_ao_winsn,
ao_nbits: 12,
di: das16_di_rbits,
i8255_offset: 0,
i8254_offset: 0x0c,
},
+#if 0
{
name: "das16/330i", // ?
},
{
- name: "das16/f", // das16.pdf
- // faster version of das16
- },
- {
name: "das16/jr/ctr5", // ?
},
{
{
name: "das1602/12-p5",//
},
+#endif
};
-#define TIMEOUT 1000
-
-static comedi_lrange range_das1x01_bip = { 4, {
- BIP_RANGE( 10 ),
- BIP_RANGE( 1 ),
- BIP_RANGE( 0.1 ),
- BIP_RANGE( 0.01 ),
-}};
-static comedi_lrange range_das1x01_unip = { 4, {
- UNI_RANGE( 10 ),
- UNI_RANGE( 1 ),
- UNI_RANGE( 0.1 ),
- UNI_RANGE( 0.01 ),
-}};
-static comedi_lrange range_das1x02_bip = { 4, {
- BIP_RANGE( 10 ),
- BIP_RANGE( 5 ),
- BIP_RANGE( 2.5 ),
- BIP_RANGE( 1.25 ),
-}};
-static comedi_lrange range_das1x02_unip = { 4, {
- UNI_RANGE( 10 ),
- UNI_RANGE( 5 ),
- UNI_RANGE( 2.5 ),
- UNI_RANGE( 1.25 ),
-}};
-static comedi_lrange range_das16jr = { 9, {
- // also used by 16/330
- BIP_RANGE( 10 ),
- BIP_RANGE( 5 ),
- BIP_RANGE( 2.5 ),
- BIP_RANGE( 1.25 ),
- BIP_RANGE( 0.625 ),
- UNI_RANGE( 10 ),
- UNI_RANGE( 5 ),
- UNI_RANGE( 2.5 ),
- UNIP_RANGE( 1.25 ),
-}};
-
-
-static int das08jr16_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn)
-{
- int n;
- int lsb,msb;
- int chan;
-
- lsb=insn->data[0]&0xff;
- msb=(insn->data[0]>>8)&0xff;
+static int das16_attach(comedi_device *dev,comedi_devconfig *it);
+static int das16_detach(comedi_device *dev);
+comedi_driver driver_das16={
+ driver_name: "das16",
+ module: THIS_MODULE,
+ attach: das16_attach,
+ detach: das16_detach,
+};
- chan=CR_CHAN(insn->chanspec);
- for(n=0;n<insn->n;n++){
-#if 0
- outb(lsb,dev->iobase+devpriv->ao_offset_lsb[chan]);
- outb(msb,dev->iobase+devpriv->ao_offset_msb[chan]);
-#else
- outb(lsb,dev->iobase+DAS08AO_AO_LSB(chan));
- outb(msb,dev->iobase+DAS08AO_AO_MSB(chan));
-#endif
+#define TIMEOUT 1000
- /* load DACs */
- inb(dev->iobase+DAS08AO_UPDATE);
- /* XXX */
- break;
- }
+struct das16_private_struct {
+ unsigned int ai_unipolar;
+ unsigned int ai_singleended;
+ unsigned int clockbase;
+};
+#define devpriv ((struct das16_private_struct *)(dev->private))
+#define thisboard ((struct das16_board_struct *)(dev->board_ptr))
- return n;
-}
static int das16_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn)
{
int i,n;
+ int range;
+ int chan;
+ int msb,lsb;
/* clear crap */
- inb(dev->iobase+DAS16_LSB);
- inb(dev->iobase+DAS16_MSB);
+ inb(dev->iobase+DAS16_AI_LSB);
+ inb(dev->iobase+DAS16_AI_MSB);
/* set multiplexer */
+ chan = CR_CHAN(insn->chanspec);
outb_p(chan,dev->iobase+DAS16_MUX);
/* set gain */
- if(board->have_pg){
+ if(thisboard->ai_pg != das16_pg_none){
range = CR_RANGE(insn->chanspec);
- outb(das16_gainlist[range],dev->iobase+DAS16_GAIN);
+ outb((das16_gainlists[thisboard->ai_pg])[range],
+ dev->iobase+DAS16_GAIN);
}
/* How long should we wait for MUX to settle? */
break;
}
if(i==TIMEOUT){
- rt_printk("das08: timeout\n");
+ rt_printk("das16: timeout\n");
return -ETIME;
}
- msb = inb(dev->iobase + DAS16_MSB);
- lsb = inb(dev->iobase + DAS16_LSB);
- if(board->ai_nbits==12){
+ msb = inb(dev->iobase + DAS16_AI_MSB);
+ lsb = inb(dev->iobase + DAS16_AI_LSB);
+ if(thisboard->ai_nbits==12){
insn->data[n] = (lsb>>4) | (msb << 4);
}else{
insn->data[n] = lsb | (msb << 8);
return n;
}
-static void das16_init(comedi_device *dev)
-{
- outb(DAS16_IRQ(dev->irq),dev->iobase+DAS16_CONTROL);
- outb(0,DAS16_PACER);
-
-}
-
static int das16_di_rbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn)
{
- insn->data[0]=inb(dev->iobase+DAS08JR_DIO)&0xf;
+ insn->data[0]=inb(dev->iobase+DAS16_DIO)&0xf;
return 1;
}
static int das16_do_wbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn)
{
- outb(insn->data[0],dev->iobase+DAS08JR_DIO);
+ outb(insn->data[0],dev->iobase+DAS16_DIO);
return 1;
}
int lsb,msb;
int chan;
- if(board->ao_nbits==12){
+ if(thisboard->ao_nbits==12){
lsb=(insn->data[0]<<4)&0xff;
msb=(insn->data[0]>>4)&0xff;
}else{
return n;
}
-static void das1600_init(comedi_device *dev)
+
+
+
+static void das16_init(comedi_device *dev)
+{
+ outb(DAS16_IRQ(dev->irq),dev->iobase+DAS16_CONTROL);
+ outb(0,DAS16_PACER);
+
+}
+
+static int detect_ao(comedi_device *dev)
{
- int status, extstatus;
+ int in_aa;
+ int in_55;
+
+ outb(0xaa,dev->iobase+DAS16_AO_LSB(0));
+ in_aa = inb(dev->iobase+DAS16_AO_LSB(0));
+
+ outb(0x55,dev->iobase+DAS16_AO_LSB(0));
+ in_55 = inb(dev->iobase+DAS16_AO_LSB(0));
+
+ printk("detect_ao: 0xaa -> 0x%02x, 0x55 -> 0x%02x\n",in_aa,in_55);
+
+ if((in_aa == 0xaa) && (in_55 == 0x55)){
+ printk("possibly 16 bit ao?\n");
+ }
+
+ if(((in_aa & 0xf0) == 0xa0) && ((in_55 & 0xf0) == 0x50)){
+ printk("ao test positive\n");
+ return 1;
+ }
+
+ printk("ao test negative\n");
+
+ return 0;
+}
+
+static int das16_probe(comedi_device *dev)
+{
+ int status;
+ int burststatus;
+ int diobits;
+
+ /* status is available on all boards */
status = inb(dev->iobase + DAS16_STATUS);
- extstatus = inb(dev->iobase + DAS1600_BURST_STATUS);
- if((extstatus & 0xfc)==0x10){
- /* probably a 1600 board */
+ if((status & DAS16_UB)){
+ devpriv->ai_unipolar = 1;
+ }else{
+ devpriv->ai_unipolar = 0;
}
- if((extstatus & DAS1600_CLK)){
- /* clock is 10 Mhz */
+ if((status & DAS16_MUX)){
+ devpriv->ai_singleended = 1;
}else{
- /* clock is 1 Mhz */
+ devpriv->ai_singleended = 0;
+ }
+
+ /* diobits indicates boards */
+
+ diobits = inb(dev->iobase + DAS16_DIO) & 0xf0;
+
+printk("diobits 0x%02x",diobits);
+ switch(diobits){
+ case 0x80:
+ printk(" das16 or das16/f");
+ /* only difference is speed, so not an issue yet */
+ return das16_board_das16;
+ case 0x00:
+ printk(" das16jr or das16/330");
+ /* the 330 has ao, 16jr does not */
+
+ /* we can write the low 4 bits without updating DAC */
+ if(detect_ao(dev)){
+ return das16_board_das16_330;
+ }else{
+ return das16_board_das16jr;
+ }
+
+ break;
+ default:
+ printk(" unknown board");
+ return -1;
+ case 0xc0:
+ printk(" das1600 or das1400");
+ break;
+ }
+
+ /* burststatus is available on 1600, 1400 */
+
+ burststatus = inb(dev->iobase + DAS1600_BURST_STATUS);
+
+ if((burststatus & 0xfc)==0x10){
+ /* true for 1400, 1600 */
+ }
+
+ if((burststatus & DAS1600_CLK)){
+ devpriv->clockbase = 100;
+ }else{
+ devpriv->clockbase = 1000;
}
outb(DAS1600_ENABLE_VAL,dev->iobase+DAS1600_ENABLE);
- if((status & DAS16_UB)){
- /* unipolar */
+ if(detect_ao(dev)){
+ printk("das1600 series\n");
+ return das16_board_das1601_12;
}else{
- /* bipolar */
+ printk("das1400 series\n");
+ return das16_board_das1401_12;
}
- if((status & DAS16_MUX)){
- /* single ended */
+}
+
+
+/*
+ *
+ * Options list:
+ * 0 I/O base
+ * 1 IRQ
+ */
+
+static int das16_attach(comedi_device *dev, comedi_devconfig *it)
+{
+ comedi_subdevice *s;
+ int ret;
+
+ dev->iobase = it->options[0];
+
+ printk("comedi%d: das16:",dev->minor);
+
+ dev->board_ptr = das16_boards + dev->board;
+ dev->board_name = thisboard->name;
+
+ if(thisboard->size<0x400){
+ printk(" 0x%04x-0x%04x",
+ dev->iobase,dev->iobase+thisboard->size);
+ if(check_region(dev->iobase,thisboard->size)<0){
+ printk(" I/O port conflict\n");
+ return -EIO;
+ }
}else{
- /* differential */
+ printk(" 0x%04x-0x%04x 0x%04x-0x%04x",
+ dev->iobase,dev->iobase+0x0f,
+ dev->iobase+0x400,dev->iobase+(thisboard->size&0x3ff));
+ if(check_region(dev->iobase,0x10)<0 ||
+ check_region(dev->iobase+0x400,thisboard->size&0x3ff)<0){
+ printk(" I/O port conflict\n");
+ return -EIO;
+ }
}
- printk("4 bit: 0x%02x\n",inb(dev->iobase + DAS16_DIO));
- /* 0x80: das16 */
- /* 0x00: das16jr, das16/330 */
- /* 0xc0: das1600, das1400 */
+ dev->n_subdevices = 5;
+ if((ret=alloc_subdevices(dev))<0)
+ return ret;
+ if((ret=alloc_private(dev,sizeof(struct das16_private_struct)))<0)
+ return ret;
+
+ if(thisboard->size<0x400){
+ request_region(dev->iobase,thisboard->size,"das16");
+ }else{
+ request_region(dev->iobase,0x10,"das16");
+ request_region(dev->iobase,thisboard->size&0x3ff,"das16");
+ }
+
+ s=dev->subdevices+0;
+ /* ai */
+ if(thisboard->ai){
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE;
+ if(devpriv->ai_singleended){
+ s->n_chan = 16;
+ s->subdev_flags |= SDF_GROUND; /* XXX ? */
+ }else{
+ s->n_chan = 8;
+ s->subdev_flags |= SDF_DIFF;
+ }
+ s->maxdata = (1<<thisboard->ai_nbits)-1;
+ if(devpriv->ai_unipolar){
+ s->range_table = das16_ai_uni_lranges[thisboard->ai_pg];
+ }else{
+ s->range_table = das16_ai_bip_lranges[thisboard->ai_pg];
+ }
+ s->insn_read = thisboard->ai;
+ }else{
+ s->type=COMEDI_SUBD_UNUSED;
+ }
+
+ s = dev->subdevices + 1;
+ /* ao */
+ if(thisboard->ao){
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITEABLE;
+ s->n_chan = 2;
+ s->maxdata = (1<<thisboard->ao_nbits)-1;
+ s->range_table = &range_unknown; /* XXX */
+ s->insn_write = thisboard->ao;
+ }else{
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ s = dev->subdevices + 2;
+ /* di */
+ if(thisboard->di){
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 4;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_read = thisboard->di;
+ }else{
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ s = dev->subdevices + 3;
+ /* do */
+ if(thisboard->do_){
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITEABLE;
+ s->n_chan = 4;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_write = thisboard->do_;
+ }else{
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ s = dev->subdevices + 4;
+ /* 8255 */
+ if(thisboard->i8255_offset!=0){
+ subdev_8255_init(dev,s,NULL,(void *)(dev->iobase+
+ thisboard->i8255_offset));
+ }else{
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ return 0;
+}
+
+
+static int das16_detach(comedi_device *dev)
+{
+ return 0;
}
+COMEDI_INITCLEANUP(driver_das16);