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, {
77 static const struct comedi_lrange range_dt3000_ai_pgl = { 4, {
85 struct dt3k_boardtype {
88 unsigned int device_id;
92 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) = {
168 {PCI_VENDOR_ID_DT, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
169 {PCI_VENDOR_ID_DT, 0x0027, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
170 {PCI_VENDOR_ID_DT, 0x0023, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
171 {PCI_VENDOR_ID_DT, 0x0024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
172 {PCI_VENDOR_ID_DT, 0x0028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
173 {PCI_VENDOR_ID_DT, 0x0025, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
174 {PCI_VENDOR_ID_DT, 0x0026, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
178 MODULE_DEVICE_TABLE(pci, dt3k_pci_table);
180 #define DT3000_SIZE (4*0x1000)
182 /* dual-ported RAM location definitions */
184 #define DPR_DAC_buffer (4*0x000)
185 #define DPR_ADC_buffer (4*0x800)
186 #define DPR_Command (4*0xfd3)
187 #define DPR_SubSys (4*0xfd3)
188 #define DPR_Encode (4*0xfd4)
189 #define DPR_Params(a) (4*(0xfd5+(a)))
190 #define DPR_Tick_Reg_Lo (4*0xff5)
191 #define DPR_Tick_Reg_Hi (4*0xff6)
192 #define DPR_DA_Buf_Front (4*0xff7)
193 #define DPR_DA_Buf_Rear (4*0xff8)
194 #define DPR_AD_Buf_Front (4*0xff9)
195 #define DPR_AD_Buf_Rear (4*0xffa)
196 #define DPR_Int_Mask (4*0xffb)
197 #define DPR_Intr_Flag (4*0xffc)
198 #define DPR_Response_Mbx (4*0xffe)
199 #define DPR_Command_Mbx (4*0xfff)
201 #define AI_FIFO_DEPTH 2003
202 #define AO_FIFO_DEPTH 2048
206 #define CMD_GETBRDINFO 0
208 #define CMD_GETCONFIG 2
211 #define CMD_READSINGLE 5
212 #define CMD_WRITESINGLE 6
213 #define CMD_CALCCLOCK 7
214 #define CMD_READEVENTS 8
215 #define CMD_WRITECTCTRL 16
216 #define CMD_READCTCTRL 17
217 #define CMD_WRITECT 18
218 #define CMD_READCT 19
219 #define CMD_WRITEDATA 32
220 #define CMD_READDATA 33
221 #define CMD_WRITEIO 34
222 #define CMD_READIO 35
223 #define CMD_WRITECODE 36
224 #define CMD_READCODE 37
225 #define CMD_EXECUTE 38
235 /* interrupt flags */
236 #define DT3000_CMDONE 0x80
237 #define DT3000_CTDONE 0x40
238 #define DT3000_DAHWERR 0x20
239 #define DT3000_DASWERR 0x10
240 #define DT3000_DAEMPTY 0x08
241 #define DT3000_ADHWERR 0x04
242 #define DT3000_ADSWERR 0x02
243 #define DT3000_ADFULL 0x01
245 #define DT3000_COMPLETION_MASK 0xff00
246 #define DT3000_COMMAND_MASK 0x00ff
247 #define DT3000_NOTPROCESSED 0x0000
248 #define DT3000_NOERROR 0x5500
249 #define DT3000_ERROR 0xaa00
250 #define DT3000_NOTSUPPORTED 0xff00
252 #define DT3000_EXTERNAL_CLOCK 1
253 #define DT3000_RISING_EDGE 2
255 #define TMODE_MASK 0x1c
257 #define DT3000_AD_TRIG_INTERNAL (0<<2)
258 #define DT3000_AD_TRIG_EXTERNAL (1<<2)
259 #define DT3000_AD_RETRIG_INTERNAL (2<<2)
260 #define DT3000_AD_RETRIG_EXTERNAL (3<<2)
261 #define DT3000_AD_EXTRETRIG (4<<2)
263 #define DT3000_CHANNEL_MODE_SE 0
264 #define DT3000_CHANNEL_MODE_DI 1
266 struct dt3k_private {
268 struct pci_dev *pci_dev;
269 resource_size_t phys_addr;
272 unsigned int ao_readback[2];
273 unsigned int ai_front;
274 unsigned int ai_rear;
277 #define devpriv ((struct dt3k_private *)dev->private)
279 static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it);
280 static int dt3000_detach(struct comedi_device *dev);
281 static struct comedi_driver driver_dt3000 = {
282 .driver_name = "dt3000",
283 .module = THIS_MODULE,
284 .attach = dt3000_attach,
285 .detach = dt3000_detach,
288 COMEDI_PCI_INITCLEANUP(driver_dt3000, dt3k_pci_table);
290 static void dt3k_ai_empty_fifo(struct comedi_device *dev, struct comedi_subdevice *s);
291 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
292 unsigned int round_mode);
293 static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
295 static void debug_intr_flags(unsigned int flags);
300 static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
303 unsigned int status = 0;
305 writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
307 for (i = 0; i < TIMEOUT; i++) {
308 status = readw(devpriv->io_addr + DPR_Command_Mbx);
309 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
313 if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR) {
317 printk("dt3k_send_cmd() timeout/error status=0x%04x\n", status);
322 static unsigned int dt3k_readsingle(struct comedi_device *dev, unsigned int subsys,
323 unsigned int chan, unsigned int gain)
325 writew(subsys, devpriv->io_addr + DPR_SubSys);
327 writew(chan, devpriv->io_addr + DPR_Params(0));
328 writew(gain, devpriv->io_addr + DPR_Params(1));
330 dt3k_send_cmd(dev, CMD_READSINGLE);
332 return readw(devpriv->io_addr + DPR_Params(2));
335 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
336 unsigned int chan, unsigned int data)
338 writew(subsys, devpriv->io_addr + DPR_SubSys);
340 writew(chan, devpriv->io_addr + DPR_Params(0));
341 writew(0, devpriv->io_addr + DPR_Params(1));
342 writew(data, devpriv->io_addr + DPR_Params(2));
344 dt3k_send_cmd(dev, CMD_WRITESINGLE);
347 static int debug_n_ints = 0;
349 /* FIXME! Assumes shared interrupt is for this card. */
350 /* What's this debug_n_ints stuff? Obviously needs some work... */
351 static irqreturn_t dt3k_interrupt(int irq, void *d)
353 struct comedi_device *dev = d;
354 struct comedi_subdevice *s;
357 if (!dev->attached) {
361 s = dev->subdevices + 0;
362 status = readw(devpriv->io_addr + DPR_Intr_Flag);
364 debug_intr_flags(status);
367 if (status & DT3000_ADFULL) {
368 dt3k_ai_empty_fifo(dev, s);
369 s->async->events |= COMEDI_CB_BLOCK;
372 if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) {
373 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
377 if (debug_n_ints >= 10) {
378 dt3k_ai_cancel(dev, s);
379 s->async->events |= COMEDI_CB_EOA;
382 comedi_event(dev, s);
387 static char *intr_flags[] = {
388 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
389 "DaSwError", "DaHwError", "CtDone", "CmDone",
391 static void debug_intr_flags(unsigned int flags)
394 printk("dt3k: intr_flags:");
395 for (i = 0; i < 8; i++) {
396 if (flags & (1 << i)) {
397 printk(" %s", intr_flags[i]);
404 static void dt3k_ai_empty_fifo(struct comedi_device *dev, struct comedi_subdevice *s)
412 front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
413 count = front - devpriv->ai_front;
415 count += AI_FIFO_DEPTH;
417 printk("reading %d samples\n", count);
419 rear = devpriv->ai_rear;
421 for (i = 0; i < count; i++) {
422 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
423 comedi_buf_put(s->async, data);
425 if (rear >= AI_FIFO_DEPTH)
429 devpriv->ai_rear = rear;
430 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
433 static int dt3k_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
434 struct comedi_cmd *cmd)
439 /* step 1: make sure trigger sources are trivially valid */
441 tmp = cmd->start_src;
442 cmd->start_src &= TRIG_NOW;
443 if (!cmd->start_src || tmp != cmd->start_src)
446 tmp = cmd->scan_begin_src;
447 cmd->scan_begin_src &= TRIG_TIMER;
448 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
451 tmp = cmd->convert_src;
452 cmd->convert_src &= TRIG_TIMER;
453 if (!cmd->convert_src || tmp != cmd->convert_src)
456 tmp = cmd->scan_end_src;
457 cmd->scan_end_src &= TRIG_COUNT;
458 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
462 cmd->stop_src &= TRIG_COUNT;
463 if (!cmd->stop_src || tmp != cmd->stop_src)
469 /* step 2: make sure trigger sources are unique and mutually compatible */
474 /* step 3: make sure arguments are trivially compatible */
476 if (cmd->start_arg != 0) {
481 if (cmd->scan_begin_src == TRIG_TIMER) {
482 if (cmd->scan_begin_arg < this_board->ai_speed) {
483 cmd->scan_begin_arg = this_board->ai_speed;
486 if (cmd->scan_begin_arg > 100 * 16 * 65535) {
487 cmd->scan_begin_arg = 100 * 16 * 65535;
493 if (cmd->convert_src == TRIG_TIMER) {
494 if (cmd->convert_arg < this_board->ai_speed) {
495 cmd->convert_arg = this_board->ai_speed;
498 if (cmd->convert_arg > 50 * 16 * 65535) {
499 cmd->convert_arg = 50 * 16 * 65535;
506 if (cmd->scan_end_arg != cmd->chanlist_len) {
507 cmd->scan_end_arg = cmd->chanlist_len;
510 if (cmd->stop_src == TRIG_COUNT) {
511 if (cmd->stop_arg > 0x00ffffff) {
512 cmd->stop_arg = 0x00ffffff;
517 if (cmd->stop_arg != 0) {
526 /* step 4: fix up any arguments */
528 if (cmd->scan_begin_src == TRIG_TIMER) {
529 tmp = cmd->scan_begin_arg;
530 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
531 cmd->flags & TRIG_ROUND_MASK);
532 if (tmp != cmd->scan_begin_arg)
537 if (cmd->convert_src == TRIG_TIMER) {
538 tmp = cmd->convert_arg;
539 dt3k_ns_to_timer(50, &cmd->convert_arg,
540 cmd->flags & TRIG_ROUND_MASK);
541 if (tmp != cmd->convert_arg)
543 if (cmd->scan_begin_src == TRIG_TIMER &&
544 cmd->scan_begin_arg <
545 cmd->convert_arg * cmd->scan_end_arg) {
546 cmd->scan_begin_arg =
547 cmd->convert_arg * cmd->scan_end_arg;
560 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
561 unsigned int round_mode)
563 int divider, base, prescale;
565 /* This function needs improvment */
566 /* Don't know if divider==0 works. */
568 for (prescale = 0; prescale < 16; prescale++) {
569 base = timer_base * (prescale + 1);
570 switch (round_mode) {
571 case TRIG_ROUND_NEAREST:
573 divider = (*nanosec + base / 2) / base;
575 case TRIG_ROUND_DOWN:
576 divider = (*nanosec) / base;
579 divider = (*nanosec) / base;
582 if (divider < 65536) {
583 *nanosec = divider * base;
584 return (prescale << 16) | (divider);
589 base = timer_base * (1 << prescale);
591 *nanosec = divider * base;
592 return (prescale << 16) | (divider);
595 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
597 struct comedi_cmd *cmd = &s->async->cmd;
599 unsigned int chan, range, aref;
600 unsigned int divider;
601 unsigned int tscandiv;
605 printk("dt3k_ai_cmd:\n");
606 for (i = 0; i < cmd->chanlist_len; i++) {
607 chan = CR_CHAN(cmd->chanlist[i]);
608 range = CR_RANGE(cmd->chanlist[i]);
610 writew((range << 6) | chan,
611 devpriv->io_addr + DPR_ADC_buffer + i);
613 aref = CR_AREF(cmd->chanlist[0]);
615 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
616 printk("param[0]=0x%04x\n", cmd->scan_end_arg);
618 if (cmd->convert_src == TRIG_TIMER) {
619 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
620 cmd->flags & TRIG_ROUND_MASK);
621 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
622 printk("param[1]=0x%04x\n", divider >> 16);
623 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
624 printk("param[2]=0x%04x\n", divider & 0xffff);
629 if (cmd->scan_begin_src == TRIG_TIMER) {
630 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
631 cmd->flags & TRIG_ROUND_MASK);
632 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
633 printk("param[3]=0x%04x\n", tscandiv >> 16);
634 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
635 printk("param[4]=0x%04x\n", tscandiv & 0xffff);
640 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
641 writew(mode, devpriv->io_addr + DPR_Params(5));
642 printk("param[5]=0x%04x\n", mode);
643 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
644 printk("param[6]=0x%04x\n", aref == AREF_DIFF);
646 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
647 printk("param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
649 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
650 ret = dt3k_send_cmd(dev, CMD_CONFIG);
652 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
653 devpriv->io_addr + DPR_Int_Mask);
657 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
658 ret = dt3k_send_cmd(dev, CMD_START);
663 static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
667 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
668 ret = dt3k_send_cmd(dev, CMD_STOP);
670 writew(0, devpriv->io_addr + DPR_Int_Mask);
675 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
676 struct comedi_insn *insn, unsigned int *data)
679 unsigned int chan, gain, aref;
681 chan = CR_CHAN(insn->chanspec);
682 gain = CR_RANGE(insn->chanspec);
683 /* XXX docs don't explain how to select aref */
684 aref = CR_AREF(insn->chanspec);
686 for (i = 0; i < insn->n; i++) {
687 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
693 static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
694 struct comedi_insn *insn, unsigned int *data)
699 chan = CR_CHAN(insn->chanspec);
700 for (i = 0; i < insn->n; i++) {
701 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
702 devpriv->ao_readback[chan] = data[i];
708 static int dt3k_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
709 struct comedi_insn *insn, unsigned int *data)
714 chan = CR_CHAN(insn->chanspec);
715 for (i = 0; i < insn->n; i++) {
716 data[i] = devpriv->ao_readback[chan];
722 static void dt3k_dio_config(struct comedi_device *dev, int bits)
725 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
727 writew(bits, devpriv->io_addr + DPR_Params(0));
730 writew(0, devpriv->io_addr + DPR_Params(1));
731 writew(0, devpriv->io_addr + DPR_Params(2));
734 dt3k_send_cmd(dev, CMD_CONFIG);
737 static int dt3k_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
738 struct comedi_insn *insn, unsigned int *data)
742 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
745 case INSN_CONFIG_DIO_OUTPUT:
748 case INSN_CONFIG_DIO_INPUT:
751 case INSN_CONFIG_DIO_QUERY:
753 (s->io_bits & (1 << CR_CHAN(insn->
754 chanspec))) ? COMEDI_OUTPUT :
762 mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
763 dt3k_dio_config(dev, mask);
768 static int dt3k_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
769 struct comedi_insn *insn, unsigned int *data)
775 s->state &= ~data[0];
776 s->state |= data[1] & data[0];
777 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
779 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
784 static int dt3k_mem_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
785 struct comedi_insn *insn, unsigned int *data)
787 unsigned int addr = CR_CHAN(insn->chanspec);
790 for (i = 0; i < insn->n; i++) {
791 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
792 writew(addr, devpriv->io_addr + DPR_Params(0));
793 writew(1, devpriv->io_addr + DPR_Params(1));
795 dt3k_send_cmd(dev, CMD_READCODE);
797 data[i] = readw(devpriv->io_addr + DPR_Params(2));
803 static int dt_pci_probe(struct comedi_device *dev, int bus, int slot);
805 static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
807 struct comedi_subdevice *s;
812 bus = it->options[0];
813 slot = it->options[1];
815 ret = alloc_private(dev, sizeof(struct dt3k_private));
819 ret = dt_pci_probe(dev, bus, slot);
823 printk(" no DT board found\n");
827 dev->board_name = this_board->name;
829 if (request_irq(devpriv->pci_dev->irq, dt3k_interrupt, IRQF_SHARED,
831 printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq);
834 dev->irq = devpriv->pci_dev->irq;
836 ret = alloc_subdevices(dev, 4);
841 dev->read_subdev = s;
844 s->type = COMEDI_SUBD_AI;
845 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
846 s->n_chan = this_board->adchan;
847 s->insn_read = dt3k_ai_insn;
848 s->maxdata = (1 << this_board->adbits) - 1;
849 s->len_chanlist = 512;
850 s->range_table = &range_dt3000_ai; /* XXX */
851 s->do_cmd = dt3k_ai_cmd;
852 s->do_cmdtest = dt3k_ai_cmdtest;
853 s->cancel = dt3k_ai_cancel;
857 s->type = COMEDI_SUBD_AO;
858 s->subdev_flags = SDF_WRITABLE;
860 s->insn_read = dt3k_ao_insn_read;
861 s->insn_write = dt3k_ao_insn;
862 s->maxdata = (1 << this_board->dabits) - 1;
864 s->range_table = &range_bipolar10;
868 s->type = COMEDI_SUBD_DIO;
869 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
871 s->insn_config = dt3k_dio_insn_config;
872 s->insn_bits = dt3k_dio_insn_bits;
875 s->range_table = &range_digital;
879 s->type = COMEDI_SUBD_MEMORY;
880 s->subdev_flags = SDF_READABLE;
882 s->insn_read = dt3k_mem_insn_read;
885 s->range_table = &range_unknown;
890 s->type = COMEDI_SUBD_PROC;
896 static int dt3000_detach(struct comedi_device *dev)
899 free_irq(dev->irq, dev);
902 if (devpriv->pci_dev) {
903 if (devpriv->phys_addr) {
904 comedi_pci_disable(devpriv->pci_dev);
906 pci_dev_put(devpriv->pci_dev);
908 if (devpriv->io_addr)
909 iounmap(devpriv->io_addr);
916 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
917 static int setup_pci(struct comedi_device *dev);
919 static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
923 struct pci_dev *pcidev;
926 while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
927 if ((bus == 0 && slot == 0) ||
928 (pcidev->bus->number == bus &&
929 PCI_SLOT(pcidev->devfn) == slot)) {
933 devpriv->pci_dev = pcidev;
936 dev->board_ptr = dt3k_boardtypes + board;
938 if (!devpriv->pci_dev)
941 ret = setup_pci(dev);
948 static int setup_pci(struct comedi_device *dev)
950 resource_size_t addr;
953 ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
957 addr = pci_resource_start(devpriv->pci_dev, 0);
958 devpriv->phys_addr = addr;
959 devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
960 if (!devpriv->io_addr)
963 printk("0x%08llx mapped to %p, ",
964 (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
970 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
974 for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
976 from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
977 for (i = 0; i < n_dt3k_boards; i++) {
978 if (from->device == dt3k_boardtypes[i].device_id) {
983 printk("unknown Data Translation PCI device found with device_id=0x%04x\n", from->device);