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,
111 adrange: &range_dt3000_ai_pgl,
120 adrange: &range_dt3000_ai,
129 adrange: &range_dt3000_ai,
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
266 struct pci_dev *pci_dev;
267 resource_size_t phys_addr;
270 unsigned int ao_readback[2];
271 unsigned int ai_front;
272 unsigned int ai_rear;
274 #define devpriv ((dt3k_private *)dev->private)
276 static int dt3000_attach(struct comedi_device * dev, struct comedi_devconfig * it);
277 static int dt3000_detach(struct comedi_device * dev);
278 static struct comedi_driver driver_dt3000 = {
279 driver_name:"dt3000",
281 attach:dt3000_attach,
282 detach:dt3000_detach,
285 COMEDI_PCI_INITCLEANUP(driver_dt3000, dt3k_pci_table);
287 static void dt3k_ai_empty_fifo(struct comedi_device * dev, struct comedi_subdevice * s);
288 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
289 unsigned int round_mode);
290 static int dt3k_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s);
292 static void debug_intr_flags(unsigned int flags);
297 static int dt3k_send_cmd(struct comedi_device * dev, unsigned int cmd)
300 unsigned int status = 0;
302 writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
304 for (i = 0; i < TIMEOUT; i++) {
305 status = readw(devpriv->io_addr + DPR_Command_Mbx);
306 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
310 if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR) {
314 printk("dt3k_send_cmd() timeout/error status=0x%04x\n", status);
319 static unsigned int dt3k_readsingle(struct comedi_device * dev, unsigned int subsys,
320 unsigned int chan, unsigned int gain)
322 writew(subsys, devpriv->io_addr + DPR_SubSys);
324 writew(chan, devpriv->io_addr + DPR_Params(0));
325 writew(gain, devpriv->io_addr + DPR_Params(1));
327 dt3k_send_cmd(dev, CMD_READSINGLE);
329 return readw(devpriv->io_addr + DPR_Params(2));
332 static void dt3k_writesingle(struct comedi_device * dev, unsigned int subsys,
333 unsigned int chan, unsigned int data)
335 writew(subsys, devpriv->io_addr + DPR_SubSys);
337 writew(chan, devpriv->io_addr + DPR_Params(0));
338 writew(0, devpriv->io_addr + DPR_Params(1));
339 writew(data, devpriv->io_addr + DPR_Params(2));
341 dt3k_send_cmd(dev, CMD_WRITESINGLE);
344 static int debug_n_ints = 0;
346 // FIXME! Assumes shared interrupt is for this card.
347 // What's this debug_n_ints stuff? Obviously needs some work...
348 static irqreturn_t dt3k_interrupt(int irq, void *d PT_REGS_ARG)
350 struct comedi_device *dev = d;
351 struct comedi_subdevice *s;
354 if (!dev->attached) {
358 s = dev->subdevices + 0;
359 status = readw(devpriv->io_addr + DPR_Intr_Flag);
361 debug_intr_flags(status);
364 if (status & DT3000_ADFULL) {
365 dt3k_ai_empty_fifo(dev, s);
366 s->async->events |= COMEDI_CB_BLOCK;
369 if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) {
370 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
374 if (debug_n_ints >= 10) {
375 dt3k_ai_cancel(dev, s);
376 s->async->events |= COMEDI_CB_EOA;
379 comedi_event(dev, s);
384 static char *intr_flags[] = {
385 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
386 "DaSwError", "DaHwError", "CtDone", "CmDone",
388 static void debug_intr_flags(unsigned int flags)
391 printk("dt3k: intr_flags:");
392 for (i = 0; i < 8; i++) {
393 if (flags & (1 << i)) {
394 printk(" %s", intr_flags[i]);
401 static void dt3k_ai_empty_fifo(struct comedi_device * dev, struct comedi_subdevice * s)
409 front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
410 count = front - devpriv->ai_front;
412 count += AI_FIFO_DEPTH;
414 printk("reading %d samples\n", count);
416 rear = devpriv->ai_rear;
418 for (i = 0; i < count; i++) {
419 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
420 comedi_buf_put(s->async, data);
422 if (rear >= AI_FIFO_DEPTH)
426 devpriv->ai_rear = rear;
427 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
430 static int dt3k_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s,
431 struct comedi_cmd * cmd)
436 /* step 1: make sure trigger sources are trivially valid */
438 tmp = cmd->start_src;
439 cmd->start_src &= TRIG_NOW;
440 if (!cmd->start_src || tmp != cmd->start_src)
443 tmp = cmd->scan_begin_src;
444 cmd->scan_begin_src &= TRIG_TIMER;
445 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
448 tmp = cmd->convert_src;
449 cmd->convert_src &= TRIG_TIMER;
450 if (!cmd->convert_src || tmp != cmd->convert_src)
453 tmp = cmd->scan_end_src;
454 cmd->scan_end_src &= TRIG_COUNT;
455 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
459 cmd->stop_src &= TRIG_COUNT;
460 if (!cmd->stop_src || tmp != cmd->stop_src)
466 /* step 2: make sure trigger sources are unique and mutually compatible */
471 /* step 3: make sure arguments are trivially compatible */
473 if (cmd->start_arg != 0) {
478 if (cmd->scan_begin_src == TRIG_TIMER) {
479 if (cmd->scan_begin_arg < this_board->ai_speed) {
480 cmd->scan_begin_arg = this_board->ai_speed;
483 if (cmd->scan_begin_arg > 100 * 16 * 65535) {
484 cmd->scan_begin_arg = 100 * 16 * 65535;
490 if (cmd->convert_src == TRIG_TIMER) {
491 if (cmd->convert_arg < this_board->ai_speed) {
492 cmd->convert_arg = this_board->ai_speed;
495 if (cmd->convert_arg > 50 * 16 * 65535) {
496 cmd->convert_arg = 50 * 16 * 65535;
503 if (cmd->scan_end_arg != cmd->chanlist_len) {
504 cmd->scan_end_arg = cmd->chanlist_len;
507 if (cmd->stop_src == TRIG_COUNT) {
508 if (cmd->stop_arg > 0x00ffffff) {
509 cmd->stop_arg = 0x00ffffff;
514 if (cmd->stop_arg != 0) {
523 /* step 4: fix up any arguments */
525 if (cmd->scan_begin_src == TRIG_TIMER) {
526 tmp = cmd->scan_begin_arg;
527 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
528 cmd->flags & TRIG_ROUND_MASK);
529 if (tmp != cmd->scan_begin_arg)
534 if (cmd->convert_src == TRIG_TIMER) {
535 tmp = cmd->convert_arg;
536 dt3k_ns_to_timer(50, &cmd->convert_arg,
537 cmd->flags & TRIG_ROUND_MASK);
538 if (tmp != cmd->convert_arg)
540 if (cmd->scan_begin_src == TRIG_TIMER &&
541 cmd->scan_begin_arg <
542 cmd->convert_arg * cmd->scan_end_arg) {
543 cmd->scan_begin_arg =
544 cmd->convert_arg * cmd->scan_end_arg;
557 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
558 unsigned int round_mode)
560 int divider, base, prescale;
562 /* This function needs improvment */
563 /* Don't know if divider==0 works. */
565 for (prescale = 0; prescale < 16; prescale++) {
566 base = timer_base * (prescale + 1);
567 switch (round_mode) {
568 case TRIG_ROUND_NEAREST:
570 divider = (*nanosec + base / 2) / base;
572 case TRIG_ROUND_DOWN:
573 divider = (*nanosec) / base;
576 divider = (*nanosec) / base;
579 if (divider < 65536) {
580 *nanosec = divider * base;
581 return (prescale << 16) | (divider);
586 base = timer_base * (1 << prescale);
588 *nanosec = divider * base;
589 return (prescale << 16) | (divider);
592 static int dt3k_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s)
594 struct comedi_cmd *cmd = &s->async->cmd;
596 unsigned int chan, range, aref;
597 unsigned int divider;
598 unsigned int tscandiv;
602 printk("dt3k_ai_cmd:\n");
603 for (i = 0; i < cmd->chanlist_len; i++) {
604 chan = CR_CHAN(cmd->chanlist[i]);
605 range = CR_RANGE(cmd->chanlist[i]);
607 writew((range << 6) | chan,
608 devpriv->io_addr + DPR_ADC_buffer + i);
610 aref = CR_AREF(cmd->chanlist[0]);
612 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
613 printk("param[0]=0x%04x\n", cmd->scan_end_arg);
615 if (cmd->convert_src == TRIG_TIMER) {
616 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
617 cmd->flags & TRIG_ROUND_MASK);
618 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
619 printk("param[1]=0x%04x\n", divider >> 16);
620 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
621 printk("param[2]=0x%04x\n", divider & 0xffff);
626 if (cmd->scan_begin_src == TRIG_TIMER) {
627 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
628 cmd->flags & TRIG_ROUND_MASK);
629 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
630 printk("param[3]=0x%04x\n", tscandiv >> 16);
631 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
632 printk("param[4]=0x%04x\n", tscandiv & 0xffff);
637 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
638 writew(mode, devpriv->io_addr + DPR_Params(5));
639 printk("param[5]=0x%04x\n", mode);
640 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
641 printk("param[6]=0x%04x\n", aref == AREF_DIFF);
643 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
644 printk("param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
646 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
647 ret = dt3k_send_cmd(dev, CMD_CONFIG);
649 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
650 devpriv->io_addr + DPR_Int_Mask);
654 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
655 ret = dt3k_send_cmd(dev, CMD_START);
660 static int dt3k_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s)
664 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
665 ret = dt3k_send_cmd(dev, CMD_STOP);
667 writew(0, devpriv->io_addr + DPR_Int_Mask);
672 static int dt3k_ai_insn(struct comedi_device * dev, struct comedi_subdevice * s,
673 struct comedi_insn * insn, unsigned int * data)
676 unsigned int chan, gain, aref;
678 chan = CR_CHAN(insn->chanspec);
679 gain = CR_RANGE(insn->chanspec);
680 /* XXX docs don't explain how to select aref */
681 aref = CR_AREF(insn->chanspec);
683 for (i = 0; i < insn->n; i++) {
684 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
690 static int dt3k_ao_insn(struct comedi_device * dev, struct comedi_subdevice * s,
691 struct comedi_insn * insn, unsigned int * data)
696 chan = CR_CHAN(insn->chanspec);
697 for (i = 0; i < insn->n; i++) {
698 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
699 devpriv->ao_readback[chan] = data[i];
705 static int dt3k_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
706 struct comedi_insn * insn, unsigned int * data)
711 chan = CR_CHAN(insn->chanspec);
712 for (i = 0; i < insn->n; i++) {
713 data[i] = devpriv->ao_readback[chan];
719 static void dt3k_dio_config(struct comedi_device * dev, int bits)
722 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
724 writew(bits, devpriv->io_addr + DPR_Params(0));
727 writew(0, devpriv->io_addr + DPR_Params(1));
728 writew(0, devpriv->io_addr + DPR_Params(2));
731 dt3k_send_cmd(dev, CMD_CONFIG);
734 static int dt3k_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
735 struct comedi_insn * insn, unsigned int * data)
739 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
742 case INSN_CONFIG_DIO_OUTPUT:
745 case INSN_CONFIG_DIO_INPUT:
748 case INSN_CONFIG_DIO_QUERY:
750 (s->io_bits & (1 << CR_CHAN(insn->
751 chanspec))) ? COMEDI_OUTPUT :
759 mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
760 dt3k_dio_config(dev, mask);
765 static int dt3k_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
766 struct comedi_insn * insn, unsigned int * data)
772 s->state &= ~data[0];
773 s->state |= data[1] & data[0];
774 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
776 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
781 static int dt3k_mem_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
782 struct comedi_insn * insn, unsigned int * data)
784 unsigned int addr = CR_CHAN(insn->chanspec);
787 for (i = 0; i < insn->n; i++) {
788 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
789 writew(addr, devpriv->io_addr + DPR_Params(0));
790 writew(1, devpriv->io_addr + DPR_Params(1));
792 dt3k_send_cmd(dev, CMD_READCODE);
794 data[i] = readw(devpriv->io_addr + DPR_Params(2));
800 static int dt_pci_probe(struct comedi_device * dev, int bus, int slot);
802 static int dt3000_attach(struct comedi_device * dev, struct comedi_devconfig * it)
804 struct comedi_subdevice *s;
809 bus = it->options[0];
810 slot = it->options[1];
812 if ((ret = alloc_private(dev, sizeof(dt3k_private))) < 0)
815 ret = dt_pci_probe(dev, bus, slot);
819 printk(" no DT board found\n");
823 dev->board_name = this_board->name;
825 if (comedi_request_irq(devpriv->pci_dev->irq, dt3k_interrupt,
826 IRQF_SHARED, "dt3000", dev)) {
827 printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq);
830 dev->irq = devpriv->pci_dev->irq;
832 if ((ret = alloc_subdevices(dev, 4)) < 0)
836 dev->read_subdev = s;
839 s->type = COMEDI_SUBD_AI;
840 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
841 s->n_chan = this_board->adchan;
842 s->insn_read = dt3k_ai_insn;
843 s->maxdata = (1 << this_board->adbits) - 1;
844 s->len_chanlist = 512;
845 s->range_table = &range_dt3000_ai; /* XXX */
846 s->do_cmd = dt3k_ai_cmd;
847 s->do_cmdtest = dt3k_ai_cmdtest;
848 s->cancel = dt3k_ai_cancel;
852 s->type = COMEDI_SUBD_AO;
853 s->subdev_flags = SDF_WRITABLE;
855 s->insn_read = dt3k_ao_insn_read;
856 s->insn_write = dt3k_ao_insn;
857 s->maxdata = (1 << this_board->dabits) - 1;
859 s->range_table = &range_bipolar10;
863 s->type = COMEDI_SUBD_DIO;
864 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
866 s->insn_config = dt3k_dio_insn_config;
867 s->insn_bits = dt3k_dio_insn_bits;
870 s->range_table = &range_digital;
874 s->type = COMEDI_SUBD_MEMORY;
875 s->subdev_flags = SDF_READABLE;
877 s->insn_read = dt3k_mem_insn_read;
880 s->range_table = &range_unknown;
885 s->type = COMEDI_SUBD_PROC;
891 static int dt3000_detach(struct comedi_device * dev)
894 comedi_free_irq(dev->irq, dev);
897 if (devpriv->pci_dev) {
898 if (devpriv->phys_addr) {
899 comedi_pci_disable(devpriv->pci_dev);
901 pci_dev_put(devpriv->pci_dev);
903 if (devpriv->io_addr)
904 iounmap(devpriv->io_addr);
911 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
912 static int setup_pci(struct comedi_device * dev);
914 static int dt_pci_probe(struct comedi_device * dev, int bus, int slot)
918 struct pci_dev *pcidev;
921 while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
922 if ((bus == 0 && slot == 0) ||
923 (pcidev->bus->number == bus &&
924 PCI_SLOT(pcidev->devfn) == slot)) {
928 devpriv->pci_dev = pcidev;
931 dev->board_ptr = dt3k_boardtypes + board;
933 if (!devpriv->pci_dev)
936 if ((ret = setup_pci(dev)) < 0)
942 static int setup_pci(struct comedi_device * dev)
944 resource_size_t addr;
947 ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
951 addr = pci_resource_start(devpriv->pci_dev, 0);
952 devpriv->phys_addr = addr;
953 devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
954 if (!devpriv->io_addr)
957 printk("0x%08llx mapped to %p, ",
958 (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
964 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
968 for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
970 from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
971 for (i = 0; i < n_dt3k_boards; i++) {
972 if (from->device == dt3k_boardtypes[i].device_id) {
977 printk("unknown Data Translation PCI device found with device_id=0x%04x\n", from->device);