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, {
86 unsigned int device_id;
90 const struct comedi_lrange *adrange;
95 static const dt3k_boardtype dt3k_boardtypes[] = {
100 adrange: &range_dt3000_ai,
109 adrange: &range_dt3000_ai_pgl,
118 adrange: &range_dt3000_ai,
127 adrange: &range_dt3000_ai,
136 adrange: &range_dt3000_ai_pgl,
145 adrange: &range_dt3000_ai,
150 {name:"dt3005", /* a.k.a. 3004-200 */
154 adrange: &range_dt3000_ai,
161 #define n_dt3k_boards sizeof(dt3k_boardtypes)/sizeof(dt3k_boardtype)
162 #define this_board ((const dt3k_boardtype *)dev->board_ptr)
164 static DEFINE_PCI_DEVICE_TABLE(dt3k_pci_table) = {
165 {PCI_VENDOR_ID_DT, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
166 {PCI_VENDOR_ID_DT, 0x0027, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
167 {PCI_VENDOR_ID_DT, 0x0023, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
168 {PCI_VENDOR_ID_DT, 0x0024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
169 {PCI_VENDOR_ID_DT, 0x0028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
170 {PCI_VENDOR_ID_DT, 0x0025, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
171 {PCI_VENDOR_ID_DT, 0x0026, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
175 MODULE_DEVICE_TABLE(pci, dt3k_pci_table);
177 #define DT3000_SIZE (4*0x1000)
179 /* dual-ported RAM location definitions */
181 #define DPR_DAC_buffer (4*0x000)
182 #define DPR_ADC_buffer (4*0x800)
183 #define DPR_Command (4*0xfd3)
184 #define DPR_SubSys (4*0xfd3)
185 #define DPR_Encode (4*0xfd4)
186 #define DPR_Params(a) (4*(0xfd5+(a)))
187 #define DPR_Tick_Reg_Lo (4*0xff5)
188 #define DPR_Tick_Reg_Hi (4*0xff6)
189 #define DPR_DA_Buf_Front (4*0xff7)
190 #define DPR_DA_Buf_Rear (4*0xff8)
191 #define DPR_AD_Buf_Front (4*0xff9)
192 #define DPR_AD_Buf_Rear (4*0xffa)
193 #define DPR_Int_Mask (4*0xffb)
194 #define DPR_Intr_Flag (4*0xffc)
195 #define DPR_Response_Mbx (4*0xffe)
196 #define DPR_Command_Mbx (4*0xfff)
198 #define AI_FIFO_DEPTH 2003
199 #define AO_FIFO_DEPTH 2048
203 #define CMD_GETBRDINFO 0
205 #define CMD_GETCONFIG 2
208 #define CMD_READSINGLE 5
209 #define CMD_WRITESINGLE 6
210 #define CMD_CALCCLOCK 7
211 #define CMD_READEVENTS 8
212 #define CMD_WRITECTCTRL 16
213 #define CMD_READCTCTRL 17
214 #define CMD_WRITECT 18
215 #define CMD_READCT 19
216 #define CMD_WRITEDATA 32
217 #define CMD_READDATA 33
218 #define CMD_WRITEIO 34
219 #define CMD_READIO 35
220 #define CMD_WRITECODE 36
221 #define CMD_READCODE 37
222 #define CMD_EXECUTE 38
232 /* interrupt flags */
233 #define DT3000_CMDONE 0x80
234 #define DT3000_CTDONE 0x40
235 #define DT3000_DAHWERR 0x20
236 #define DT3000_DASWERR 0x10
237 #define DT3000_DAEMPTY 0x08
238 #define DT3000_ADHWERR 0x04
239 #define DT3000_ADSWERR 0x02
240 #define DT3000_ADFULL 0x01
242 #define DT3000_COMPLETION_MASK 0xff00
243 #define DT3000_COMMAND_MASK 0x00ff
244 #define DT3000_NOTPROCESSED 0x0000
245 #define DT3000_NOERROR 0x5500
246 #define DT3000_ERROR 0xaa00
247 #define DT3000_NOTSUPPORTED 0xff00
249 #define DT3000_EXTERNAL_CLOCK 1
250 #define DT3000_RISING_EDGE 2
252 #define TMODE_MASK 0x1c
254 #define DT3000_AD_TRIG_INTERNAL (0<<2)
255 #define DT3000_AD_TRIG_EXTERNAL (1<<2)
256 #define DT3000_AD_RETRIG_INTERNAL (2<<2)
257 #define DT3000_AD_RETRIG_EXTERNAL (3<<2)
258 #define DT3000_AD_EXTRETRIG (4<<2)
260 #define DT3000_CHANNEL_MODE_SE 0
261 #define DT3000_CHANNEL_MODE_DI 1
264 struct pci_dev *pci_dev;
265 resource_size_t phys_addr;
268 unsigned int ao_readback[2];
269 unsigned int ai_front;
270 unsigned int ai_rear;
272 #define devpriv ((dt3k_private *)dev->private)
274 static int dt3000_attach(struct comedi_device * dev, comedi_devconfig * it);
275 static int dt3000_detach(struct comedi_device * dev);
276 static struct comedi_driver driver_dt3000 = {
277 driver_name:"dt3000",
279 attach:dt3000_attach,
280 detach:dt3000_detach,
283 COMEDI_PCI_INITCLEANUP(driver_dt3000, dt3k_pci_table);
285 static void dt3k_ai_empty_fifo(struct comedi_device * dev, struct comedi_subdevice * s);
286 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
287 unsigned int round_mode);
288 static int dt3k_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s);
290 static void debug_intr_flags(unsigned int flags);
295 static int dt3k_send_cmd(struct comedi_device * dev, unsigned int cmd)
298 unsigned int status = 0;
300 writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
302 for (i = 0; i < TIMEOUT; i++) {
303 status = readw(devpriv->io_addr + DPR_Command_Mbx);
304 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
308 if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR) {
312 printk("dt3k_send_cmd() timeout/error status=0x%04x\n", status);
317 static unsigned int dt3k_readsingle(struct comedi_device * dev, unsigned int subsys,
318 unsigned int chan, unsigned int gain)
320 writew(subsys, devpriv->io_addr + DPR_SubSys);
322 writew(chan, devpriv->io_addr + DPR_Params(0));
323 writew(gain, devpriv->io_addr + DPR_Params(1));
325 dt3k_send_cmd(dev, CMD_READSINGLE);
327 return readw(devpriv->io_addr + DPR_Params(2));
330 static void dt3k_writesingle(struct comedi_device * dev, unsigned int subsys,
331 unsigned int chan, unsigned int data)
333 writew(subsys, devpriv->io_addr + DPR_SubSys);
335 writew(chan, devpriv->io_addr + DPR_Params(0));
336 writew(0, devpriv->io_addr + DPR_Params(1));
337 writew(data, devpriv->io_addr + DPR_Params(2));
339 dt3k_send_cmd(dev, CMD_WRITESINGLE);
342 static int debug_n_ints = 0;
344 // FIXME! Assumes shared interrupt is for this card.
345 // What's this debug_n_ints stuff? Obviously needs some work...
346 static irqreturn_t dt3k_interrupt(int irq, void *d PT_REGS_ARG)
348 struct comedi_device *dev = d;
349 struct comedi_subdevice *s;
352 if (!dev->attached) {
356 s = dev->subdevices + 0;
357 status = readw(devpriv->io_addr + DPR_Intr_Flag);
359 debug_intr_flags(status);
362 if (status & DT3000_ADFULL) {
363 dt3k_ai_empty_fifo(dev, s);
364 s->async->events |= COMEDI_CB_BLOCK;
367 if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) {
368 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
372 if (debug_n_ints >= 10) {
373 dt3k_ai_cancel(dev, s);
374 s->async->events |= COMEDI_CB_EOA;
377 comedi_event(dev, s);
382 static char *intr_flags[] = {
383 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
384 "DaSwError", "DaHwError", "CtDone", "CmDone",
386 static void debug_intr_flags(unsigned int flags)
389 printk("dt3k: intr_flags:");
390 for (i = 0; i < 8; i++) {
391 if (flags & (1 << i)) {
392 printk(" %s", intr_flags[i]);
399 static void dt3k_ai_empty_fifo(struct comedi_device * dev, struct comedi_subdevice * s)
407 front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
408 count = front - devpriv->ai_front;
410 count += AI_FIFO_DEPTH;
412 printk("reading %d samples\n", count);
414 rear = devpriv->ai_rear;
416 for (i = 0; i < count; i++) {
417 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
418 comedi_buf_put(s->async, data);
420 if (rear >= AI_FIFO_DEPTH)
424 devpriv->ai_rear = rear;
425 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
428 static int dt3k_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s,
429 struct comedi_cmd * cmd)
434 /* step 1: make sure trigger sources are trivially valid */
436 tmp = cmd->start_src;
437 cmd->start_src &= TRIG_NOW;
438 if (!cmd->start_src || tmp != cmd->start_src)
441 tmp = cmd->scan_begin_src;
442 cmd->scan_begin_src &= TRIG_TIMER;
443 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
446 tmp = cmd->convert_src;
447 cmd->convert_src &= TRIG_TIMER;
448 if (!cmd->convert_src || tmp != cmd->convert_src)
451 tmp = cmd->scan_end_src;
452 cmd->scan_end_src &= TRIG_COUNT;
453 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
457 cmd->stop_src &= TRIG_COUNT;
458 if (!cmd->stop_src || tmp != cmd->stop_src)
464 /* step 2: make sure trigger sources are unique and mutually compatible */
469 /* step 3: make sure arguments are trivially compatible */
471 if (cmd->start_arg != 0) {
476 if (cmd->scan_begin_src == TRIG_TIMER) {
477 if (cmd->scan_begin_arg < this_board->ai_speed) {
478 cmd->scan_begin_arg = this_board->ai_speed;
481 if (cmd->scan_begin_arg > 100 * 16 * 65535) {
482 cmd->scan_begin_arg = 100 * 16 * 65535;
488 if (cmd->convert_src == TRIG_TIMER) {
489 if (cmd->convert_arg < this_board->ai_speed) {
490 cmd->convert_arg = this_board->ai_speed;
493 if (cmd->convert_arg > 50 * 16 * 65535) {
494 cmd->convert_arg = 50 * 16 * 65535;
501 if (cmd->scan_end_arg != cmd->chanlist_len) {
502 cmd->scan_end_arg = cmd->chanlist_len;
505 if (cmd->stop_src == TRIG_COUNT) {
506 if (cmd->stop_arg > 0x00ffffff) {
507 cmd->stop_arg = 0x00ffffff;
512 if (cmd->stop_arg != 0) {
521 /* step 4: fix up any arguments */
523 if (cmd->scan_begin_src == TRIG_TIMER) {
524 tmp = cmd->scan_begin_arg;
525 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
526 cmd->flags & TRIG_ROUND_MASK);
527 if (tmp != cmd->scan_begin_arg)
532 if (cmd->convert_src == TRIG_TIMER) {
533 tmp = cmd->convert_arg;
534 dt3k_ns_to_timer(50, &cmd->convert_arg,
535 cmd->flags & TRIG_ROUND_MASK);
536 if (tmp != cmd->convert_arg)
538 if (cmd->scan_begin_src == TRIG_TIMER &&
539 cmd->scan_begin_arg <
540 cmd->convert_arg * cmd->scan_end_arg) {
541 cmd->scan_begin_arg =
542 cmd->convert_arg * cmd->scan_end_arg;
555 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
556 unsigned int round_mode)
558 int divider, base, prescale;
560 /* This function needs improvment */
561 /* Don't know if divider==0 works. */
563 for (prescale = 0; prescale < 16; prescale++) {
564 base = timer_base * (prescale + 1);
565 switch (round_mode) {
566 case TRIG_ROUND_NEAREST:
568 divider = (*nanosec + base / 2) / base;
570 case TRIG_ROUND_DOWN:
571 divider = (*nanosec) / base;
574 divider = (*nanosec) / base;
577 if (divider < 65536) {
578 *nanosec = divider * base;
579 return (prescale << 16) | (divider);
584 base = timer_base * (1 << prescale);
586 *nanosec = divider * base;
587 return (prescale << 16) | (divider);
590 static int dt3k_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s)
592 struct comedi_cmd *cmd = &s->async->cmd;
594 unsigned int chan, range, aref;
595 unsigned int divider;
596 unsigned int tscandiv;
600 printk("dt3k_ai_cmd:\n");
601 for (i = 0; i < cmd->chanlist_len; i++) {
602 chan = CR_CHAN(cmd->chanlist[i]);
603 range = CR_RANGE(cmd->chanlist[i]);
605 writew((range << 6) | chan,
606 devpriv->io_addr + DPR_ADC_buffer + i);
608 aref = CR_AREF(cmd->chanlist[0]);
610 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
611 printk("param[0]=0x%04x\n", cmd->scan_end_arg);
613 if (cmd->convert_src == TRIG_TIMER) {
614 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
615 cmd->flags & TRIG_ROUND_MASK);
616 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
617 printk("param[1]=0x%04x\n", divider >> 16);
618 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
619 printk("param[2]=0x%04x\n", divider & 0xffff);
624 if (cmd->scan_begin_src == TRIG_TIMER) {
625 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
626 cmd->flags & TRIG_ROUND_MASK);
627 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
628 printk("param[3]=0x%04x\n", tscandiv >> 16);
629 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
630 printk("param[4]=0x%04x\n", tscandiv & 0xffff);
635 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
636 writew(mode, devpriv->io_addr + DPR_Params(5));
637 printk("param[5]=0x%04x\n", mode);
638 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
639 printk("param[6]=0x%04x\n", aref == AREF_DIFF);
641 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
642 printk("param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
644 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
645 ret = dt3k_send_cmd(dev, CMD_CONFIG);
647 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
648 devpriv->io_addr + DPR_Int_Mask);
652 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
653 ret = dt3k_send_cmd(dev, CMD_START);
658 static int dt3k_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s)
662 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
663 ret = dt3k_send_cmd(dev, CMD_STOP);
665 writew(0, devpriv->io_addr + DPR_Int_Mask);
670 static int dt3k_ai_insn(struct comedi_device * dev, struct comedi_subdevice * s,
671 struct comedi_insn * insn, unsigned int * data)
674 unsigned int chan, gain, aref;
676 chan = CR_CHAN(insn->chanspec);
677 gain = CR_RANGE(insn->chanspec);
678 /* XXX docs don't explain how to select aref */
679 aref = CR_AREF(insn->chanspec);
681 for (i = 0; i < insn->n; i++) {
682 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
688 static int dt3k_ao_insn(struct comedi_device * dev, struct comedi_subdevice * s,
689 struct comedi_insn * insn, unsigned int * data)
694 chan = CR_CHAN(insn->chanspec);
695 for (i = 0; i < insn->n; i++) {
696 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
697 devpriv->ao_readback[chan] = data[i];
703 static int dt3k_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
704 struct comedi_insn * insn, unsigned int * data)
709 chan = CR_CHAN(insn->chanspec);
710 for (i = 0; i < insn->n; i++) {
711 data[i] = devpriv->ao_readback[chan];
717 static void dt3k_dio_config(struct comedi_device * dev, int bits)
720 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
722 writew(bits, devpriv->io_addr + DPR_Params(0));
725 writew(0, devpriv->io_addr + DPR_Params(1));
726 writew(0, devpriv->io_addr + DPR_Params(2));
729 dt3k_send_cmd(dev, CMD_CONFIG);
732 static int dt3k_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
733 struct comedi_insn * insn, unsigned int * data)
737 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
740 case INSN_CONFIG_DIO_OUTPUT:
743 case INSN_CONFIG_DIO_INPUT:
746 case INSN_CONFIG_DIO_QUERY:
748 (s->io_bits & (1 << CR_CHAN(insn->
749 chanspec))) ? COMEDI_OUTPUT :
757 mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
758 dt3k_dio_config(dev, mask);
763 static int dt3k_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
764 struct comedi_insn * insn, unsigned int * data)
770 s->state &= ~data[0];
771 s->state |= data[1] & data[0];
772 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
774 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
779 static int dt3k_mem_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
780 struct comedi_insn * insn, unsigned int * data)
782 unsigned int addr = CR_CHAN(insn->chanspec);
785 for (i = 0; i < insn->n; i++) {
786 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
787 writew(addr, devpriv->io_addr + DPR_Params(0));
788 writew(1, devpriv->io_addr + DPR_Params(1));
790 dt3k_send_cmd(dev, CMD_READCODE);
792 data[i] = readw(devpriv->io_addr + DPR_Params(2));
798 static int dt_pci_probe(struct comedi_device * dev, int bus, int slot);
800 static int dt3000_attach(struct comedi_device * dev, comedi_devconfig * it)
802 struct comedi_subdevice *s;
807 bus = it->options[0];
808 slot = it->options[1];
810 if ((ret = alloc_private(dev, sizeof(dt3k_private))) < 0)
813 ret = dt_pci_probe(dev, bus, slot);
817 printk(" no DT board found\n");
821 dev->board_name = this_board->name;
823 if (comedi_request_irq(devpriv->pci_dev->irq, dt3k_interrupt,
824 IRQF_SHARED, "dt3000", dev)) {
825 printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq);
828 dev->irq = devpriv->pci_dev->irq;
830 if ((ret = alloc_subdevices(dev, 4)) < 0)
834 dev->read_subdev = s;
837 s->type = COMEDI_SUBD_AI;
838 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
839 s->n_chan = this_board->adchan;
840 s->insn_read = dt3k_ai_insn;
841 s->maxdata = (1 << this_board->adbits) - 1;
842 s->len_chanlist = 512;
843 s->range_table = &range_dt3000_ai; /* XXX */
844 s->do_cmd = dt3k_ai_cmd;
845 s->do_cmdtest = dt3k_ai_cmdtest;
846 s->cancel = dt3k_ai_cancel;
850 s->type = COMEDI_SUBD_AO;
851 s->subdev_flags = SDF_WRITABLE;
853 s->insn_read = dt3k_ao_insn_read;
854 s->insn_write = dt3k_ao_insn;
855 s->maxdata = (1 << this_board->dabits) - 1;
857 s->range_table = &range_bipolar10;
861 s->type = COMEDI_SUBD_DIO;
862 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
864 s->insn_config = dt3k_dio_insn_config;
865 s->insn_bits = dt3k_dio_insn_bits;
868 s->range_table = &range_digital;
872 s->type = COMEDI_SUBD_MEMORY;
873 s->subdev_flags = SDF_READABLE;
875 s->insn_read = dt3k_mem_insn_read;
878 s->range_table = &range_unknown;
883 s->type = COMEDI_SUBD_PROC;
889 static int dt3000_detach(struct comedi_device * dev)
892 comedi_free_irq(dev->irq, dev);
895 if (devpriv->pci_dev) {
896 if (devpriv->phys_addr) {
897 comedi_pci_disable(devpriv->pci_dev);
899 pci_dev_put(devpriv->pci_dev);
901 if (devpriv->io_addr)
902 iounmap(devpriv->io_addr);
909 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
910 static int setup_pci(struct comedi_device * dev);
912 static int dt_pci_probe(struct comedi_device * dev, int bus, int slot)
916 struct pci_dev *pcidev;
919 while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
920 if ((bus == 0 && slot == 0) ||
921 (pcidev->bus->number == bus &&
922 PCI_SLOT(pcidev->devfn) == slot)) {
926 devpriv->pci_dev = pcidev;
929 dev->board_ptr = dt3k_boardtypes + board;
931 if (!devpriv->pci_dev)
934 if ((ret = setup_pci(dev)) < 0)
940 static int setup_pci(struct comedi_device * dev)
942 resource_size_t addr;
945 ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
949 addr = pci_resource_start(devpriv->pci_dev, 0);
950 devpriv->phys_addr = addr;
951 devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
952 if (!devpriv->io_addr)
955 printk("0x%08llx mapped to %p, ",
956 (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
962 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
966 for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
968 from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
969 for (i = 0; i < n_dt3k_boards; i++) {
970 if (from->device == dt3k_boardtypes[i].device_id) {
975 printk("unknown Data Translation PCI device found with device_id=0x%04x\n", from->device);