5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 2000 David A. Schleef <ds@stm.lbl.gov>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/comedidev.h>
28 #include <linux/errno.h>
29 #include <linux/ioport.h>
31 #include <linux/malloc.h>
32 #include <linux/delay.h>
43 0 a/d bits 0-3 start 8 bit
44 1 a/d bits 4-11 start 12 bit
45 2 eoc, ip1-3, irq, mux op1-4, inte, mux
50 requires hard-wiring for async ai
56 #define DAS08_TRIG_12BIT 1
57 #define DAS08_STATUS 2
58 #define DAS08_EOC (1<<7)
59 #define DAS08_IRQ (1<<3)
60 #define DAS08_IP(x) (((x)>>4)&0x7)
61 #define DAS08_CONTROL 2
62 #define DAS08_MUX(x) ((x)<<0)
63 #define DAS08_INTE (1<<3)
64 #define DAS08_OP(x) ((x)<<4)
72 1 a/d bits 4-11 start 12 bit
83 #define DAS08JR_AO_LSB(x) ((x)?6:4)
84 #define DAS08JR_AO_MSB(x) ((x)?7:5)
93 0 a/d bits 0-3 start 8 bit
94 1 a/d bits 4-11 start 12 bit
95 2 eoc, ip1-3, irq, mux op1-4, inte, mux
96 3 mux, gain status gain control
106 #define DAS08AO_GAIN_CONTROL 3
107 #define DAS08AO_GAIN_STATUS 3
109 #define DAS08AO_AO_LSB(x) ((x)?0xa:8)
110 #define DAS08AO_AO_MSB(x) ((x)?0xb:9)
111 #define DAS08AO_AO_UPDATE 8
113 /* gainlist same as _pgx_ below */
120 0 a/d bits 0-3 start 8 bit
121 1 a/d bits 4-11 start 12 bit
122 2 eoc, ip1-3, irq, mux op1-4, inte, mux
123 3 mux, gain status gain control
128 static int das08_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
129 static int das08_di_rbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
130 static int das08_do_wbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
131 static int das08jr_di_rbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
132 static int das08jr_do_wbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
133 static int das08jr_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
134 static int das08ao_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
136 static comedi_lrange range_das08_pgl = { 9, {
147 static comedi_lrange range_das08_pgh = { 12, {
161 static comedi_lrange range_das08_pgm = { 9, {
173 enum { das08_pg_none, das08_pgh, das08_pgl, das08_pgm };
175 static comedi_lrange *das08_ai_lranges[]={
176 &range_bipolar10, /* XXX guess */
182 static int das08_pgh_gainlist[] = { 8, 0, 10, 2, 12, 4, 14, 6, 1, 3, 5, 7 };
183 static int das08_pgl_gainlist[] = { 8, 0, 2, 4, 6, 1, 3, 5, 7 };
184 static int das08_pgm_gainlist[] = { 8, 0, 10, 12, 14, 9, 11, 13, 15 };
186 static int *das08_gainlists[] = {
193 typedef struct das08_board_struct{
196 unsigned int ai_nbits;
199 unsigned int ao_nbits;
202 unsigned int i8255_offset;
203 unsigned int i8254_offset;
205 static struct das08_board_struct das08_boards[]={
207 name: "das08", // cio-das08.pdf
210 ai_pg: das08_pg_none,
219 name: "das08-pgm", // cio-das08pgx.pdf
230 name: "das08-pgh", // cio-das08pgx.pdf
241 name: "das08-pgl", // cio-das08pgx.pdf
252 name: "das08-aoh", // cio-das08_aox.pdf
256 ao: das08ao_ao_winsn, // 8
264 name: "das08-aol", // cio-das08_aox.pdf
268 ao: das08ao_ao_winsn, // 8
276 name: "das08-aom", // cio-das08_aox.pdf
280 ao: das08ao_ao_winsn, // 8
288 name: "das08/jr-ao", // cio-das08-jr-ao.pdf
291 ai_pg: das08_pg_none,
292 ao: das08jr_ao_winsn,
294 di: das08jr_di_rbits,
295 do_: das08jr_do_wbits,
300 name: "das08jr-16-ao", // cio-das08jr-16-ao.pdf
303 ai_pg: das08_pg_none,
304 ao: das08jr_ao_winsn,
306 di: das08jr_di_rbits,
307 do_: das08jr_do_wbits,
322 name: "das48-pga", // cio-das48-pga.pdf
325 name: "das08-pga-g2", // a KM board
329 #define n_boardtypes sizeof(das08_boards)/sizeof(das08_boards[0])
332 struct das08_private_struct{
333 unsigned int do_bits;
334 unsigned int *pg_gainlist;
337 #define devpriv ((struct das08_private_struct *)dev->private)
338 #define thisboard ((struct das08_board_struct *)dev->board_ptr)
342 static int das08_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
349 chan = CR_CHAN(insn->chanspec);
350 range = CR_RANGE(insn->chanspec);
353 inb(dev->iobase+DAS08_LSB);
354 inb(dev->iobase+DAS08_MSB);
356 /* set multiplexer */
357 outb_p(DAS08_MUX(chan) | devpriv->do_bits,dev->iobase+DAS08_CONTROL);
359 if(thisboard->ai_pg!=das08_pg_none){
361 range = CR_RANGE(insn->chanspec);
362 outb_p(devpriv->pg_gainlist[range],dev->iobase+DAS08AO_GAIN_CONTROL);
365 /* How long should we wait for MUX to settle? */
368 for(n=0;n<insn->n;n++){
369 /* trigger conversion */
370 outb_p(0,dev->iobase+DAS08_TRIG_12BIT);
372 for(i=0;i<TIMEOUT;i++){
373 if(!(inb(dev->iobase+DAS08_STATUS)&DAS08_EOC))
377 rt_printk("das08: timeout\n");
380 msb = inb(dev->iobase + DAS08_MSB);
381 lsb = inb(dev->iobase + DAS08_LSB);
382 if(thisboard->ai_nbits==12){
383 data[n] = (lsb>>4) | (msb << 4);
385 data[n] = lsb | (msb << 8);
392 static int das08_di_rbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
394 insn->data[0]=DAS08_IP(inb(dev->iobase+DAS08_STATUS));
399 static int das08_do_wbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
401 /* XXX race with ai */
403 devpriv->do_bits = DAS08_OP(insn->data[0]);
405 outb(devpriv->do_bits,dev->iobase+DAS08_CONTROL);
410 static int das08jr_di_rbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
412 insn->data[0]=inb(dev->iobase+DAS08JR_DIO);
417 static int das08jr_do_wbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
419 outb(insn->data[0],dev->iobase+DAS08JR_DIO);
424 static int das08jr_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
430 lsb=insn->data[0]&0xff;
431 msb=(insn->data[0]>>8)&0xf;
433 chan=CR_CHAN(insn->chanspec);
435 for(n=0;n<insn->n;n++){
437 outb(lsb,dev->iobase+devpriv->ao_offset_lsb[chan]);
438 outb(msb,dev->iobase+devpriv->ao_offset_msb[chan]);
440 outb(lsb,dev->iobase+DAS08JR_AO_LSB(chan));
441 outb(msb,dev->iobase+DAS08JR_AO_MSB(chan));
445 inb(dev->iobase+DAS08JR_DIO);
453 * The -aox boards have the DACs at a different offset and use
454 * a different method to force an update.
457 static int das08ao_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
463 lsb=insn->data[0]&0xff;
464 msb=(insn->data[0]>>8)&0xf;
466 chan=CR_CHAN(insn->chanspec);
468 for(n=0;n<insn->n;n++){
470 outb(lsb,dev->iobase+devpriv->ao_offset_lsb[chan]);
471 outb(msb,dev->iobase+devpriv->ao_offset_msb[chan]);
473 outb(lsb,dev->iobase+DAS08AO_AO_LSB(chan));
474 outb(msb,dev->iobase+DAS08AO_AO_MSB(chan));
478 inb(dev->iobase+DAS08AO_AO_UPDATE);
484 static int das08_attach(comedi_device *dev,comedi_devconfig *it);
485 static int das08_detach(comedi_device *dev);
487 comedi_driver driver_das08={
488 driver_name: "das08",
490 attach: das08_attach,
491 detach: das08_detach,
492 board_name: das08_boards,
493 num_names: sizeof(das08_boards)/sizeof(struct das08_board_struct),
494 offset: sizeof(struct das08_board_struct),
497 static int das08_attach(comedi_device *dev,comedi_devconfig *it)
502 dev->iobase=it->options[0];
503 printk("comedi%d: das08: 0x%04x",dev->minor,dev->iobase);
504 if(check_region(dev->iobase,DAS08_SIZE)<0){
505 printk(" I/O port conflict\n");
509 dev->board_name = thisboard->name;
512 if((ret=alloc_subdevices(dev))<0)
514 if((ret=alloc_private(dev,sizeof(struct das08_private_struct)))<0)
517 request_region(dev->iobase,DAS08_SIZE,"das08");
522 s->type=COMEDI_SUBD_AI;
523 s->subdev_flags = SDF_READABLE;
525 s->maxdata = (1<<thisboard->ai_nbits)-1;
526 s->range_table = das08_ai_lranges[thisboard->ai_pg];
527 s->insn_read = thisboard->ai;
528 devpriv->pg_gainlist = das08_gainlists[thisboard->ai_pg];
530 s->type=COMEDI_SUBD_UNUSED;
536 s->type=COMEDI_SUBD_AO;
537 s->subdev_flags = SDF_WRITEABLE;
539 s->maxdata = (1<<thisboard->ao_nbits)-1;
540 s->range_table = &range_bipolar5;
541 s->insn_write = thisboard->ao;
543 s->type=COMEDI_SUBD_UNUSED;
549 s->type=COMEDI_SUBD_DI;
550 s->subdev_flags = SDF_READABLE;
551 s->n_chan = (thisboard->di==das08_di_rbits)?3:8;
553 s->range_table = &range_digital;
554 s->insn_read = thisboard->di; /* XXX */
556 s->type=COMEDI_SUBD_UNUSED;
562 s->type=COMEDI_SUBD_DO;
563 s->subdev_flags = SDF_WRITEABLE;
564 s->n_chan = (thisboard->do_==das08_do_wbits)?4:8;
566 s->range_table = &range_digital;
567 s->insn_write = thisboard->do_; /* XXX */
569 s->type=COMEDI_SUBD_UNUSED;
574 if(thisboard->i8255_offset!=0){
575 subdev_8255_init(dev,s,NULL,(void *)(dev->iobase+
576 thisboard->i8255_offset));
578 s->type=COMEDI_SUBD_UNUSED;
584 static int das08_detach(comedi_device *dev)
586 printk(KERN_INFO "comedi%d: das08: remove\n",dev->minor);
588 release_region(dev->iobase,DAS08_SIZE);
593 COMEDI_INITCLEANUP(driver_das08);