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 "../comedidev.h"
63 #include <linux/delay.h>
65 #include "comedi_pci.h"
67 #define PCI_VENDOR_ID_DT 0x1116
69 static const struct comedi_lrange range_dt3000_ai = { 4, {
76 static const struct comedi_lrange range_dt3000_ai_pgl = { 4, {
84 struct dt3k_boardtype {
87 unsigned int device_id;
91 const struct comedi_lrange *adrange;
97 static const struct dt3k_boardtype dt3k_boardtypes[] = {
102 .adrange = &range_dt3000_ai,
107 {.name = "dt3001-pgl",
111 .adrange = &range_dt3000_ai_pgl,
120 .adrange = &range_dt3000_ai,
129 .adrange = &range_dt3000_ai,
134 {.name = "dt3003-pgl",
138 .adrange = &range_dt3000_ai_pgl,
147 .adrange = &range_dt3000_ai,
152 {.name = "dt3005", /* a.k.a. 3004-200 */
156 .adrange = &range_dt3000_ai,
163 #define n_dt3k_boards sizeof(dt3k_boardtypes)/sizeof(struct dt3k_boardtype)
164 #define this_board ((const struct dt3k_boardtype *)dev->board_ptr)
166 static DEFINE_PCI_DEVICE_TABLE(dt3k_pci_table) = {
167 {PCI_VENDOR_ID_DT, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
168 {PCI_VENDOR_ID_DT, 0x0027, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
169 {PCI_VENDOR_ID_DT, 0x0023, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
170 {PCI_VENDOR_ID_DT, 0x0024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
171 {PCI_VENDOR_ID_DT, 0x0028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
172 {PCI_VENDOR_ID_DT, 0x0025, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
173 {PCI_VENDOR_ID_DT, 0x0026, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
177 MODULE_DEVICE_TABLE(pci, dt3k_pci_table);
179 #define DT3000_SIZE (4*0x1000)
181 /* dual-ported RAM location definitions */
183 #define DPR_DAC_buffer (4*0x000)
184 #define DPR_ADC_buffer (4*0x800)
185 #define DPR_Command (4*0xfd3)
186 #define DPR_SubSys (4*0xfd3)
187 #define DPR_Encode (4*0xfd4)
188 #define DPR_Params(a) (4*(0xfd5+(a)))
189 #define DPR_Tick_Reg_Lo (4*0xff5)
190 #define DPR_Tick_Reg_Hi (4*0xff6)
191 #define DPR_DA_Buf_Front (4*0xff7)
192 #define DPR_DA_Buf_Rear (4*0xff8)
193 #define DPR_AD_Buf_Front (4*0xff9)
194 #define DPR_AD_Buf_Rear (4*0xffa)
195 #define DPR_Int_Mask (4*0xffb)
196 #define DPR_Intr_Flag (4*0xffc)
197 #define DPR_Response_Mbx (4*0xffe)
198 #define DPR_Command_Mbx (4*0xfff)
200 #define AI_FIFO_DEPTH 2003
201 #define AO_FIFO_DEPTH 2048
205 #define CMD_GETBRDINFO 0
207 #define CMD_GETCONFIG 2
210 #define CMD_READSINGLE 5
211 #define CMD_WRITESINGLE 6
212 #define CMD_CALCCLOCK 7
213 #define CMD_READEVENTS 8
214 #define CMD_WRITECTCTRL 16
215 #define CMD_READCTCTRL 17
216 #define CMD_WRITECT 18
217 #define CMD_READCT 19
218 #define CMD_WRITEDATA 32
219 #define CMD_READDATA 33
220 #define CMD_WRITEIO 34
221 #define CMD_READIO 35
222 #define CMD_WRITECODE 36
223 #define CMD_READCODE 37
224 #define CMD_EXECUTE 38
234 /* interrupt flags */
235 #define DT3000_CMDONE 0x80
236 #define DT3000_CTDONE 0x40
237 #define DT3000_DAHWERR 0x20
238 #define DT3000_DASWERR 0x10
239 #define DT3000_DAEMPTY 0x08
240 #define DT3000_ADHWERR 0x04
241 #define DT3000_ADSWERR 0x02
242 #define DT3000_ADFULL 0x01
244 #define DT3000_COMPLETION_MASK 0xff00
245 #define DT3000_COMMAND_MASK 0x00ff
246 #define DT3000_NOTPROCESSED 0x0000
247 #define DT3000_NOERROR 0x5500
248 #define DT3000_ERROR 0xaa00
249 #define DT3000_NOTSUPPORTED 0xff00
251 #define DT3000_EXTERNAL_CLOCK 1
252 #define DT3000_RISING_EDGE 2
254 #define TMODE_MASK 0x1c
256 #define DT3000_AD_TRIG_INTERNAL (0<<2)
257 #define DT3000_AD_TRIG_EXTERNAL (1<<2)
258 #define DT3000_AD_RETRIG_INTERNAL (2<<2)
259 #define DT3000_AD_RETRIG_EXTERNAL (3<<2)
260 #define DT3000_AD_EXTRETRIG (4<<2)
262 #define DT3000_CHANNEL_MODE_SE 0
263 #define DT3000_CHANNEL_MODE_DI 1
265 struct dt3k_private {
267 struct pci_dev *pci_dev;
268 resource_size_t phys_addr;
271 unsigned int ao_readback[2];
272 unsigned int ai_front;
273 unsigned int ai_rear;
276 #define devpriv ((struct dt3k_private *)dev->private)
278 static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it);
279 static int dt3000_detach(struct comedi_device *dev);
280 static struct comedi_driver driver_dt3000 = {
281 .driver_name = "dt3000",
282 .module = THIS_MODULE,
283 .attach = dt3000_attach,
284 .detach = dt3000_detach,
287 COMEDI_PCI_INITCLEANUP(driver_dt3000, dt3k_pci_table);
289 static void dt3k_ai_empty_fifo(struct comedi_device *dev, struct comedi_subdevice *s);
290 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
291 unsigned int round_mode);
292 static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
294 static void debug_intr_flags(unsigned int flags);
299 static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
302 unsigned int status = 0;
304 writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
306 for (i = 0; i < TIMEOUT; i++) {
307 status = readw(devpriv->io_addr + DPR_Command_Mbx);
308 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
312 if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR) {
316 printk("dt3k_send_cmd() timeout/error status=0x%04x\n", status);
321 static unsigned int dt3k_readsingle(struct comedi_device *dev, unsigned int subsys,
322 unsigned int chan, unsigned int gain)
324 writew(subsys, devpriv->io_addr + DPR_SubSys);
326 writew(chan, devpriv->io_addr + DPR_Params(0));
327 writew(gain, devpriv->io_addr + DPR_Params(1));
329 dt3k_send_cmd(dev, CMD_READSINGLE);
331 return readw(devpriv->io_addr + DPR_Params(2));
334 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
335 unsigned int chan, unsigned int data)
337 writew(subsys, devpriv->io_addr + DPR_SubSys);
339 writew(chan, devpriv->io_addr + DPR_Params(0));
340 writew(0, devpriv->io_addr + DPR_Params(1));
341 writew(data, devpriv->io_addr + DPR_Params(2));
343 dt3k_send_cmd(dev, CMD_WRITESINGLE);
346 static int debug_n_ints = 0;
348 /* FIXME! Assumes shared interrupt is for this card. */
349 /* What's this debug_n_ints stuff? Obviously needs some work... */
350 static irqreturn_t dt3k_interrupt(int irq, void *d)
352 struct comedi_device *dev = d;
353 struct comedi_subdevice *s;
356 if (!dev->attached) {
360 s = dev->subdevices + 0;
361 status = readw(devpriv->io_addr + DPR_Intr_Flag);
363 debug_intr_flags(status);
366 if (status & DT3000_ADFULL) {
367 dt3k_ai_empty_fifo(dev, s);
368 s->async->events |= COMEDI_CB_BLOCK;
371 if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) {
372 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
376 if (debug_n_ints >= 10) {
377 dt3k_ai_cancel(dev, s);
378 s->async->events |= COMEDI_CB_EOA;
381 comedi_event(dev, s);
386 static char *intr_flags[] = {
387 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
388 "DaSwError", "DaHwError", "CtDone", "CmDone",
390 static void debug_intr_flags(unsigned int flags)
393 printk("dt3k: intr_flags:");
394 for (i = 0; i < 8; i++) {
395 if (flags & (1 << i)) {
396 printk(" %s", intr_flags[i]);
403 static void dt3k_ai_empty_fifo(struct comedi_device *dev, struct comedi_subdevice *s)
411 front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
412 count = front - devpriv->ai_front;
414 count += AI_FIFO_DEPTH;
416 printk("reading %d samples\n", count);
418 rear = devpriv->ai_rear;
420 for (i = 0; i < count; i++) {
421 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
422 comedi_buf_put(s->async, data);
424 if (rear >= AI_FIFO_DEPTH)
428 devpriv->ai_rear = rear;
429 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
432 static int dt3k_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
433 struct comedi_cmd *cmd)
438 /* step 1: make sure trigger sources are trivially valid */
440 tmp = cmd->start_src;
441 cmd->start_src &= TRIG_NOW;
442 if (!cmd->start_src || tmp != cmd->start_src)
445 tmp = cmd->scan_begin_src;
446 cmd->scan_begin_src &= TRIG_TIMER;
447 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
450 tmp = cmd->convert_src;
451 cmd->convert_src &= TRIG_TIMER;
452 if (!cmd->convert_src || tmp != cmd->convert_src)
455 tmp = cmd->scan_end_src;
456 cmd->scan_end_src &= TRIG_COUNT;
457 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
461 cmd->stop_src &= TRIG_COUNT;
462 if (!cmd->stop_src || tmp != cmd->stop_src)
468 /* step 2: make sure trigger sources are unique and mutually compatible */
473 /* step 3: make sure arguments are trivially compatible */
475 if (cmd->start_arg != 0) {
480 if (cmd->scan_begin_src == TRIG_TIMER) {
481 if (cmd->scan_begin_arg < this_board->ai_speed) {
482 cmd->scan_begin_arg = this_board->ai_speed;
485 if (cmd->scan_begin_arg > 100 * 16 * 65535) {
486 cmd->scan_begin_arg = 100 * 16 * 65535;
492 if (cmd->convert_src == TRIG_TIMER) {
493 if (cmd->convert_arg < this_board->ai_speed) {
494 cmd->convert_arg = this_board->ai_speed;
497 if (cmd->convert_arg > 50 * 16 * 65535) {
498 cmd->convert_arg = 50 * 16 * 65535;
505 if (cmd->scan_end_arg != cmd->chanlist_len) {
506 cmd->scan_end_arg = cmd->chanlist_len;
509 if (cmd->stop_src == TRIG_COUNT) {
510 if (cmd->stop_arg > 0x00ffffff) {
511 cmd->stop_arg = 0x00ffffff;
516 if (cmd->stop_arg != 0) {
525 /* step 4: fix up any arguments */
527 if (cmd->scan_begin_src == TRIG_TIMER) {
528 tmp = cmd->scan_begin_arg;
529 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
530 cmd->flags & TRIG_ROUND_MASK);
531 if (tmp != cmd->scan_begin_arg)
536 if (cmd->convert_src == TRIG_TIMER) {
537 tmp = cmd->convert_arg;
538 dt3k_ns_to_timer(50, &cmd->convert_arg,
539 cmd->flags & TRIG_ROUND_MASK);
540 if (tmp != cmd->convert_arg)
542 if (cmd->scan_begin_src == TRIG_TIMER &&
543 cmd->scan_begin_arg <
544 cmd->convert_arg * cmd->scan_end_arg) {
545 cmd->scan_begin_arg =
546 cmd->convert_arg * cmd->scan_end_arg;
559 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
560 unsigned int round_mode)
562 int divider, base, prescale;
564 /* This function needs improvment */
565 /* Don't know if divider==0 works. */
567 for (prescale = 0; prescale < 16; prescale++) {
568 base = timer_base * (prescale + 1);
569 switch (round_mode) {
570 case TRIG_ROUND_NEAREST:
572 divider = (*nanosec + base / 2) / base;
574 case TRIG_ROUND_DOWN:
575 divider = (*nanosec) / base;
578 divider = (*nanosec) / base;
581 if (divider < 65536) {
582 *nanosec = divider * base;
583 return (prescale << 16) | (divider);
588 base = timer_base * (1 << prescale);
590 *nanosec = divider * base;
591 return (prescale << 16) | (divider);
594 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
596 struct comedi_cmd *cmd = &s->async->cmd;
598 unsigned int chan, range, aref;
599 unsigned int divider;
600 unsigned int tscandiv;
604 printk("dt3k_ai_cmd:\n");
605 for (i = 0; i < cmd->chanlist_len; i++) {
606 chan = CR_CHAN(cmd->chanlist[i]);
607 range = CR_RANGE(cmd->chanlist[i]);
609 writew((range << 6) | chan,
610 devpriv->io_addr + DPR_ADC_buffer + i);
612 aref = CR_AREF(cmd->chanlist[0]);
614 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
615 printk("param[0]=0x%04x\n", cmd->scan_end_arg);
617 if (cmd->convert_src == TRIG_TIMER) {
618 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
619 cmd->flags & TRIG_ROUND_MASK);
620 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
621 printk("param[1]=0x%04x\n", divider >> 16);
622 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
623 printk("param[2]=0x%04x\n", divider & 0xffff);
628 if (cmd->scan_begin_src == TRIG_TIMER) {
629 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
630 cmd->flags & TRIG_ROUND_MASK);
631 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
632 printk("param[3]=0x%04x\n", tscandiv >> 16);
633 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
634 printk("param[4]=0x%04x\n", tscandiv & 0xffff);
639 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
640 writew(mode, devpriv->io_addr + DPR_Params(5));
641 printk("param[5]=0x%04x\n", mode);
642 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
643 printk("param[6]=0x%04x\n", aref == AREF_DIFF);
645 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
646 printk("param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
648 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
649 ret = dt3k_send_cmd(dev, CMD_CONFIG);
651 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
652 devpriv->io_addr + DPR_Int_Mask);
656 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
657 ret = dt3k_send_cmd(dev, CMD_START);
662 static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
666 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
667 ret = dt3k_send_cmd(dev, CMD_STOP);
669 writew(0, devpriv->io_addr + DPR_Int_Mask);
674 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
675 struct comedi_insn *insn, unsigned int *data)
678 unsigned int chan, gain, aref;
680 chan = CR_CHAN(insn->chanspec);
681 gain = CR_RANGE(insn->chanspec);
682 /* XXX docs don't explain how to select aref */
683 aref = CR_AREF(insn->chanspec);
685 for (i = 0; i < insn->n; i++) {
686 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
692 static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
693 struct comedi_insn *insn, unsigned int *data)
698 chan = CR_CHAN(insn->chanspec);
699 for (i = 0; i < insn->n; i++) {
700 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
701 devpriv->ao_readback[chan] = data[i];
707 static int dt3k_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
708 struct comedi_insn *insn, unsigned int *data)
713 chan = CR_CHAN(insn->chanspec);
714 for (i = 0; i < insn->n; i++) {
715 data[i] = devpriv->ao_readback[chan];
721 static void dt3k_dio_config(struct comedi_device *dev, int bits)
724 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
726 writew(bits, devpriv->io_addr + DPR_Params(0));
729 writew(0, devpriv->io_addr + DPR_Params(1));
730 writew(0, devpriv->io_addr + DPR_Params(2));
733 dt3k_send_cmd(dev, CMD_CONFIG);
736 static int dt3k_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
737 struct comedi_insn *insn, unsigned int *data)
741 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
744 case INSN_CONFIG_DIO_OUTPUT:
747 case INSN_CONFIG_DIO_INPUT:
750 case INSN_CONFIG_DIO_QUERY:
752 (s->io_bits & (1 << CR_CHAN(insn->
753 chanspec))) ? COMEDI_OUTPUT :
761 mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
762 dt3k_dio_config(dev, mask);
767 static int dt3k_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
768 struct comedi_insn *insn, unsigned int *data)
774 s->state &= ~data[0];
775 s->state |= data[1] & data[0];
776 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
778 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
783 static int dt3k_mem_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
784 struct comedi_insn *insn, unsigned int *data)
786 unsigned int addr = CR_CHAN(insn->chanspec);
789 for (i = 0; i < insn->n; i++) {
790 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
791 writew(addr, devpriv->io_addr + DPR_Params(0));
792 writew(1, devpriv->io_addr + DPR_Params(1));
794 dt3k_send_cmd(dev, CMD_READCODE);
796 data[i] = readw(devpriv->io_addr + DPR_Params(2));
802 static int dt_pci_probe(struct comedi_device *dev, int bus, int slot);
804 static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
806 struct comedi_subdevice *s;
811 bus = it->options[0];
812 slot = it->options[1];
814 ret = alloc_private(dev, sizeof(struct dt3k_private));
818 ret = dt_pci_probe(dev, bus, slot);
822 printk(" no DT board found\n");
826 dev->board_name = this_board->name;
828 if (comedi_request_irq(devpriv->pci_dev->irq, dt3k_interrupt,
829 IRQF_SHARED, "dt3000", dev)) {
830 printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq);
833 dev->irq = devpriv->pci_dev->irq;
835 ret = alloc_subdevices(dev, 4);
840 dev->read_subdev = s;
843 s->type = COMEDI_SUBD_AI;
844 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
845 s->n_chan = this_board->adchan;
846 s->insn_read = dt3k_ai_insn;
847 s->maxdata = (1 << this_board->adbits) - 1;
848 s->len_chanlist = 512;
849 s->range_table = &range_dt3000_ai; /* XXX */
850 s->do_cmd = dt3k_ai_cmd;
851 s->do_cmdtest = dt3k_ai_cmdtest;
852 s->cancel = dt3k_ai_cancel;
856 s->type = COMEDI_SUBD_AO;
857 s->subdev_flags = SDF_WRITABLE;
859 s->insn_read = dt3k_ao_insn_read;
860 s->insn_write = dt3k_ao_insn;
861 s->maxdata = (1 << this_board->dabits) - 1;
863 s->range_table = &range_bipolar10;
867 s->type = COMEDI_SUBD_DIO;
868 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
870 s->insn_config = dt3k_dio_insn_config;
871 s->insn_bits = dt3k_dio_insn_bits;
874 s->range_table = &range_digital;
878 s->type = COMEDI_SUBD_MEMORY;
879 s->subdev_flags = SDF_READABLE;
881 s->insn_read = dt3k_mem_insn_read;
884 s->range_table = &range_unknown;
889 s->type = COMEDI_SUBD_PROC;
895 static int dt3000_detach(struct comedi_device *dev)
898 comedi_free_irq(dev->irq, dev);
901 if (devpriv->pci_dev) {
902 if (devpriv->phys_addr) {
903 comedi_pci_disable(devpriv->pci_dev);
905 pci_dev_put(devpriv->pci_dev);
907 if (devpriv->io_addr)
908 iounmap(devpriv->io_addr);
915 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
916 static int setup_pci(struct comedi_device *dev);
918 static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
922 struct pci_dev *pcidev;
925 while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
926 if ((bus == 0 && slot == 0) ||
927 (pcidev->bus->number == bus &&
928 PCI_SLOT(pcidev->devfn) == slot)) {
932 devpriv->pci_dev = pcidev;
935 dev->board_ptr = dt3k_boardtypes + board;
937 if (!devpriv->pci_dev)
940 ret = setup_pci(dev);
947 static int setup_pci(struct comedi_device *dev)
949 resource_size_t addr;
952 ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
956 addr = pci_resource_start(devpriv->pci_dev, 0);
957 devpriv->phys_addr = addr;
958 devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
959 if (!devpriv->io_addr)
962 printk("0x%08llx mapped to %p, ",
963 (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
969 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
973 for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
975 from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
976 for (i = 0; i < n_dt3k_boards; i++) {
977 if (from->device == dt3k_boardtypes[i].device_id) {
982 printk("unknown Data Translation PCI device found with device_id=0x%04x\n", from->device);