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
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",
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 if ((ret = alloc_private(dev, sizeof(struct dt3k_private))) < 0)
817 ret = dt_pci_probe(dev, bus, slot);
821 printk(" no DT board found\n");
825 dev->board_name = this_board->name;
827 if (comedi_request_irq(devpriv->pci_dev->irq, dt3k_interrupt,
828 IRQF_SHARED, "dt3000", dev)) {
829 printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq);
832 dev->irq = devpriv->pci_dev->irq;
834 if ((ret = alloc_subdevices(dev, 4)) < 0)
838 dev->read_subdev = s;
841 s->type = COMEDI_SUBD_AI;
842 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
843 s->n_chan = this_board->adchan;
844 s->insn_read = dt3k_ai_insn;
845 s->maxdata = (1 << this_board->adbits) - 1;
846 s->len_chanlist = 512;
847 s->range_table = &range_dt3000_ai; /* XXX */
848 s->do_cmd = dt3k_ai_cmd;
849 s->do_cmdtest = dt3k_ai_cmdtest;
850 s->cancel = dt3k_ai_cancel;
854 s->type = COMEDI_SUBD_AO;
855 s->subdev_flags = SDF_WRITABLE;
857 s->insn_read = dt3k_ao_insn_read;
858 s->insn_write = dt3k_ao_insn;
859 s->maxdata = (1 << this_board->dabits) - 1;
861 s->range_table = &range_bipolar10;
865 s->type = COMEDI_SUBD_DIO;
866 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
868 s->insn_config = dt3k_dio_insn_config;
869 s->insn_bits = dt3k_dio_insn_bits;
872 s->range_table = &range_digital;
876 s->type = COMEDI_SUBD_MEMORY;
877 s->subdev_flags = SDF_READABLE;
879 s->insn_read = dt3k_mem_insn_read;
882 s->range_table = &range_unknown;
887 s->type = COMEDI_SUBD_PROC;
893 static int dt3000_detach(struct comedi_device *dev)
896 comedi_free_irq(dev->irq, dev);
899 if (devpriv->pci_dev) {
900 if (devpriv->phys_addr) {
901 comedi_pci_disable(devpriv->pci_dev);
903 pci_dev_put(devpriv->pci_dev);
905 if (devpriv->io_addr)
906 iounmap(devpriv->io_addr);
913 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
914 static int setup_pci(struct comedi_device *dev);
916 static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
920 struct pci_dev *pcidev;
923 while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
924 if ((bus == 0 && slot == 0) ||
925 (pcidev->bus->number == bus &&
926 PCI_SLOT(pcidev->devfn) == slot)) {
930 devpriv->pci_dev = pcidev;
933 dev->board_ptr = dt3k_boardtypes + board;
935 if (!devpriv->pci_dev)
938 if ((ret = setup_pci(dev)) < 0)
944 static int setup_pci(struct comedi_device *dev)
946 resource_size_t addr;
949 ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
953 addr = pci_resource_start(devpriv->pci_dev, 0);
954 devpriv->phys_addr = addr;
955 devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
956 if (!devpriv->io_addr)
959 printk("0x%08llx mapped to %p, ",
960 (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
966 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
970 for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
972 from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
973 for (i = 0; i < n_dt3k_boards; i++) {
974 if (from->device == dt3k_boardtypes[i].device_id) {
979 printk("unknown Data Translation PCI device found with device_id=0x%04x\n", from->device);