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: not applicable, uses PCI auto config
34 There is code to support AI commands, but it may not work.
36 AO commands are not supported.
40 The DT3000 series is Data Translation's attempt to make a PCI
41 data acquisition board. The design of this series is very nice,
42 since each board has an on-board DSP (Texas Instruments TMS320C52).
43 However, a few details are a little annoying. The boards lack
44 bus-mastering DMA, which eliminates them from serious work.
45 They also are not capable of autocalibration, which is a common
46 feature in modern hardware. The default firmware is pretty bad,
47 making it nearly impossible to write an RT compatible driver.
48 It would make an interesting project to write a decent firmware
51 Data Translation originally wanted an NDA for the documentation
52 for the 3k series. However, if you ask nicely, they might send
53 you the docs without one, also.
58 #include <linux/pci.h>
59 #include <linux/delay.h>
60 #include <linux/interrupt.h>
62 #include "../comedidev.h"
64 #include "comedi_fc.h"
67 * PCI device id's supported by this driver
69 #define PCI_DEVICE_ID_DT3001 0x0022
70 #define PCI_DEVICE_ID_DT3002 0x0023
71 #define PCI_DEVICE_ID_DT3003 0x0024
72 #define PCI_DEVICE_ID_DT3004 0x0025
73 #define PCI_DEVICE_ID_DT3005 0x0026
74 #define PCI_DEVICE_ID_DT3001_PGL 0x0027
75 #define PCI_DEVICE_ID_DT3003_PGL 0x0028
77 static const struct comedi_lrange range_dt3000_ai = {
86 static const struct comedi_lrange range_dt3000_ai_pgl = {
95 struct dt3k_boardtype {
97 unsigned int device_id;
101 const struct comedi_lrange *adrange;
106 static const struct dt3k_boardtype dt3k_boardtypes[] = {
109 .device_id = PCI_DEVICE_ID_DT3001,
112 .adrange = &range_dt3000_ai,
117 .name = "dt3001-pgl",
118 .device_id = PCI_DEVICE_ID_DT3001_PGL,
121 .adrange = &range_dt3000_ai_pgl,
127 .device_id = PCI_DEVICE_ID_DT3002,
130 .adrange = &range_dt3000_ai,
134 .device_id = PCI_DEVICE_ID_DT3003,
137 .adrange = &range_dt3000_ai,
142 .name = "dt3003-pgl",
143 .device_id = PCI_DEVICE_ID_DT3003_PGL,
146 .adrange = &range_dt3000_ai_pgl,
152 .device_id = PCI_DEVICE_ID_DT3004,
155 .adrange = &range_dt3000_ai,
160 .name = "dt3005", /* a.k.a. 3004-200 */
161 .device_id = PCI_DEVICE_ID_DT3005,
164 .adrange = &range_dt3000_ai,
171 #define DT3000_SIZE (4*0x1000)
173 /* dual-ported RAM location definitions */
175 #define DPR_DAC_buffer (4*0x000)
176 #define DPR_ADC_buffer (4*0x800)
177 #define DPR_Command (4*0xfd3)
178 #define DPR_SubSys (4*0xfd3)
179 #define DPR_Encode (4*0xfd4)
180 #define DPR_Params(a) (4*(0xfd5+(a)))
181 #define DPR_Tick_Reg_Lo (4*0xff5)
182 #define DPR_Tick_Reg_Hi (4*0xff6)
183 #define DPR_DA_Buf_Front (4*0xff7)
184 #define DPR_DA_Buf_Rear (4*0xff8)
185 #define DPR_AD_Buf_Front (4*0xff9)
186 #define DPR_AD_Buf_Rear (4*0xffa)
187 #define DPR_Int_Mask (4*0xffb)
188 #define DPR_Intr_Flag (4*0xffc)
189 #define DPR_Response_Mbx (4*0xffe)
190 #define DPR_Command_Mbx (4*0xfff)
192 #define AI_FIFO_DEPTH 2003
193 #define AO_FIFO_DEPTH 2048
197 #define CMD_GETBRDINFO 0
199 #define CMD_GETCONFIG 2
202 #define CMD_READSINGLE 5
203 #define CMD_WRITESINGLE 6
204 #define CMD_CALCCLOCK 7
205 #define CMD_READEVENTS 8
206 #define CMD_WRITECTCTRL 16
207 #define CMD_READCTCTRL 17
208 #define CMD_WRITECT 18
209 #define CMD_READCT 19
210 #define CMD_WRITEDATA 32
211 #define CMD_READDATA 33
212 #define CMD_WRITEIO 34
213 #define CMD_READIO 35
214 #define CMD_WRITECODE 36
215 #define CMD_READCODE 37
216 #define CMD_EXECUTE 38
226 /* interrupt flags */
227 #define DT3000_CMDONE 0x80
228 #define DT3000_CTDONE 0x40
229 #define DT3000_DAHWERR 0x20
230 #define DT3000_DASWERR 0x10
231 #define DT3000_DAEMPTY 0x08
232 #define DT3000_ADHWERR 0x04
233 #define DT3000_ADSWERR 0x02
234 #define DT3000_ADFULL 0x01
236 #define DT3000_COMPLETION_MASK 0xff00
237 #define DT3000_COMMAND_MASK 0x00ff
238 #define DT3000_NOTPROCESSED 0x0000
239 #define DT3000_NOERROR 0x5500
240 #define DT3000_ERROR 0xaa00
241 #define DT3000_NOTSUPPORTED 0xff00
243 #define DT3000_EXTERNAL_CLOCK 1
244 #define DT3000_RISING_EDGE 2
246 #define TMODE_MASK 0x1c
248 #define DT3000_AD_TRIG_INTERNAL (0<<2)
249 #define DT3000_AD_TRIG_EXTERNAL (1<<2)
250 #define DT3000_AD_RETRIG_INTERNAL (2<<2)
251 #define DT3000_AD_RETRIG_EXTERNAL (3<<2)
252 #define DT3000_AD_EXTRETRIG (4<<2)
254 #define DT3000_CHANNEL_MODE_SE 0
255 #define DT3000_CHANNEL_MODE_DI 1
257 struct dt3k_private {
258 void __iomem *io_addr;
260 unsigned int ao_readback[2];
261 unsigned int ai_front;
262 unsigned int ai_rear;
266 static char *intr_flags[] = {
267 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
268 "DaSwError", "DaHwError", "CtDone", "CmDone",
271 static void debug_intr_flags(unsigned int flags)
274 printk(KERN_DEBUG "dt3k: intr_flags:");
275 for (i = 0; i < 8; i++) {
276 if (flags & (1 << i))
277 printk(KERN_CONT " %s", intr_flags[i]);
279 printk(KERN_CONT "\n");
285 static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
287 struct dt3k_private *devpriv = dev->private;
289 unsigned int status = 0;
291 writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
293 for (i = 0; i < TIMEOUT; i++) {
294 status = readw(devpriv->io_addr + DPR_Command_Mbx);
295 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
300 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOERROR)
301 dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n",
305 static unsigned int dt3k_readsingle(struct comedi_device *dev,
306 unsigned int subsys, unsigned int chan,
309 struct dt3k_private *devpriv = dev->private;
311 writew(subsys, devpriv->io_addr + DPR_SubSys);
313 writew(chan, devpriv->io_addr + DPR_Params(0));
314 writew(gain, devpriv->io_addr + DPR_Params(1));
316 dt3k_send_cmd(dev, CMD_READSINGLE);
318 return readw(devpriv->io_addr + DPR_Params(2));
321 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
322 unsigned int chan, unsigned int data)
324 struct dt3k_private *devpriv = dev->private;
326 writew(subsys, devpriv->io_addr + DPR_SubSys);
328 writew(chan, devpriv->io_addr + DPR_Params(0));
329 writew(0, devpriv->io_addr + DPR_Params(1));
330 writew(data, devpriv->io_addr + DPR_Params(2));
332 dt3k_send_cmd(dev, CMD_WRITESINGLE);
335 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
336 struct comedi_subdevice *s)
338 struct dt3k_private *devpriv = dev->private;
345 front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
346 count = front - devpriv->ai_front;
348 count += AI_FIFO_DEPTH;
350 rear = devpriv->ai_rear;
352 for (i = 0; i < count; i++) {
353 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
354 comedi_buf_put(s->async, data);
356 if (rear >= AI_FIFO_DEPTH)
360 devpriv->ai_rear = rear;
361 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
364 static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
366 struct dt3k_private *devpriv = dev->private;
368 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
369 dt3k_send_cmd(dev, CMD_STOP);
371 writew(0, devpriv->io_addr + DPR_Int_Mask);
376 static int debug_n_ints;
378 /* FIXME! Assumes shared interrupt is for this card. */
379 /* What's this debug_n_ints stuff? Obviously needs some work... */
380 static irqreturn_t dt3k_interrupt(int irq, void *d)
382 struct comedi_device *dev = d;
383 struct dt3k_private *devpriv = dev->private;
384 struct comedi_subdevice *s;
390 s = &dev->subdevices[0];
391 status = readw(devpriv->io_addr + DPR_Intr_Flag);
393 debug_intr_flags(status);
396 if (status & DT3000_ADFULL) {
397 dt3k_ai_empty_fifo(dev, s);
398 s->async->events |= COMEDI_CB_BLOCK;
401 if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
402 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
405 if (debug_n_ints >= 10) {
406 dt3k_ai_cancel(dev, s);
407 s->async->events |= COMEDI_CB_EOA;
410 comedi_event(dev, s);
414 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
415 unsigned int round_mode)
417 int divider, base, prescale;
419 /* This function needs improvment */
420 /* Don't know if divider==0 works. */
422 for (prescale = 0; prescale < 16; prescale++) {
423 base = timer_base * (prescale + 1);
424 switch (round_mode) {
425 case TRIG_ROUND_NEAREST:
427 divider = (*nanosec + base / 2) / base;
429 case TRIG_ROUND_DOWN:
430 divider = (*nanosec) / base;
433 divider = (*nanosec) / base;
436 if (divider < 65536) {
437 *nanosec = divider * base;
438 return (prescale << 16) | (divider);
443 base = timer_base * (1 << prescale);
445 *nanosec = divider * base;
446 return (prescale << 16) | (divider);
449 static int dt3k_ai_cmdtest(struct comedi_device *dev,
450 struct comedi_subdevice *s, struct comedi_cmd *cmd)
452 const struct dt3k_boardtype *this_board = comedi_board(dev);
456 /* Step 1 : check if triggers are trivially valid */
458 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
459 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
460 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
461 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
462 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
467 /* Step 2a : make sure trigger sources are unique */
468 /* Step 2b : and mutually compatible */
473 /* Step 3: check if arguments are trivially valid */
475 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
477 if (cmd->scan_begin_src == TRIG_TIMER) {
478 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
479 this_board->ai_speed);
480 err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
484 if (cmd->convert_src == TRIG_TIMER) {
485 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
486 this_board->ai_speed);
487 err |= cfc_check_trigger_arg_max(&cmd->convert_arg,
491 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
493 if (cmd->stop_src == TRIG_COUNT)
494 err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
496 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
501 /* step 4: fix up any arguments */
503 if (cmd->scan_begin_src == TRIG_TIMER) {
504 tmp = cmd->scan_begin_arg;
505 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
506 cmd->flags & TRIG_ROUND_MASK);
507 if (tmp != cmd->scan_begin_arg)
511 if (cmd->convert_src == TRIG_TIMER) {
512 tmp = cmd->convert_arg;
513 dt3k_ns_to_timer(50, &cmd->convert_arg,
514 cmd->flags & TRIG_ROUND_MASK);
515 if (tmp != cmd->convert_arg)
517 if (cmd->scan_begin_src == TRIG_TIMER &&
518 cmd->scan_begin_arg <
519 cmd->convert_arg * cmd->scan_end_arg) {
520 cmd->scan_begin_arg =
521 cmd->convert_arg * cmd->scan_end_arg;
532 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
534 struct dt3k_private *devpriv = dev->private;
535 struct comedi_cmd *cmd = &s->async->cmd;
537 unsigned int chan, range, aref;
538 unsigned int divider;
539 unsigned int tscandiv;
542 for (i = 0; i < cmd->chanlist_len; i++) {
543 chan = CR_CHAN(cmd->chanlist[i]);
544 range = CR_RANGE(cmd->chanlist[i]);
546 writew((range << 6) | chan,
547 devpriv->io_addr + DPR_ADC_buffer + i);
549 aref = CR_AREF(cmd->chanlist[0]);
551 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
553 if (cmd->convert_src == TRIG_TIMER) {
554 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
555 cmd->flags & TRIG_ROUND_MASK);
556 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
557 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
560 if (cmd->scan_begin_src == TRIG_TIMER) {
561 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
562 cmd->flags & TRIG_ROUND_MASK);
563 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
564 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
567 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
568 writew(mode, devpriv->io_addr + DPR_Params(5));
569 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
571 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
573 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
574 dt3k_send_cmd(dev, CMD_CONFIG);
576 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
577 devpriv->io_addr + DPR_Int_Mask);
581 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
582 dt3k_send_cmd(dev, CMD_START);
587 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
588 struct comedi_insn *insn, unsigned int *data)
591 unsigned int chan, gain, aref;
593 chan = CR_CHAN(insn->chanspec);
594 gain = CR_RANGE(insn->chanspec);
595 /* XXX docs don't explain how to select aref */
596 aref = CR_AREF(insn->chanspec);
598 for (i = 0; i < insn->n; i++)
599 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
604 static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
605 struct comedi_insn *insn, unsigned int *data)
607 struct dt3k_private *devpriv = dev->private;
611 chan = CR_CHAN(insn->chanspec);
612 for (i = 0; i < insn->n; i++) {
613 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
614 devpriv->ao_readback[chan] = data[i];
620 static int dt3k_ao_insn_read(struct comedi_device *dev,
621 struct comedi_subdevice *s,
622 struct comedi_insn *insn, unsigned int *data)
624 struct dt3k_private *devpriv = dev->private;
628 chan = CR_CHAN(insn->chanspec);
629 for (i = 0; i < insn->n; i++)
630 data[i] = devpriv->ao_readback[chan];
635 static void dt3k_dio_config(struct comedi_device *dev, int bits)
637 struct dt3k_private *devpriv = dev->private;
640 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
642 writew(bits, devpriv->io_addr + DPR_Params(0));
645 writew(0, devpriv->io_addr + DPR_Params(1));
646 writew(0, devpriv->io_addr + DPR_Params(2));
649 dt3k_send_cmd(dev, CMD_CONFIG);
652 static int dt3k_dio_insn_config(struct comedi_device *dev,
653 struct comedi_subdevice *s,
654 struct comedi_insn *insn, unsigned int *data)
658 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
661 case INSN_CONFIG_DIO_OUTPUT:
664 case INSN_CONFIG_DIO_INPUT:
667 case INSN_CONFIG_DIO_QUERY:
670 io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
678 mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
679 dt3k_dio_config(dev, mask);
684 static int dt3k_dio_insn_bits(struct comedi_device *dev,
685 struct comedi_subdevice *s,
686 struct comedi_insn *insn, unsigned int *data)
689 s->state &= ~data[0];
690 s->state |= data[1] & data[0];
691 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
693 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
698 static int dt3k_mem_insn_read(struct comedi_device *dev,
699 struct comedi_subdevice *s,
700 struct comedi_insn *insn, unsigned int *data)
702 struct dt3k_private *devpriv = dev->private;
703 unsigned int addr = CR_CHAN(insn->chanspec);
706 for (i = 0; i < insn->n; i++) {
707 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
708 writew(addr, devpriv->io_addr + DPR_Params(0));
709 writew(1, devpriv->io_addr + DPR_Params(1));
711 dt3k_send_cmd(dev, CMD_READCODE);
713 data[i] = readw(devpriv->io_addr + DPR_Params(2));
719 static const void *dt3000_find_boardinfo(struct comedi_device *dev,
720 struct pci_dev *pcidev)
722 const struct dt3k_boardtype *this_board;
725 for (i = 0; i < ARRAY_SIZE(dt3k_boardtypes); i++) {
726 this_board = &dt3k_boardtypes[i];
727 if (this_board->device_id == pcidev->device)
733 static int dt3000_auto_attach(struct comedi_device *dev,
734 unsigned long context_unused)
736 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
737 const struct dt3k_boardtype *this_board;
738 struct dt3k_private *devpriv;
739 struct comedi_subdevice *s;
740 resource_size_t pci_base;
743 this_board = dt3000_find_boardinfo(dev, pcidev);
746 dev->board_ptr = this_board;
747 dev->board_name = this_board->name;
749 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
752 dev->private = devpriv;
754 ret = comedi_pci_enable(pcidev, dev->board_name);
757 dev->iobase = 1; /* the "detach" needs this */
759 pci_base = pci_resource_start(pcidev, 0);
760 devpriv->io_addr = ioremap(pci_base, DT3000_SIZE);
761 if (!devpriv->io_addr)
764 ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
765 dev->board_name, dev);
768 dev->irq = pcidev->irq;
770 ret = comedi_alloc_subdevices(dev, 4);
774 s = &dev->subdevices[0];
775 dev->read_subdev = s;
777 s->type = COMEDI_SUBD_AI;
778 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
779 s->n_chan = this_board->adchan;
780 s->insn_read = dt3k_ai_insn;
781 s->maxdata = (1 << this_board->adbits) - 1;
782 s->len_chanlist = 512;
783 s->range_table = &range_dt3000_ai; /* XXX */
784 s->do_cmd = dt3k_ai_cmd;
785 s->do_cmdtest = dt3k_ai_cmdtest;
786 s->cancel = dt3k_ai_cancel;
788 s = &dev->subdevices[1];
790 s->type = COMEDI_SUBD_AO;
791 s->subdev_flags = SDF_WRITABLE;
793 s->insn_read = dt3k_ao_insn_read;
794 s->insn_write = dt3k_ao_insn;
795 s->maxdata = (1 << this_board->dabits) - 1;
797 s->range_table = &range_bipolar10;
799 s = &dev->subdevices[2];
801 s->type = COMEDI_SUBD_DIO;
802 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
804 s->insn_config = dt3k_dio_insn_config;
805 s->insn_bits = dt3k_dio_insn_bits;
808 s->range_table = &range_digital;
810 s = &dev->subdevices[3];
812 s->type = COMEDI_SUBD_MEMORY;
813 s->subdev_flags = SDF_READABLE;
815 s->insn_read = dt3k_mem_insn_read;
818 s->range_table = &range_unknown;
821 s = &dev->subdevices[4];
823 s->type = COMEDI_SUBD_PROC;
826 dev_info(dev->class_dev, "%s attached\n", dev->board_name);
831 static void dt3000_detach(struct comedi_device *dev)
833 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
834 struct dt3k_private *devpriv = dev->private;
837 free_irq(dev->irq, dev);
839 if (devpriv->io_addr)
840 iounmap(devpriv->io_addr);
844 comedi_pci_disable(pcidev);
848 static struct comedi_driver dt3000_driver = {
849 .driver_name = "dt3000",
850 .module = THIS_MODULE,
851 .auto_attach = dt3000_auto_attach,
852 .detach = dt3000_detach,
855 static int dt3000_pci_probe(struct pci_dev *dev,
856 const struct pci_device_id *ent)
858 return comedi_pci_auto_config(dev, &dt3000_driver);
861 static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table) = {
862 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3001) },
863 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3001_PGL) },
864 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3002) },
865 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3003) },
866 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3003_PGL) },
867 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3004) },
868 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3005) },
871 MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
873 static struct pci_driver dt3000_pci_driver = {
875 .id_table = dt3000_pci_table,
876 .probe = dt3000_pci_probe,
877 .remove = comedi_pci_auto_unconfig,
879 module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
881 MODULE_AUTHOR("Comedi http://www.comedi.org");
882 MODULE_DESCRIPTION("Comedi low-level driver");
883 MODULE_LICENSE("GPL");