2 comedi/drivers/dt3000.c
3 Data Translation DT3000 series driver
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1999 David A. Schleef <ds@schleef.org>
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 Description: Data Translation DT3000 series
27 Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003,
28 DT3003-PGL, DT3004, DT3005, DT3004-200
29 Updated: Mon, 14 Apr 2008 15:41:24 +0100
32 Configuration Options:
33 [0] - PCI bus of device (optional)
34 [1] - PCI slot of device (optional)
35 If bus/slot is not specified, the first supported
36 PCI device found will be used.
38 There is code to support AI commands, but it may not work.
40 AO commands are not supported.
44 The DT3000 series is Data Translation's attempt to make a PCI
45 data acquisition board. The design of this series is very nice,
46 since each board has an on-board DSP (Texas Instruments TMS320C52).
47 However, a few details are a little annoying. The boards lack
48 bus-mastering DMA, which eliminates them from serious work.
49 They also are not capable of autocalibration, which is a common
50 feature in modern hardware. The default firmware is pretty bad,
51 making it nearly impossible to write an RT compatible driver.
52 It would make an interesting project to write a decent firmware
55 Data Translation originally wanted an NDA for the documentation
56 for the 3k series. However, if you ask nicely, they might send
57 you the docs without one, also.
62 #include <linux/interrupt.h>
63 #include "../comedidev.h"
64 #include <linux/delay.h>
66 #include "comedi_pci.h"
68 #define PCI_VENDOR_ID_DT 0x1116
70 static const struct comedi_lrange range_dt3000_ai = { 4, {
78 static const struct comedi_lrange range_dt3000_ai_pgl = { 4, {
86 struct dt3k_boardtype {
89 unsigned int device_id;
93 const struct comedi_lrange *adrange;
98 static const struct dt3k_boardtype dt3k_boardtypes[] = {
103 .adrange = &range_dt3000_ai,
108 {.name = "dt3001-pgl",
112 .adrange = &range_dt3000_ai_pgl,
121 .adrange = &range_dt3000_ai,
130 .adrange = &range_dt3000_ai,
135 {.name = "dt3003-pgl",
139 .adrange = &range_dt3000_ai_pgl,
148 .adrange = &range_dt3000_ai,
153 {.name = "dt3005", /* a.k.a. 3004-200 */
157 .adrange = &range_dt3000_ai,
164 #define n_dt3k_boards sizeof(dt3k_boardtypes)/sizeof(struct dt3k_boardtype)
165 #define this_board ((const struct dt3k_boardtype *)dev->board_ptr)
167 static DEFINE_PCI_DEVICE_TABLE(dt3k_pci_table) = {
169 PCI_VENDOR_ID_DT, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
170 PCI_VENDOR_ID_DT, 0x0027, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
171 PCI_VENDOR_ID_DT, 0x0023, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
172 PCI_VENDOR_ID_DT, 0x0024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
173 PCI_VENDOR_ID_DT, 0x0028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
174 PCI_VENDOR_ID_DT, 0x0025, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
175 PCI_VENDOR_ID_DT, 0x0026, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
179 MODULE_DEVICE_TABLE(pci, dt3k_pci_table);
181 #define DT3000_SIZE (4*0x1000)
183 /* dual-ported RAM location definitions */
185 #define DPR_DAC_buffer (4*0x000)
186 #define DPR_ADC_buffer (4*0x800)
187 #define DPR_Command (4*0xfd3)
188 #define DPR_SubSys (4*0xfd3)
189 #define DPR_Encode (4*0xfd4)
190 #define DPR_Params(a) (4*(0xfd5+(a)))
191 #define DPR_Tick_Reg_Lo (4*0xff5)
192 #define DPR_Tick_Reg_Hi (4*0xff6)
193 #define DPR_DA_Buf_Front (4*0xff7)
194 #define DPR_DA_Buf_Rear (4*0xff8)
195 #define DPR_AD_Buf_Front (4*0xff9)
196 #define DPR_AD_Buf_Rear (4*0xffa)
197 #define DPR_Int_Mask (4*0xffb)
198 #define DPR_Intr_Flag (4*0xffc)
199 #define DPR_Response_Mbx (4*0xffe)
200 #define DPR_Command_Mbx (4*0xfff)
202 #define AI_FIFO_DEPTH 2003
203 #define AO_FIFO_DEPTH 2048
207 #define CMD_GETBRDINFO 0
209 #define CMD_GETCONFIG 2
212 #define CMD_READSINGLE 5
213 #define CMD_WRITESINGLE 6
214 #define CMD_CALCCLOCK 7
215 #define CMD_READEVENTS 8
216 #define CMD_WRITECTCTRL 16
217 #define CMD_READCTCTRL 17
218 #define CMD_WRITECT 18
219 #define CMD_READCT 19
220 #define CMD_WRITEDATA 32
221 #define CMD_READDATA 33
222 #define CMD_WRITEIO 34
223 #define CMD_READIO 35
224 #define CMD_WRITECODE 36
225 #define CMD_READCODE 37
226 #define CMD_EXECUTE 38
236 /* interrupt flags */
237 #define DT3000_CMDONE 0x80
238 #define DT3000_CTDONE 0x40
239 #define DT3000_DAHWERR 0x20
240 #define DT3000_DASWERR 0x10
241 #define DT3000_DAEMPTY 0x08
242 #define DT3000_ADHWERR 0x04
243 #define DT3000_ADSWERR 0x02
244 #define DT3000_ADFULL 0x01
246 #define DT3000_COMPLETION_MASK 0xff00
247 #define DT3000_COMMAND_MASK 0x00ff
248 #define DT3000_NOTPROCESSED 0x0000
249 #define DT3000_NOERROR 0x5500
250 #define DT3000_ERROR 0xaa00
251 #define DT3000_NOTSUPPORTED 0xff00
253 #define DT3000_EXTERNAL_CLOCK 1
254 #define DT3000_RISING_EDGE 2
256 #define TMODE_MASK 0x1c
258 #define DT3000_AD_TRIG_INTERNAL (0<<2)
259 #define DT3000_AD_TRIG_EXTERNAL (1<<2)
260 #define DT3000_AD_RETRIG_INTERNAL (2<<2)
261 #define DT3000_AD_RETRIG_EXTERNAL (3<<2)
262 #define DT3000_AD_EXTRETRIG (4<<2)
264 #define DT3000_CHANNEL_MODE_SE 0
265 #define DT3000_CHANNEL_MODE_DI 1
267 struct dt3k_private {
269 struct pci_dev *pci_dev;
270 resource_size_t phys_addr;
273 unsigned int ao_readback[2];
274 unsigned int ai_front;
275 unsigned int ai_rear;
278 #define devpriv ((struct dt3k_private *)dev->private)
280 static int dt3000_attach(struct comedi_device *dev,
281 struct comedi_devconfig *it);
282 static int dt3000_detach(struct comedi_device *dev);
283 static struct comedi_driver driver_dt3000 = {
284 .driver_name = "dt3000",
285 .module = THIS_MODULE,
286 .attach = dt3000_attach,
287 .detach = dt3000_detach,
290 static int __devinit driver_dt3000_pci_probe(struct pci_dev *dev,
291 const struct pci_device_id *ent)
293 return comedi_pci_auto_config(dev, driver_dt3000.driver_name);
296 static void __devexit driver_dt3000_pci_remove(struct pci_dev *dev)
298 comedi_pci_auto_unconfig(dev);
301 static struct pci_driver driver_dt3000_pci_driver = {
302 .id_table = dt3k_pci_table,
303 .probe = &driver_dt3000_pci_probe,
304 .remove = __devexit_p(&driver_dt3000_pci_remove)
307 static int __init driver_dt3000_init_module(void)
311 retval = comedi_driver_register(&driver_dt3000);
315 driver_dt3000_pci_driver.name = (char *)driver_dt3000.driver_name;
316 return pci_register_driver(&driver_dt3000_pci_driver);
319 static void __exit driver_dt3000_cleanup_module(void)
321 pci_unregister_driver(&driver_dt3000_pci_driver);
322 comedi_driver_unregister(&driver_dt3000);
325 module_init(driver_dt3000_init_module);
326 module_exit(driver_dt3000_cleanup_module);
328 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
329 struct comedi_subdevice *s);
330 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
331 unsigned int round_mode);
332 static int dt3k_ai_cancel(struct comedi_device *dev,
333 struct comedi_subdevice *s);
335 static void debug_intr_flags(unsigned int flags);
340 static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
343 unsigned int status = 0;
345 writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
347 for (i = 0; i < TIMEOUT; i++) {
348 status = readw(devpriv->io_addr + DPR_Command_Mbx);
349 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
353 if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR)
356 printk("dt3k_send_cmd() timeout/error status=0x%04x\n", status);
361 static unsigned int dt3k_readsingle(struct comedi_device *dev,
362 unsigned int subsys, unsigned int chan,
365 writew(subsys, devpriv->io_addr + DPR_SubSys);
367 writew(chan, devpriv->io_addr + DPR_Params(0));
368 writew(gain, devpriv->io_addr + DPR_Params(1));
370 dt3k_send_cmd(dev, CMD_READSINGLE);
372 return readw(devpriv->io_addr + DPR_Params(2));
375 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
376 unsigned int chan, unsigned int data)
378 writew(subsys, devpriv->io_addr + DPR_SubSys);
380 writew(chan, devpriv->io_addr + DPR_Params(0));
381 writew(0, devpriv->io_addr + DPR_Params(1));
382 writew(data, devpriv->io_addr + DPR_Params(2));
384 dt3k_send_cmd(dev, CMD_WRITESINGLE);
387 static int debug_n_ints = 0;
389 /* FIXME! Assumes shared interrupt is for this card. */
390 /* What's this debug_n_ints stuff? Obviously needs some work... */
391 static irqreturn_t dt3k_interrupt(int irq, void *d)
393 struct comedi_device *dev = d;
394 struct comedi_subdevice *s;
400 s = dev->subdevices + 0;
401 status = readw(devpriv->io_addr + DPR_Intr_Flag);
403 debug_intr_flags(status);
406 if (status & DT3000_ADFULL) {
407 dt3k_ai_empty_fifo(dev, s);
408 s->async->events |= COMEDI_CB_BLOCK;
411 if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
412 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
415 if (debug_n_ints >= 10) {
416 dt3k_ai_cancel(dev, s);
417 s->async->events |= COMEDI_CB_EOA;
420 comedi_event(dev, s);
425 static char *intr_flags[] = {
426 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
427 "DaSwError", "DaHwError", "CtDone", "CmDone",
430 static void debug_intr_flags(unsigned int flags)
433 printk("dt3k: intr_flags:");
434 for (i = 0; i < 8; i++) {
435 if (flags & (1 << i))
436 printk(" %s", intr_flags[i]);
442 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
443 struct comedi_subdevice *s)
451 front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
452 count = front - devpriv->ai_front;
454 count += AI_FIFO_DEPTH;
456 printk("reading %d samples\n", count);
458 rear = devpriv->ai_rear;
460 for (i = 0; i < count; i++) {
461 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
462 comedi_buf_put(s->async, data);
464 if (rear >= AI_FIFO_DEPTH)
468 devpriv->ai_rear = rear;
469 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
472 static int dt3k_ai_cmdtest(struct comedi_device *dev,
473 struct comedi_subdevice *s, struct comedi_cmd *cmd)
478 /* step 1: make sure trigger sources are trivially valid */
480 tmp = cmd->start_src;
481 cmd->start_src &= TRIG_NOW;
482 if (!cmd->start_src || tmp != cmd->start_src)
485 tmp = cmd->scan_begin_src;
486 cmd->scan_begin_src &= TRIG_TIMER;
487 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
490 tmp = cmd->convert_src;
491 cmd->convert_src &= TRIG_TIMER;
492 if (!cmd->convert_src || tmp != cmd->convert_src)
495 tmp = cmd->scan_end_src;
496 cmd->scan_end_src &= TRIG_COUNT;
497 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
501 cmd->stop_src &= TRIG_COUNT;
502 if (!cmd->stop_src || tmp != cmd->stop_src)
508 /* step 2: make sure trigger sources are unique and mutually compatible */
513 /* step 3: make sure arguments are trivially compatible */
515 if (cmd->start_arg != 0) {
520 if (cmd->scan_begin_src == TRIG_TIMER) {
521 if (cmd->scan_begin_arg < this_board->ai_speed) {
522 cmd->scan_begin_arg = this_board->ai_speed;
525 if (cmd->scan_begin_arg > 100 * 16 * 65535) {
526 cmd->scan_begin_arg = 100 * 16 * 65535;
532 if (cmd->convert_src == TRIG_TIMER) {
533 if (cmd->convert_arg < this_board->ai_speed) {
534 cmd->convert_arg = this_board->ai_speed;
537 if (cmd->convert_arg > 50 * 16 * 65535) {
538 cmd->convert_arg = 50 * 16 * 65535;
545 if (cmd->scan_end_arg != cmd->chanlist_len) {
546 cmd->scan_end_arg = cmd->chanlist_len;
549 if (cmd->stop_src == TRIG_COUNT) {
550 if (cmd->stop_arg > 0x00ffffff) {
551 cmd->stop_arg = 0x00ffffff;
556 if (cmd->stop_arg != 0) {
565 /* step 4: fix up any arguments */
567 if (cmd->scan_begin_src == TRIG_TIMER) {
568 tmp = cmd->scan_begin_arg;
569 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
570 cmd->flags & TRIG_ROUND_MASK);
571 if (tmp != cmd->scan_begin_arg)
576 if (cmd->convert_src == TRIG_TIMER) {
577 tmp = cmd->convert_arg;
578 dt3k_ns_to_timer(50, &cmd->convert_arg,
579 cmd->flags & TRIG_ROUND_MASK);
580 if (tmp != cmd->convert_arg)
582 if (cmd->scan_begin_src == TRIG_TIMER &&
583 cmd->scan_begin_arg <
584 cmd->convert_arg * cmd->scan_end_arg) {
585 cmd->scan_begin_arg =
586 cmd->convert_arg * cmd->scan_end_arg;
599 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
600 unsigned int round_mode)
602 int divider, base, prescale;
604 /* This function needs improvment */
605 /* Don't know if divider==0 works. */
607 for (prescale = 0; prescale < 16; prescale++) {
608 base = timer_base * (prescale + 1);
609 switch (round_mode) {
610 case TRIG_ROUND_NEAREST:
612 divider = (*nanosec + base / 2) / base;
614 case TRIG_ROUND_DOWN:
615 divider = (*nanosec) / base;
618 divider = (*nanosec) / base;
621 if (divider < 65536) {
622 *nanosec = divider * base;
623 return (prescale << 16) | (divider);
628 base = timer_base * (1 << prescale);
630 *nanosec = divider * base;
631 return (prescale << 16) | (divider);
634 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
636 struct comedi_cmd *cmd = &s->async->cmd;
638 unsigned int chan, range, aref;
639 unsigned int divider;
640 unsigned int tscandiv;
644 printk("dt3k_ai_cmd:\n");
645 for (i = 0; i < cmd->chanlist_len; i++) {
646 chan = CR_CHAN(cmd->chanlist[i]);
647 range = CR_RANGE(cmd->chanlist[i]);
649 writew((range << 6) | chan,
650 devpriv->io_addr + DPR_ADC_buffer + i);
652 aref = CR_AREF(cmd->chanlist[0]);
654 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
655 printk("param[0]=0x%04x\n", cmd->scan_end_arg);
657 if (cmd->convert_src == TRIG_TIMER) {
658 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
659 cmd->flags & TRIG_ROUND_MASK);
660 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
661 printk("param[1]=0x%04x\n", divider >> 16);
662 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
663 printk("param[2]=0x%04x\n", divider & 0xffff);
668 if (cmd->scan_begin_src == TRIG_TIMER) {
669 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
670 cmd->flags & TRIG_ROUND_MASK);
671 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
672 printk("param[3]=0x%04x\n", tscandiv >> 16);
673 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
674 printk("param[4]=0x%04x\n", tscandiv & 0xffff);
679 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
680 writew(mode, devpriv->io_addr + DPR_Params(5));
681 printk("param[5]=0x%04x\n", mode);
682 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
683 printk("param[6]=0x%04x\n", aref == AREF_DIFF);
685 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
686 printk("param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
688 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
689 ret = dt3k_send_cmd(dev, CMD_CONFIG);
691 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
692 devpriv->io_addr + DPR_Int_Mask);
696 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
697 ret = dt3k_send_cmd(dev, CMD_START);
702 static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
706 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
707 ret = dt3k_send_cmd(dev, CMD_STOP);
709 writew(0, devpriv->io_addr + DPR_Int_Mask);
714 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
715 struct comedi_insn *insn, unsigned int *data)
718 unsigned int chan, gain, aref;
720 chan = CR_CHAN(insn->chanspec);
721 gain = CR_RANGE(insn->chanspec);
722 /* XXX docs don't explain how to select aref */
723 aref = CR_AREF(insn->chanspec);
725 for (i = 0; i < insn->n; i++)
726 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
731 static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
732 struct comedi_insn *insn, unsigned int *data)
737 chan = CR_CHAN(insn->chanspec);
738 for (i = 0; i < insn->n; i++) {
739 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
740 devpriv->ao_readback[chan] = data[i];
746 static int dt3k_ao_insn_read(struct comedi_device *dev,
747 struct comedi_subdevice *s,
748 struct comedi_insn *insn, unsigned int *data)
753 chan = CR_CHAN(insn->chanspec);
754 for (i = 0; i < insn->n; i++)
755 data[i] = devpriv->ao_readback[chan];
760 static void dt3k_dio_config(struct comedi_device *dev, int bits)
763 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
765 writew(bits, devpriv->io_addr + DPR_Params(0));
768 writew(0, devpriv->io_addr + DPR_Params(1));
769 writew(0, devpriv->io_addr + DPR_Params(2));
772 dt3k_send_cmd(dev, CMD_CONFIG);
775 static int dt3k_dio_insn_config(struct comedi_device *dev,
776 struct comedi_subdevice *s,
777 struct comedi_insn *insn, unsigned int *data)
781 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
784 case INSN_CONFIG_DIO_OUTPUT:
787 case INSN_CONFIG_DIO_INPUT:
790 case INSN_CONFIG_DIO_QUERY:
793 io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
801 mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
802 dt3k_dio_config(dev, mask);
807 static int dt3k_dio_insn_bits(struct comedi_device *dev,
808 struct comedi_subdevice *s,
809 struct comedi_insn *insn, unsigned int *data)
815 s->state &= ~data[0];
816 s->state |= data[1] & data[0];
817 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
819 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
824 static int dt3k_mem_insn_read(struct comedi_device *dev,
825 struct comedi_subdevice *s,
826 struct comedi_insn *insn, unsigned int *data)
828 unsigned int addr = CR_CHAN(insn->chanspec);
831 for (i = 0; i < insn->n; i++) {
832 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
833 writew(addr, devpriv->io_addr + DPR_Params(0));
834 writew(1, devpriv->io_addr + DPR_Params(1));
836 dt3k_send_cmd(dev, CMD_READCODE);
838 data[i] = readw(devpriv->io_addr + DPR_Params(2));
844 static int dt_pci_probe(struct comedi_device *dev, int bus, int slot);
846 static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
848 struct comedi_subdevice *s;
853 bus = it->options[0];
854 slot = it->options[1];
856 ret = alloc_private(dev, sizeof(struct dt3k_private));
860 ret = dt_pci_probe(dev, bus, slot);
864 printk(" no DT board found\n");
868 dev->board_name = this_board->name;
870 if (request_irq(devpriv->pci_dev->irq, dt3k_interrupt, IRQF_SHARED,
872 printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq);
875 dev->irq = devpriv->pci_dev->irq;
877 ret = alloc_subdevices(dev, 4);
882 dev->read_subdev = s;
885 s->type = COMEDI_SUBD_AI;
886 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
887 s->n_chan = this_board->adchan;
888 s->insn_read = dt3k_ai_insn;
889 s->maxdata = (1 << this_board->adbits) - 1;
890 s->len_chanlist = 512;
891 s->range_table = &range_dt3000_ai; /* XXX */
892 s->do_cmd = dt3k_ai_cmd;
893 s->do_cmdtest = dt3k_ai_cmdtest;
894 s->cancel = dt3k_ai_cancel;
898 s->type = COMEDI_SUBD_AO;
899 s->subdev_flags = SDF_WRITABLE;
901 s->insn_read = dt3k_ao_insn_read;
902 s->insn_write = dt3k_ao_insn;
903 s->maxdata = (1 << this_board->dabits) - 1;
905 s->range_table = &range_bipolar10;
909 s->type = COMEDI_SUBD_DIO;
910 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
912 s->insn_config = dt3k_dio_insn_config;
913 s->insn_bits = dt3k_dio_insn_bits;
916 s->range_table = &range_digital;
920 s->type = COMEDI_SUBD_MEMORY;
921 s->subdev_flags = SDF_READABLE;
923 s->insn_read = dt3k_mem_insn_read;
926 s->range_table = &range_unknown;
931 s->type = COMEDI_SUBD_PROC;
937 static int dt3000_detach(struct comedi_device *dev)
940 free_irq(dev->irq, dev);
943 if (devpriv->pci_dev) {
944 if (devpriv->phys_addr)
945 comedi_pci_disable(devpriv->pci_dev);
946 pci_dev_put(devpriv->pci_dev);
948 if (devpriv->io_addr)
949 iounmap(devpriv->io_addr);
956 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
957 static int setup_pci(struct comedi_device *dev);
959 static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
963 struct pci_dev *pcidev;
966 while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
967 if ((bus == 0 && slot == 0) ||
968 (pcidev->bus->number == bus &&
969 PCI_SLOT(pcidev->devfn) == slot)) {
973 devpriv->pci_dev = pcidev;
976 dev->board_ptr = dt3k_boardtypes + board;
978 if (!devpriv->pci_dev)
981 ret = setup_pci(dev);
988 static int setup_pci(struct comedi_device *dev)
990 resource_size_t addr;
993 ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
997 addr = pci_resource_start(devpriv->pci_dev, 0);
998 devpriv->phys_addr = addr;
999 devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
1000 if (!devpriv->io_addr)
1003 printk("0x%08llx mapped to %p, ",
1004 (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
1010 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
1014 for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
1016 from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
1017 for (i = 0; i < n_dt3k_boards; i++) {
1018 if (from->device == dt3k_boardtypes[i].device_id) {
1024 ("unknown Data Translation PCI device found with device_id=0x%04x\n",
1031 MODULE_AUTHOR("Comedi http://www.comedi.org");
1032 MODULE_DESCRIPTION("Comedi low-level driver");
1033 MODULE_LICENSE("GPL");