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/interrupt.h>
59 #include "../comedidev.h"
60 #include <linux/delay.h>
62 #include "comedi_fc.h"
65 * PCI device id's supported by this driver
67 #define PCI_DEVICE_ID_DT3001 0x0022
68 #define PCI_DEVICE_ID_DT3002 0x0023
69 #define PCI_DEVICE_ID_DT3003 0x0024
70 #define PCI_DEVICE_ID_DT3004 0x0025
71 #define PCI_DEVICE_ID_DT3005 0x0026
72 #define PCI_DEVICE_ID_DT3001_PGL 0x0027
73 #define PCI_DEVICE_ID_DT3003_PGL 0x0028
75 static const struct comedi_lrange range_dt3000_ai = {
84 static const struct comedi_lrange range_dt3000_ai_pgl = {
93 struct dt3k_boardtype {
95 unsigned int device_id;
99 const struct comedi_lrange *adrange;
104 static const struct dt3k_boardtype dt3k_boardtypes[] = {
107 .device_id = PCI_DEVICE_ID_DT3001,
110 .adrange = &range_dt3000_ai,
115 .name = "dt3001-pgl",
116 .device_id = PCI_DEVICE_ID_DT3001_PGL,
119 .adrange = &range_dt3000_ai_pgl,
125 .device_id = PCI_DEVICE_ID_DT3002,
128 .adrange = &range_dt3000_ai,
132 .device_id = PCI_DEVICE_ID_DT3003,
135 .adrange = &range_dt3000_ai,
140 .name = "dt3003-pgl",
141 .device_id = PCI_DEVICE_ID_DT3003_PGL,
144 .adrange = &range_dt3000_ai_pgl,
150 .device_id = PCI_DEVICE_ID_DT3004,
153 .adrange = &range_dt3000_ai,
158 .name = "dt3005", /* a.k.a. 3004-200 */
159 .device_id = PCI_DEVICE_ID_DT3005,
162 .adrange = &range_dt3000_ai,
169 #define DT3000_SIZE (4*0x1000)
171 /* dual-ported RAM location definitions */
173 #define DPR_DAC_buffer (4*0x000)
174 #define DPR_ADC_buffer (4*0x800)
175 #define DPR_Command (4*0xfd3)
176 #define DPR_SubSys (4*0xfd3)
177 #define DPR_Encode (4*0xfd4)
178 #define DPR_Params(a) (4*(0xfd5+(a)))
179 #define DPR_Tick_Reg_Lo (4*0xff5)
180 #define DPR_Tick_Reg_Hi (4*0xff6)
181 #define DPR_DA_Buf_Front (4*0xff7)
182 #define DPR_DA_Buf_Rear (4*0xff8)
183 #define DPR_AD_Buf_Front (4*0xff9)
184 #define DPR_AD_Buf_Rear (4*0xffa)
185 #define DPR_Int_Mask (4*0xffb)
186 #define DPR_Intr_Flag (4*0xffc)
187 #define DPR_Response_Mbx (4*0xffe)
188 #define DPR_Command_Mbx (4*0xfff)
190 #define AI_FIFO_DEPTH 2003
191 #define AO_FIFO_DEPTH 2048
195 #define CMD_GETBRDINFO 0
197 #define CMD_GETCONFIG 2
200 #define CMD_READSINGLE 5
201 #define CMD_WRITESINGLE 6
202 #define CMD_CALCCLOCK 7
203 #define CMD_READEVENTS 8
204 #define CMD_WRITECTCTRL 16
205 #define CMD_READCTCTRL 17
206 #define CMD_WRITECT 18
207 #define CMD_READCT 19
208 #define CMD_WRITEDATA 32
209 #define CMD_READDATA 33
210 #define CMD_WRITEIO 34
211 #define CMD_READIO 35
212 #define CMD_WRITECODE 36
213 #define CMD_READCODE 37
214 #define CMD_EXECUTE 38
224 /* interrupt flags */
225 #define DT3000_CMDONE 0x80
226 #define DT3000_CTDONE 0x40
227 #define DT3000_DAHWERR 0x20
228 #define DT3000_DASWERR 0x10
229 #define DT3000_DAEMPTY 0x08
230 #define DT3000_ADHWERR 0x04
231 #define DT3000_ADSWERR 0x02
232 #define DT3000_ADFULL 0x01
234 #define DT3000_COMPLETION_MASK 0xff00
235 #define DT3000_COMMAND_MASK 0x00ff
236 #define DT3000_NOTPROCESSED 0x0000
237 #define DT3000_NOERROR 0x5500
238 #define DT3000_ERROR 0xaa00
239 #define DT3000_NOTSUPPORTED 0xff00
241 #define DT3000_EXTERNAL_CLOCK 1
242 #define DT3000_RISING_EDGE 2
244 #define TMODE_MASK 0x1c
246 #define DT3000_AD_TRIG_INTERNAL (0<<2)
247 #define DT3000_AD_TRIG_EXTERNAL (1<<2)
248 #define DT3000_AD_RETRIG_INTERNAL (2<<2)
249 #define DT3000_AD_RETRIG_EXTERNAL (3<<2)
250 #define DT3000_AD_EXTRETRIG (4<<2)
252 #define DT3000_CHANNEL_MODE_SE 0
253 #define DT3000_CHANNEL_MODE_DI 1
255 struct dt3k_private {
256 void __iomem *io_addr;
258 unsigned int ao_readback[2];
259 unsigned int ai_front;
260 unsigned int ai_rear;
264 static char *intr_flags[] = {
265 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
266 "DaSwError", "DaHwError", "CtDone", "CmDone",
269 static void debug_intr_flags(unsigned int flags)
272 printk(KERN_DEBUG "dt3k: intr_flags:");
273 for (i = 0; i < 8; i++) {
274 if (flags & (1 << i))
275 printk(KERN_CONT " %s", intr_flags[i]);
277 printk(KERN_CONT "\n");
283 static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
285 struct dt3k_private *devpriv = dev->private;
287 unsigned int status = 0;
289 writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
291 for (i = 0; i < TIMEOUT; i++) {
292 status = readw(devpriv->io_addr + DPR_Command_Mbx);
293 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
298 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOERROR)
299 dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n",
303 static unsigned int dt3k_readsingle(struct comedi_device *dev,
304 unsigned int subsys, unsigned int chan,
307 struct dt3k_private *devpriv = dev->private;
309 writew(subsys, devpriv->io_addr + DPR_SubSys);
311 writew(chan, devpriv->io_addr + DPR_Params(0));
312 writew(gain, devpriv->io_addr + DPR_Params(1));
314 dt3k_send_cmd(dev, CMD_READSINGLE);
316 return readw(devpriv->io_addr + DPR_Params(2));
319 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
320 unsigned int chan, unsigned int data)
322 struct dt3k_private *devpriv = dev->private;
324 writew(subsys, devpriv->io_addr + DPR_SubSys);
326 writew(chan, devpriv->io_addr + DPR_Params(0));
327 writew(0, devpriv->io_addr + DPR_Params(1));
328 writew(data, devpriv->io_addr + DPR_Params(2));
330 dt3k_send_cmd(dev, CMD_WRITESINGLE);
333 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
334 struct comedi_subdevice *s)
336 struct dt3k_private *devpriv = dev->private;
343 front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
344 count = front - devpriv->ai_front;
346 count += AI_FIFO_DEPTH;
348 rear = devpriv->ai_rear;
350 for (i = 0; i < count; i++) {
351 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
352 comedi_buf_put(s->async, data);
354 if (rear >= AI_FIFO_DEPTH)
358 devpriv->ai_rear = rear;
359 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
362 static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
364 struct dt3k_private *devpriv = dev->private;
366 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
367 dt3k_send_cmd(dev, CMD_STOP);
369 writew(0, devpriv->io_addr + DPR_Int_Mask);
374 static int debug_n_ints;
376 /* FIXME! Assumes shared interrupt is for this card. */
377 /* What's this debug_n_ints stuff? Obviously needs some work... */
378 static irqreturn_t dt3k_interrupt(int irq, void *d)
380 struct comedi_device *dev = d;
381 struct dt3k_private *devpriv = dev->private;
382 struct comedi_subdevice *s;
388 s = &dev->subdevices[0];
389 status = readw(devpriv->io_addr + DPR_Intr_Flag);
391 debug_intr_flags(status);
394 if (status & DT3000_ADFULL) {
395 dt3k_ai_empty_fifo(dev, s);
396 s->async->events |= COMEDI_CB_BLOCK;
399 if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
400 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
403 if (debug_n_ints >= 10) {
404 dt3k_ai_cancel(dev, s);
405 s->async->events |= COMEDI_CB_EOA;
408 comedi_event(dev, s);
412 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
413 unsigned int round_mode)
415 int divider, base, prescale;
417 /* This function needs improvment */
418 /* Don't know if divider==0 works. */
420 for (prescale = 0; prescale < 16; prescale++) {
421 base = timer_base * (prescale + 1);
422 switch (round_mode) {
423 case TRIG_ROUND_NEAREST:
425 divider = (*nanosec + base / 2) / base;
427 case TRIG_ROUND_DOWN:
428 divider = (*nanosec) / base;
431 divider = (*nanosec) / base;
434 if (divider < 65536) {
435 *nanosec = divider * base;
436 return (prescale << 16) | (divider);
441 base = timer_base * (1 << prescale);
443 *nanosec = divider * base;
444 return (prescale << 16) | (divider);
447 static int dt3k_ai_cmdtest(struct comedi_device *dev,
448 struct comedi_subdevice *s, struct comedi_cmd *cmd)
450 const struct dt3k_boardtype *this_board = comedi_board(dev);
454 /* Step 1 : check if triggers are trivially valid */
456 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
457 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
458 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
459 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
460 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
465 /* Step 2a : make sure trigger sources are unique */
466 /* Step 2b : and mutually compatible */
471 /* Step 3: check if arguments are trivially valid */
473 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
475 if (cmd->scan_begin_src == TRIG_TIMER) {
476 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
477 this_board->ai_speed);
478 err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
482 if (cmd->convert_src == TRIG_TIMER) {
483 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
484 this_board->ai_speed);
485 err |= cfc_check_trigger_arg_max(&cmd->convert_arg,
489 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
491 if (cmd->stop_src == TRIG_COUNT)
492 err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
494 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
499 /* step 4: fix up any arguments */
501 if (cmd->scan_begin_src == TRIG_TIMER) {
502 tmp = cmd->scan_begin_arg;
503 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
504 cmd->flags & TRIG_ROUND_MASK);
505 if (tmp != cmd->scan_begin_arg)
509 if (cmd->convert_src == TRIG_TIMER) {
510 tmp = cmd->convert_arg;
511 dt3k_ns_to_timer(50, &cmd->convert_arg,
512 cmd->flags & TRIG_ROUND_MASK);
513 if (tmp != cmd->convert_arg)
515 if (cmd->scan_begin_src == TRIG_TIMER &&
516 cmd->scan_begin_arg <
517 cmd->convert_arg * cmd->scan_end_arg) {
518 cmd->scan_begin_arg =
519 cmd->convert_arg * cmd->scan_end_arg;
530 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
532 struct dt3k_private *devpriv = dev->private;
533 struct comedi_cmd *cmd = &s->async->cmd;
535 unsigned int chan, range, aref;
536 unsigned int divider;
537 unsigned int tscandiv;
540 for (i = 0; i < cmd->chanlist_len; i++) {
541 chan = CR_CHAN(cmd->chanlist[i]);
542 range = CR_RANGE(cmd->chanlist[i]);
544 writew((range << 6) | chan,
545 devpriv->io_addr + DPR_ADC_buffer + i);
547 aref = CR_AREF(cmd->chanlist[0]);
549 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
551 if (cmd->convert_src == TRIG_TIMER) {
552 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
553 cmd->flags & TRIG_ROUND_MASK);
554 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
555 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
558 if (cmd->scan_begin_src == TRIG_TIMER) {
559 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
560 cmd->flags & TRIG_ROUND_MASK);
561 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
562 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
565 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
566 writew(mode, devpriv->io_addr + DPR_Params(5));
567 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
569 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
571 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
572 dt3k_send_cmd(dev, CMD_CONFIG);
574 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
575 devpriv->io_addr + DPR_Int_Mask);
579 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
580 dt3k_send_cmd(dev, CMD_START);
585 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
586 struct comedi_insn *insn, unsigned int *data)
589 unsigned int chan, gain, aref;
591 chan = CR_CHAN(insn->chanspec);
592 gain = CR_RANGE(insn->chanspec);
593 /* XXX docs don't explain how to select aref */
594 aref = CR_AREF(insn->chanspec);
596 for (i = 0; i < insn->n; i++)
597 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
602 static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
603 struct comedi_insn *insn, unsigned int *data)
605 struct dt3k_private *devpriv = dev->private;
609 chan = CR_CHAN(insn->chanspec);
610 for (i = 0; i < insn->n; i++) {
611 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
612 devpriv->ao_readback[chan] = data[i];
618 static int dt3k_ao_insn_read(struct comedi_device *dev,
619 struct comedi_subdevice *s,
620 struct comedi_insn *insn, unsigned int *data)
622 struct dt3k_private *devpriv = dev->private;
626 chan = CR_CHAN(insn->chanspec);
627 for (i = 0; i < insn->n; i++)
628 data[i] = devpriv->ao_readback[chan];
633 static void dt3k_dio_config(struct comedi_device *dev, int bits)
635 struct dt3k_private *devpriv = dev->private;
638 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
640 writew(bits, devpriv->io_addr + DPR_Params(0));
643 writew(0, devpriv->io_addr + DPR_Params(1));
644 writew(0, devpriv->io_addr + DPR_Params(2));
647 dt3k_send_cmd(dev, CMD_CONFIG);
650 static int dt3k_dio_insn_config(struct comedi_device *dev,
651 struct comedi_subdevice *s,
652 struct comedi_insn *insn, unsigned int *data)
656 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
659 case INSN_CONFIG_DIO_OUTPUT:
662 case INSN_CONFIG_DIO_INPUT:
665 case INSN_CONFIG_DIO_QUERY:
668 io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
676 mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
677 dt3k_dio_config(dev, mask);
682 static int dt3k_dio_insn_bits(struct comedi_device *dev,
683 struct comedi_subdevice *s,
684 struct comedi_insn *insn, unsigned int *data)
687 s->state &= ~data[0];
688 s->state |= data[1] & data[0];
689 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
691 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
696 static int dt3k_mem_insn_read(struct comedi_device *dev,
697 struct comedi_subdevice *s,
698 struct comedi_insn *insn, unsigned int *data)
700 struct dt3k_private *devpriv = dev->private;
701 unsigned int addr = CR_CHAN(insn->chanspec);
704 for (i = 0; i < insn->n; i++) {
705 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
706 writew(addr, devpriv->io_addr + DPR_Params(0));
707 writew(1, devpriv->io_addr + DPR_Params(1));
709 dt3k_send_cmd(dev, CMD_READCODE);
711 data[i] = readw(devpriv->io_addr + DPR_Params(2));
717 static const void *dt3000_find_boardinfo(struct comedi_device *dev,
718 struct pci_dev *pcidev)
720 const struct dt3k_boardtype *this_board;
723 for (i = 0; i < ARRAY_SIZE(dt3k_boardtypes); i++) {
724 this_board = &dt3k_boardtypes[i];
725 if (this_board->device_id == pcidev->device)
731 static int dt3000_auto_attach(struct comedi_device *dev,
732 unsigned long context_unused)
734 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
735 const struct dt3k_boardtype *this_board;
736 struct dt3k_private *devpriv;
737 struct comedi_subdevice *s;
738 resource_size_t pci_base;
741 this_board = dt3000_find_boardinfo(dev, pcidev);
744 dev->board_ptr = this_board;
745 dev->board_name = this_board->name;
747 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
750 dev->private = devpriv;
752 ret = comedi_pci_enable(pcidev, dev->board_name);
755 dev->iobase = 1; /* the "detach" needs this */
757 pci_base = pci_resource_start(pcidev, 0);
758 devpriv->io_addr = ioremap(pci_base, DT3000_SIZE);
759 if (!devpriv->io_addr)
762 ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
763 dev->board_name, dev);
766 dev->irq = pcidev->irq;
768 ret = comedi_alloc_subdevices(dev, 4);
772 s = &dev->subdevices[0];
773 dev->read_subdev = s;
775 s->type = COMEDI_SUBD_AI;
776 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
777 s->n_chan = this_board->adchan;
778 s->insn_read = dt3k_ai_insn;
779 s->maxdata = (1 << this_board->adbits) - 1;
780 s->len_chanlist = 512;
781 s->range_table = &range_dt3000_ai; /* XXX */
782 s->do_cmd = dt3k_ai_cmd;
783 s->do_cmdtest = dt3k_ai_cmdtest;
784 s->cancel = dt3k_ai_cancel;
786 s = &dev->subdevices[1];
788 s->type = COMEDI_SUBD_AO;
789 s->subdev_flags = SDF_WRITABLE;
791 s->insn_read = dt3k_ao_insn_read;
792 s->insn_write = dt3k_ao_insn;
793 s->maxdata = (1 << this_board->dabits) - 1;
795 s->range_table = &range_bipolar10;
797 s = &dev->subdevices[2];
799 s->type = COMEDI_SUBD_DIO;
800 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
802 s->insn_config = dt3k_dio_insn_config;
803 s->insn_bits = dt3k_dio_insn_bits;
806 s->range_table = &range_digital;
808 s = &dev->subdevices[3];
810 s->type = COMEDI_SUBD_MEMORY;
811 s->subdev_flags = SDF_READABLE;
813 s->insn_read = dt3k_mem_insn_read;
816 s->range_table = &range_unknown;
819 s = &dev->subdevices[4];
821 s->type = COMEDI_SUBD_PROC;
824 dev_info(dev->class_dev, "%s attached\n", dev->board_name);
829 static void dt3000_detach(struct comedi_device *dev)
831 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
832 struct dt3k_private *devpriv = dev->private;
835 free_irq(dev->irq, dev);
837 if (devpriv->io_addr)
838 iounmap(devpriv->io_addr);
842 comedi_pci_disable(pcidev);
846 static struct comedi_driver dt3000_driver = {
847 .driver_name = "dt3000",
848 .module = THIS_MODULE,
849 .auto_attach = dt3000_auto_attach,
850 .detach = dt3000_detach,
853 static int dt3000_pci_probe(struct pci_dev *dev,
854 const struct pci_device_id *ent)
856 return comedi_pci_auto_config(dev, &dt3000_driver);
859 static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table) = {
860 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3001) },
861 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3001_PGL) },
862 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3002) },
863 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3003) },
864 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3003_PGL) },
865 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3004) },
866 { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3005) },
869 MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
871 static struct pci_driver dt3000_pci_driver = {
873 .id_table = dt3000_pci_table,
874 .probe = dt3000_pci_probe,
875 .remove = comedi_pci_auto_unconfig,
877 module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
879 MODULE_AUTHOR("Comedi http://www.comedi.org");
880 MODULE_DESCRIPTION("Comedi low-level driver");
881 MODULE_LICENSE("GPL");