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 COMEDI_PCI_INITCLEANUP(driver_dt3000, dt3k_pci_table);
292 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
293 struct comedi_subdevice *s);
294 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
295 unsigned int round_mode);
296 static int dt3k_ai_cancel(struct comedi_device *dev,
297 struct comedi_subdevice *s);
299 static void debug_intr_flags(unsigned int flags);
304 static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
307 unsigned int status = 0;
309 writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
311 for (i = 0; i < TIMEOUT; i++) {
312 status = readw(devpriv->io_addr + DPR_Command_Mbx);
313 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
317 if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR) {
321 printk("dt3k_send_cmd() timeout/error status=0x%04x\n", status);
326 static unsigned int dt3k_readsingle(struct comedi_device *dev,
327 unsigned int subsys, unsigned int chan,
330 writew(subsys, devpriv->io_addr + DPR_SubSys);
332 writew(chan, devpriv->io_addr + DPR_Params(0));
333 writew(gain, devpriv->io_addr + DPR_Params(1));
335 dt3k_send_cmd(dev, CMD_READSINGLE);
337 return readw(devpriv->io_addr + DPR_Params(2));
340 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
341 unsigned int chan, unsigned int data)
343 writew(subsys, devpriv->io_addr + DPR_SubSys);
345 writew(chan, devpriv->io_addr + DPR_Params(0));
346 writew(0, devpriv->io_addr + DPR_Params(1));
347 writew(data, devpriv->io_addr + DPR_Params(2));
349 dt3k_send_cmd(dev, CMD_WRITESINGLE);
352 static int debug_n_ints = 0;
354 /* FIXME! Assumes shared interrupt is for this card. */
355 /* What's this debug_n_ints stuff? Obviously needs some work... */
356 static irqreturn_t dt3k_interrupt(int irq, void *d)
358 struct comedi_device *dev = d;
359 struct comedi_subdevice *s;
362 if (!dev->attached) {
366 s = dev->subdevices + 0;
367 status = readw(devpriv->io_addr + DPR_Intr_Flag);
369 debug_intr_flags(status);
372 if (status & DT3000_ADFULL) {
373 dt3k_ai_empty_fifo(dev, s);
374 s->async->events |= COMEDI_CB_BLOCK;
377 if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) {
378 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
382 if (debug_n_ints >= 10) {
383 dt3k_ai_cancel(dev, s);
384 s->async->events |= COMEDI_CB_EOA;
387 comedi_event(dev, s);
392 static char *intr_flags[] = {
393 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
394 "DaSwError", "DaHwError", "CtDone", "CmDone",
397 static void debug_intr_flags(unsigned int flags)
400 printk("dt3k: intr_flags:");
401 for (i = 0; i < 8; i++) {
402 if (flags & (1 << i)) {
403 printk(" %s", intr_flags[i]);
410 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
411 struct comedi_subdevice *s)
419 front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
420 count = front - devpriv->ai_front;
422 count += AI_FIFO_DEPTH;
424 printk("reading %d samples\n", count);
426 rear = devpriv->ai_rear;
428 for (i = 0; i < count; i++) {
429 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
430 comedi_buf_put(s->async, data);
432 if (rear >= AI_FIFO_DEPTH)
436 devpriv->ai_rear = rear;
437 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
440 static int dt3k_ai_cmdtest(struct comedi_device *dev,
441 struct comedi_subdevice *s, struct comedi_cmd *cmd)
446 /* step 1: make sure trigger sources are trivially valid */
448 tmp = cmd->start_src;
449 cmd->start_src &= TRIG_NOW;
450 if (!cmd->start_src || tmp != cmd->start_src)
453 tmp = cmd->scan_begin_src;
454 cmd->scan_begin_src &= TRIG_TIMER;
455 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
458 tmp = cmd->convert_src;
459 cmd->convert_src &= TRIG_TIMER;
460 if (!cmd->convert_src || tmp != cmd->convert_src)
463 tmp = cmd->scan_end_src;
464 cmd->scan_end_src &= TRIG_COUNT;
465 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
469 cmd->stop_src &= TRIG_COUNT;
470 if (!cmd->stop_src || tmp != cmd->stop_src)
476 /* step 2: make sure trigger sources are unique and mutually compatible */
481 /* step 3: make sure arguments are trivially compatible */
483 if (cmd->start_arg != 0) {
488 if (cmd->scan_begin_src == TRIG_TIMER) {
489 if (cmd->scan_begin_arg < this_board->ai_speed) {
490 cmd->scan_begin_arg = this_board->ai_speed;
493 if (cmd->scan_begin_arg > 100 * 16 * 65535) {
494 cmd->scan_begin_arg = 100 * 16 * 65535;
500 if (cmd->convert_src == TRIG_TIMER) {
501 if (cmd->convert_arg < this_board->ai_speed) {
502 cmd->convert_arg = this_board->ai_speed;
505 if (cmd->convert_arg > 50 * 16 * 65535) {
506 cmd->convert_arg = 50 * 16 * 65535;
513 if (cmd->scan_end_arg != cmd->chanlist_len) {
514 cmd->scan_end_arg = cmd->chanlist_len;
517 if (cmd->stop_src == TRIG_COUNT) {
518 if (cmd->stop_arg > 0x00ffffff) {
519 cmd->stop_arg = 0x00ffffff;
524 if (cmd->stop_arg != 0) {
533 /* step 4: fix up any arguments */
535 if (cmd->scan_begin_src == TRIG_TIMER) {
536 tmp = cmd->scan_begin_arg;
537 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
538 cmd->flags & TRIG_ROUND_MASK);
539 if (tmp != cmd->scan_begin_arg)
544 if (cmd->convert_src == TRIG_TIMER) {
545 tmp = cmd->convert_arg;
546 dt3k_ns_to_timer(50, &cmd->convert_arg,
547 cmd->flags & TRIG_ROUND_MASK);
548 if (tmp != cmd->convert_arg)
550 if (cmd->scan_begin_src == TRIG_TIMER &&
551 cmd->scan_begin_arg <
552 cmd->convert_arg * cmd->scan_end_arg) {
553 cmd->scan_begin_arg =
554 cmd->convert_arg * cmd->scan_end_arg;
567 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
568 unsigned int round_mode)
570 int divider, base, prescale;
572 /* This function needs improvment */
573 /* Don't know if divider==0 works. */
575 for (prescale = 0; prescale < 16; prescale++) {
576 base = timer_base * (prescale + 1);
577 switch (round_mode) {
578 case TRIG_ROUND_NEAREST:
580 divider = (*nanosec + base / 2) / base;
582 case TRIG_ROUND_DOWN:
583 divider = (*nanosec) / base;
586 divider = (*nanosec) / base;
589 if (divider < 65536) {
590 *nanosec = divider * base;
591 return (prescale << 16) | (divider);
596 base = timer_base * (1 << prescale);
598 *nanosec = divider * base;
599 return (prescale << 16) | (divider);
602 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
604 struct comedi_cmd *cmd = &s->async->cmd;
606 unsigned int chan, range, aref;
607 unsigned int divider;
608 unsigned int tscandiv;
612 printk("dt3k_ai_cmd:\n");
613 for (i = 0; i < cmd->chanlist_len; i++) {
614 chan = CR_CHAN(cmd->chanlist[i]);
615 range = CR_RANGE(cmd->chanlist[i]);
617 writew((range << 6) | chan,
618 devpriv->io_addr + DPR_ADC_buffer + i);
620 aref = CR_AREF(cmd->chanlist[0]);
622 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
623 printk("param[0]=0x%04x\n", cmd->scan_end_arg);
625 if (cmd->convert_src == TRIG_TIMER) {
626 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
627 cmd->flags & TRIG_ROUND_MASK);
628 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
629 printk("param[1]=0x%04x\n", divider >> 16);
630 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
631 printk("param[2]=0x%04x\n", divider & 0xffff);
636 if (cmd->scan_begin_src == TRIG_TIMER) {
637 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
638 cmd->flags & TRIG_ROUND_MASK);
639 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
640 printk("param[3]=0x%04x\n", tscandiv >> 16);
641 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
642 printk("param[4]=0x%04x\n", tscandiv & 0xffff);
647 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
648 writew(mode, devpriv->io_addr + DPR_Params(5));
649 printk("param[5]=0x%04x\n", mode);
650 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
651 printk("param[6]=0x%04x\n", aref == AREF_DIFF);
653 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
654 printk("param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
656 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
657 ret = dt3k_send_cmd(dev, CMD_CONFIG);
659 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
660 devpriv->io_addr + DPR_Int_Mask);
664 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
665 ret = dt3k_send_cmd(dev, CMD_START);
670 static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
674 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
675 ret = dt3k_send_cmd(dev, CMD_STOP);
677 writew(0, devpriv->io_addr + DPR_Int_Mask);
682 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
683 struct comedi_insn *insn, unsigned int *data)
686 unsigned int chan, gain, aref;
688 chan = CR_CHAN(insn->chanspec);
689 gain = CR_RANGE(insn->chanspec);
690 /* XXX docs don't explain how to select aref */
691 aref = CR_AREF(insn->chanspec);
693 for (i = 0; i < insn->n; i++) {
694 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
700 static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
701 struct comedi_insn *insn, unsigned int *data)
706 chan = CR_CHAN(insn->chanspec);
707 for (i = 0; i < insn->n; i++) {
708 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
709 devpriv->ao_readback[chan] = data[i];
715 static int dt3k_ao_insn_read(struct comedi_device *dev,
716 struct comedi_subdevice *s,
717 struct comedi_insn *insn, unsigned int *data)
722 chan = CR_CHAN(insn->chanspec);
723 for (i = 0; i < insn->n; i++) {
724 data[i] = devpriv->ao_readback[chan];
730 static void dt3k_dio_config(struct comedi_device *dev, int bits)
733 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
735 writew(bits, devpriv->io_addr + DPR_Params(0));
738 writew(0, devpriv->io_addr + DPR_Params(1));
739 writew(0, devpriv->io_addr + DPR_Params(2));
742 dt3k_send_cmd(dev, CMD_CONFIG);
745 static int dt3k_dio_insn_config(struct comedi_device *dev,
746 struct comedi_subdevice *s,
747 struct comedi_insn *insn, unsigned int *data)
751 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
754 case INSN_CONFIG_DIO_OUTPUT:
757 case INSN_CONFIG_DIO_INPUT:
760 case INSN_CONFIG_DIO_QUERY:
763 io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
771 mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
772 dt3k_dio_config(dev, mask);
777 static int dt3k_dio_insn_bits(struct comedi_device *dev,
778 struct comedi_subdevice *s,
779 struct comedi_insn *insn, unsigned int *data)
785 s->state &= ~data[0];
786 s->state |= data[1] & data[0];
787 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
789 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
794 static int dt3k_mem_insn_read(struct comedi_device *dev,
795 struct comedi_subdevice *s,
796 struct comedi_insn *insn, unsigned int *data)
798 unsigned int addr = CR_CHAN(insn->chanspec);
801 for (i = 0; i < insn->n; i++) {
802 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
803 writew(addr, devpriv->io_addr + DPR_Params(0));
804 writew(1, devpriv->io_addr + DPR_Params(1));
806 dt3k_send_cmd(dev, CMD_READCODE);
808 data[i] = readw(devpriv->io_addr + DPR_Params(2));
814 static int dt_pci_probe(struct comedi_device *dev, int bus, int slot);
816 static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
818 struct comedi_subdevice *s;
823 bus = it->options[0];
824 slot = it->options[1];
826 ret = alloc_private(dev, sizeof(struct dt3k_private));
830 ret = dt_pci_probe(dev, bus, slot);
834 printk(" no DT board found\n");
838 dev->board_name = this_board->name;
840 if (request_irq(devpriv->pci_dev->irq, dt3k_interrupt, IRQF_SHARED,
842 printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq);
845 dev->irq = devpriv->pci_dev->irq;
847 ret = alloc_subdevices(dev, 4);
852 dev->read_subdev = s;
855 s->type = COMEDI_SUBD_AI;
856 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
857 s->n_chan = this_board->adchan;
858 s->insn_read = dt3k_ai_insn;
859 s->maxdata = (1 << this_board->adbits) - 1;
860 s->len_chanlist = 512;
861 s->range_table = &range_dt3000_ai; /* XXX */
862 s->do_cmd = dt3k_ai_cmd;
863 s->do_cmdtest = dt3k_ai_cmdtest;
864 s->cancel = dt3k_ai_cancel;
868 s->type = COMEDI_SUBD_AO;
869 s->subdev_flags = SDF_WRITABLE;
871 s->insn_read = dt3k_ao_insn_read;
872 s->insn_write = dt3k_ao_insn;
873 s->maxdata = (1 << this_board->dabits) - 1;
875 s->range_table = &range_bipolar10;
879 s->type = COMEDI_SUBD_DIO;
880 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
882 s->insn_config = dt3k_dio_insn_config;
883 s->insn_bits = dt3k_dio_insn_bits;
886 s->range_table = &range_digital;
890 s->type = COMEDI_SUBD_MEMORY;
891 s->subdev_flags = SDF_READABLE;
893 s->insn_read = dt3k_mem_insn_read;
896 s->range_table = &range_unknown;
901 s->type = COMEDI_SUBD_PROC;
907 static int dt3000_detach(struct comedi_device *dev)
910 free_irq(dev->irq, dev);
913 if (devpriv->pci_dev) {
914 if (devpriv->phys_addr) {
915 comedi_pci_disable(devpriv->pci_dev);
917 pci_dev_put(devpriv->pci_dev);
919 if (devpriv->io_addr)
920 iounmap(devpriv->io_addr);
927 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
928 static int setup_pci(struct comedi_device *dev);
930 static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
934 struct pci_dev *pcidev;
937 while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
938 if ((bus == 0 && slot == 0) ||
939 (pcidev->bus->number == bus &&
940 PCI_SLOT(pcidev->devfn) == slot)) {
944 devpriv->pci_dev = pcidev;
947 dev->board_ptr = dt3k_boardtypes + board;
949 if (!devpriv->pci_dev)
952 ret = setup_pci(dev);
959 static int setup_pci(struct comedi_device *dev)
961 resource_size_t addr;
964 ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
968 addr = pci_resource_start(devpriv->pci_dev, 0);
969 devpriv->phys_addr = addr;
970 devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
971 if (!devpriv->io_addr)
974 printk("0x%08llx mapped to %p, ",
975 (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
981 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
985 for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
987 from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
988 for (i = 0; i < n_dt3k_boards; i++) {
989 if (from->device == dt3k_boardtypes[i].device_id) {
995 ("unknown Data Translation PCI device found with device_id=0x%04x\n",