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, {
78 static const struct comedi_lrange range_dt3000_ai_pgl = { 4, {
86 struct dt3k_boardtype {
89 unsigned int device_id;
93 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) = {
169 PCI_VENDOR_ID_DT, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
170 PCI_VENDOR_ID_DT, 0x0027, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
171 PCI_VENDOR_ID_DT, 0x0023, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
172 PCI_VENDOR_ID_DT, 0x0024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
173 PCI_VENDOR_ID_DT, 0x0028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
174 PCI_VENDOR_ID_DT, 0x0025, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
175 PCI_VENDOR_ID_DT, 0x0026, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
179 MODULE_DEVICE_TABLE(pci, dt3k_pci_table);
181 #define DT3000_SIZE (4*0x1000)
183 /* dual-ported RAM location definitions */
185 #define DPR_DAC_buffer (4*0x000)
186 #define DPR_ADC_buffer (4*0x800)
187 #define DPR_Command (4*0xfd3)
188 #define DPR_SubSys (4*0xfd3)
189 #define DPR_Encode (4*0xfd4)
190 #define DPR_Params(a) (4*(0xfd5+(a)))
191 #define DPR_Tick_Reg_Lo (4*0xff5)
192 #define DPR_Tick_Reg_Hi (4*0xff6)
193 #define DPR_DA_Buf_Front (4*0xff7)
194 #define DPR_DA_Buf_Rear (4*0xff8)
195 #define DPR_AD_Buf_Front (4*0xff9)
196 #define DPR_AD_Buf_Rear (4*0xffa)
197 #define DPR_Int_Mask (4*0xffb)
198 #define DPR_Intr_Flag (4*0xffc)
199 #define DPR_Response_Mbx (4*0xffe)
200 #define DPR_Command_Mbx (4*0xfff)
202 #define AI_FIFO_DEPTH 2003
203 #define AO_FIFO_DEPTH 2048
207 #define CMD_GETBRDINFO 0
209 #define CMD_GETCONFIG 2
212 #define CMD_READSINGLE 5
213 #define CMD_WRITESINGLE 6
214 #define CMD_CALCCLOCK 7
215 #define CMD_READEVENTS 8
216 #define CMD_WRITECTCTRL 16
217 #define CMD_READCTCTRL 17
218 #define CMD_WRITECT 18
219 #define CMD_READCT 19
220 #define CMD_WRITEDATA 32
221 #define CMD_READDATA 33
222 #define CMD_WRITEIO 34
223 #define CMD_READIO 35
224 #define CMD_WRITECODE 36
225 #define CMD_READCODE 37
226 #define CMD_EXECUTE 38
236 /* interrupt flags */
237 #define DT3000_CMDONE 0x80
238 #define DT3000_CTDONE 0x40
239 #define DT3000_DAHWERR 0x20
240 #define DT3000_DASWERR 0x10
241 #define DT3000_DAEMPTY 0x08
242 #define DT3000_ADHWERR 0x04
243 #define DT3000_ADSWERR 0x02
244 #define DT3000_ADFULL 0x01
246 #define DT3000_COMPLETION_MASK 0xff00
247 #define DT3000_COMMAND_MASK 0x00ff
248 #define DT3000_NOTPROCESSED 0x0000
249 #define DT3000_NOERROR 0x5500
250 #define DT3000_ERROR 0xaa00
251 #define DT3000_NOTSUPPORTED 0xff00
253 #define DT3000_EXTERNAL_CLOCK 1
254 #define DT3000_RISING_EDGE 2
256 #define TMODE_MASK 0x1c
258 #define DT3000_AD_TRIG_INTERNAL (0<<2)
259 #define DT3000_AD_TRIG_EXTERNAL (1<<2)
260 #define DT3000_AD_RETRIG_INTERNAL (2<<2)
261 #define DT3000_AD_RETRIG_EXTERNAL (3<<2)
262 #define DT3000_AD_EXTRETRIG (4<<2)
264 #define DT3000_CHANNEL_MODE_SE 0
265 #define DT3000_CHANNEL_MODE_DI 1
267 struct dt3k_private {
269 struct pci_dev *pci_dev;
270 resource_size_t phys_addr;
273 unsigned int ao_readback[2];
274 unsigned int ai_front;
275 unsigned int ai_rear;
278 #define devpriv ((struct dt3k_private *)dev->private)
280 static int dt3000_attach(struct comedi_device *dev,
281 struct comedi_devconfig *it);
282 static int dt3000_detach(struct comedi_device *dev);
283 static struct comedi_driver driver_dt3000 = {
284 .driver_name = "dt3000",
285 .module = THIS_MODULE,
286 .attach = dt3000_attach,
287 .detach = dt3000_detach,
290 COMEDI_PCI_INITCLEANUP(driver_dt3000, dt3k_pci_table);
292 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
293 struct comedi_subdevice *s);
294 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
295 unsigned int round_mode);
296 static int dt3k_ai_cancel(struct comedi_device *dev,
297 struct comedi_subdevice *s);
299 static void debug_intr_flags(unsigned int flags);
304 static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
307 unsigned int status = 0;
309 writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
311 for (i = 0; i < TIMEOUT; i++) {
312 status = readw(devpriv->io_addr + DPR_Command_Mbx);
313 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
317 if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR)
320 printk("dt3k_send_cmd() timeout/error status=0x%04x\n", status);
325 static unsigned int dt3k_readsingle(struct comedi_device *dev,
326 unsigned int subsys, unsigned int chan,
329 writew(subsys, devpriv->io_addr + DPR_SubSys);
331 writew(chan, devpriv->io_addr + DPR_Params(0));
332 writew(gain, devpriv->io_addr + DPR_Params(1));
334 dt3k_send_cmd(dev, CMD_READSINGLE);
336 return readw(devpriv->io_addr + DPR_Params(2));
339 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
340 unsigned int chan, unsigned int data)
342 writew(subsys, devpriv->io_addr + DPR_SubSys);
344 writew(chan, devpriv->io_addr + DPR_Params(0));
345 writew(0, devpriv->io_addr + DPR_Params(1));
346 writew(data, devpriv->io_addr + DPR_Params(2));
348 dt3k_send_cmd(dev, CMD_WRITESINGLE);
351 static int debug_n_ints = 0;
353 /* FIXME! Assumes shared interrupt is for this card. */
354 /* What's this debug_n_ints stuff? Obviously needs some work... */
355 static irqreturn_t dt3k_interrupt(int irq, void *d)
357 struct comedi_device *dev = d;
358 struct comedi_subdevice *s;
364 s = dev->subdevices + 0;
365 status = readw(devpriv->io_addr + DPR_Intr_Flag);
367 debug_intr_flags(status);
370 if (status & DT3000_ADFULL) {
371 dt3k_ai_empty_fifo(dev, s);
372 s->async->events |= COMEDI_CB_BLOCK;
375 if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
376 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
379 if (debug_n_ints >= 10) {
380 dt3k_ai_cancel(dev, s);
381 s->async->events |= COMEDI_CB_EOA;
384 comedi_event(dev, s);
389 static char *intr_flags[] = {
390 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
391 "DaSwError", "DaHwError", "CtDone", "CmDone",
394 static void debug_intr_flags(unsigned int flags)
397 printk("dt3k: intr_flags:");
398 for (i = 0; i < 8; i++) {
399 if (flags & (1 << i))
400 printk(" %s", intr_flags[i]);
406 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
407 struct comedi_subdevice *s)
415 front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
416 count = front - devpriv->ai_front;
418 count += AI_FIFO_DEPTH;
420 printk("reading %d samples\n", count);
422 rear = devpriv->ai_rear;
424 for (i = 0; i < count; i++) {
425 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
426 comedi_buf_put(s->async, data);
428 if (rear >= AI_FIFO_DEPTH)
432 devpriv->ai_rear = rear;
433 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
436 static int dt3k_ai_cmdtest(struct comedi_device *dev,
437 struct comedi_subdevice *s, struct comedi_cmd *cmd)
442 /* step 1: make sure trigger sources are trivially valid */
444 tmp = cmd->start_src;
445 cmd->start_src &= TRIG_NOW;
446 if (!cmd->start_src || tmp != cmd->start_src)
449 tmp = cmd->scan_begin_src;
450 cmd->scan_begin_src &= TRIG_TIMER;
451 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
454 tmp = cmd->convert_src;
455 cmd->convert_src &= TRIG_TIMER;
456 if (!cmd->convert_src || tmp != cmd->convert_src)
459 tmp = cmd->scan_end_src;
460 cmd->scan_end_src &= TRIG_COUNT;
461 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
465 cmd->stop_src &= TRIG_COUNT;
466 if (!cmd->stop_src || tmp != cmd->stop_src)
472 /* step 2: make sure trigger sources are unique and mutually compatible */
477 /* step 3: make sure arguments are trivially compatible */
479 if (cmd->start_arg != 0) {
484 if (cmd->scan_begin_src == TRIG_TIMER) {
485 if (cmd->scan_begin_arg < this_board->ai_speed) {
486 cmd->scan_begin_arg = this_board->ai_speed;
489 if (cmd->scan_begin_arg > 100 * 16 * 65535) {
490 cmd->scan_begin_arg = 100 * 16 * 65535;
496 if (cmd->convert_src == TRIG_TIMER) {
497 if (cmd->convert_arg < this_board->ai_speed) {
498 cmd->convert_arg = this_board->ai_speed;
501 if (cmd->convert_arg > 50 * 16 * 65535) {
502 cmd->convert_arg = 50 * 16 * 65535;
509 if (cmd->scan_end_arg != cmd->chanlist_len) {
510 cmd->scan_end_arg = cmd->chanlist_len;
513 if (cmd->stop_src == TRIG_COUNT) {
514 if (cmd->stop_arg > 0x00ffffff) {
515 cmd->stop_arg = 0x00ffffff;
520 if (cmd->stop_arg != 0) {
529 /* step 4: fix up any arguments */
531 if (cmd->scan_begin_src == TRIG_TIMER) {
532 tmp = cmd->scan_begin_arg;
533 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
534 cmd->flags & TRIG_ROUND_MASK);
535 if (tmp != cmd->scan_begin_arg)
540 if (cmd->convert_src == TRIG_TIMER) {
541 tmp = cmd->convert_arg;
542 dt3k_ns_to_timer(50, &cmd->convert_arg,
543 cmd->flags & TRIG_ROUND_MASK);
544 if (tmp != cmd->convert_arg)
546 if (cmd->scan_begin_src == TRIG_TIMER &&
547 cmd->scan_begin_arg <
548 cmd->convert_arg * cmd->scan_end_arg) {
549 cmd->scan_begin_arg =
550 cmd->convert_arg * cmd->scan_end_arg;
563 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
564 unsigned int round_mode)
566 int divider, base, prescale;
568 /* This function needs improvment */
569 /* Don't know if divider==0 works. */
571 for (prescale = 0; prescale < 16; prescale++) {
572 base = timer_base * (prescale + 1);
573 switch (round_mode) {
574 case TRIG_ROUND_NEAREST:
576 divider = (*nanosec + base / 2) / base;
578 case TRIG_ROUND_DOWN:
579 divider = (*nanosec) / base;
582 divider = (*nanosec) / base;
585 if (divider < 65536) {
586 *nanosec = divider * base;
587 return (prescale << 16) | (divider);
592 base = timer_base * (1 << prescale);
594 *nanosec = divider * base;
595 return (prescale << 16) | (divider);
598 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
600 struct comedi_cmd *cmd = &s->async->cmd;
602 unsigned int chan, range, aref;
603 unsigned int divider;
604 unsigned int tscandiv;
608 printk("dt3k_ai_cmd:\n");
609 for (i = 0; i < cmd->chanlist_len; i++) {
610 chan = CR_CHAN(cmd->chanlist[i]);
611 range = CR_RANGE(cmd->chanlist[i]);
613 writew((range << 6) | chan,
614 devpriv->io_addr + DPR_ADC_buffer + i);
616 aref = CR_AREF(cmd->chanlist[0]);
618 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
619 printk("param[0]=0x%04x\n", cmd->scan_end_arg);
621 if (cmd->convert_src == TRIG_TIMER) {
622 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
623 cmd->flags & TRIG_ROUND_MASK);
624 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
625 printk("param[1]=0x%04x\n", divider >> 16);
626 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
627 printk("param[2]=0x%04x\n", divider & 0xffff);
632 if (cmd->scan_begin_src == TRIG_TIMER) {
633 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
634 cmd->flags & TRIG_ROUND_MASK);
635 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
636 printk("param[3]=0x%04x\n", tscandiv >> 16);
637 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
638 printk("param[4]=0x%04x\n", tscandiv & 0xffff);
643 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
644 writew(mode, devpriv->io_addr + DPR_Params(5));
645 printk("param[5]=0x%04x\n", mode);
646 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
647 printk("param[6]=0x%04x\n", aref == AREF_DIFF);
649 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
650 printk("param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
652 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
653 ret = dt3k_send_cmd(dev, CMD_CONFIG);
655 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
656 devpriv->io_addr + DPR_Int_Mask);
660 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
661 ret = dt3k_send_cmd(dev, CMD_START);
666 static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
670 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
671 ret = dt3k_send_cmd(dev, CMD_STOP);
673 writew(0, devpriv->io_addr + DPR_Int_Mask);
678 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
679 struct comedi_insn *insn, unsigned int *data)
682 unsigned int chan, gain, aref;
684 chan = CR_CHAN(insn->chanspec);
685 gain = CR_RANGE(insn->chanspec);
686 /* XXX docs don't explain how to select aref */
687 aref = CR_AREF(insn->chanspec);
689 for (i = 0; i < insn->n; i++)
690 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
695 static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
696 struct comedi_insn *insn, unsigned int *data)
701 chan = CR_CHAN(insn->chanspec);
702 for (i = 0; i < insn->n; i++) {
703 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
704 devpriv->ao_readback[chan] = data[i];
710 static int dt3k_ao_insn_read(struct comedi_device *dev,
711 struct comedi_subdevice *s,
712 struct comedi_insn *insn, unsigned int *data)
717 chan = CR_CHAN(insn->chanspec);
718 for (i = 0; i < insn->n; i++)
719 data[i] = devpriv->ao_readback[chan];
724 static void dt3k_dio_config(struct comedi_device *dev, int bits)
727 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
729 writew(bits, devpriv->io_addr + DPR_Params(0));
732 writew(0, devpriv->io_addr + DPR_Params(1));
733 writew(0, devpriv->io_addr + DPR_Params(2));
736 dt3k_send_cmd(dev, CMD_CONFIG);
739 static int dt3k_dio_insn_config(struct comedi_device *dev,
740 struct comedi_subdevice *s,
741 struct comedi_insn *insn, unsigned int *data)
745 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
748 case INSN_CONFIG_DIO_OUTPUT:
751 case INSN_CONFIG_DIO_INPUT:
754 case INSN_CONFIG_DIO_QUERY:
757 io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
765 mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
766 dt3k_dio_config(dev, mask);
771 static int dt3k_dio_insn_bits(struct comedi_device *dev,
772 struct comedi_subdevice *s,
773 struct comedi_insn *insn, unsigned int *data)
779 s->state &= ~data[0];
780 s->state |= data[1] & data[0];
781 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
783 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
788 static int dt3k_mem_insn_read(struct comedi_device *dev,
789 struct comedi_subdevice *s,
790 struct comedi_insn *insn, unsigned int *data)
792 unsigned int addr = CR_CHAN(insn->chanspec);
795 for (i = 0; i < insn->n; i++) {
796 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
797 writew(addr, devpriv->io_addr + DPR_Params(0));
798 writew(1, devpriv->io_addr + DPR_Params(1));
800 dt3k_send_cmd(dev, CMD_READCODE);
802 data[i] = readw(devpriv->io_addr + DPR_Params(2));
808 static int dt_pci_probe(struct comedi_device *dev, int bus, int slot);
810 static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
812 struct comedi_subdevice *s;
817 bus = it->options[0];
818 slot = it->options[1];
820 ret = alloc_private(dev, sizeof(struct dt3k_private));
824 ret = dt_pci_probe(dev, bus, slot);
828 printk(" no DT board found\n");
832 dev->board_name = this_board->name;
834 if (request_irq(devpriv->pci_dev->irq, dt3k_interrupt, IRQF_SHARED,
836 printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq);
839 dev->irq = devpriv->pci_dev->irq;
841 ret = alloc_subdevices(dev, 4);
846 dev->read_subdev = s;
849 s->type = COMEDI_SUBD_AI;
850 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
851 s->n_chan = this_board->adchan;
852 s->insn_read = dt3k_ai_insn;
853 s->maxdata = (1 << this_board->adbits) - 1;
854 s->len_chanlist = 512;
855 s->range_table = &range_dt3000_ai; /* XXX */
856 s->do_cmd = dt3k_ai_cmd;
857 s->do_cmdtest = dt3k_ai_cmdtest;
858 s->cancel = dt3k_ai_cancel;
862 s->type = COMEDI_SUBD_AO;
863 s->subdev_flags = SDF_WRITABLE;
865 s->insn_read = dt3k_ao_insn_read;
866 s->insn_write = dt3k_ao_insn;
867 s->maxdata = (1 << this_board->dabits) - 1;
869 s->range_table = &range_bipolar10;
873 s->type = COMEDI_SUBD_DIO;
874 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
876 s->insn_config = dt3k_dio_insn_config;
877 s->insn_bits = dt3k_dio_insn_bits;
880 s->range_table = &range_digital;
884 s->type = COMEDI_SUBD_MEMORY;
885 s->subdev_flags = SDF_READABLE;
887 s->insn_read = dt3k_mem_insn_read;
890 s->range_table = &range_unknown;
895 s->type = COMEDI_SUBD_PROC;
901 static int dt3000_detach(struct comedi_device *dev)
904 free_irq(dev->irq, dev);
907 if (devpriv->pci_dev) {
908 if (devpriv->phys_addr)
909 comedi_pci_disable(devpriv->pci_dev);
910 pci_dev_put(devpriv->pci_dev);
912 if (devpriv->io_addr)
913 iounmap(devpriv->io_addr);
920 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
921 static int setup_pci(struct comedi_device *dev);
923 static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
927 struct pci_dev *pcidev;
930 while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
931 if ((bus == 0 && slot == 0) ||
932 (pcidev->bus->number == bus &&
933 PCI_SLOT(pcidev->devfn) == slot)) {
937 devpriv->pci_dev = pcidev;
940 dev->board_ptr = dt3k_boardtypes + board;
942 if (!devpriv->pci_dev)
945 ret = setup_pci(dev);
952 static int setup_pci(struct comedi_device *dev)
954 resource_size_t addr;
957 ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
961 addr = pci_resource_start(devpriv->pci_dev, 0);
962 devpriv->phys_addr = addr;
963 devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
964 if (!devpriv->io_addr)
967 printk("0x%08llx mapped to %p, ",
968 (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
974 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
978 for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
980 from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
981 for (i = 0; i < n_dt3k_boards; i++) {
982 if (from->device == dt3k_boardtypes[i].device_id) {
988 ("unknown Data Translation PCI device found with device_id=0x%04x\n",