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_fc.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 this_board ((const struct dt3k_boardtype *)dev->board_ptr)
166 #define DT3000_SIZE (4*0x1000)
168 /* dual-ported RAM location definitions */
170 #define DPR_DAC_buffer (4*0x000)
171 #define DPR_ADC_buffer (4*0x800)
172 #define DPR_Command (4*0xfd3)
173 #define DPR_SubSys (4*0xfd3)
174 #define DPR_Encode (4*0xfd4)
175 #define DPR_Params(a) (4*(0xfd5+(a)))
176 #define DPR_Tick_Reg_Lo (4*0xff5)
177 #define DPR_Tick_Reg_Hi (4*0xff6)
178 #define DPR_DA_Buf_Front (4*0xff7)
179 #define DPR_DA_Buf_Rear (4*0xff8)
180 #define DPR_AD_Buf_Front (4*0xff9)
181 #define DPR_AD_Buf_Rear (4*0xffa)
182 #define DPR_Int_Mask (4*0xffb)
183 #define DPR_Intr_Flag (4*0xffc)
184 #define DPR_Response_Mbx (4*0xffe)
185 #define DPR_Command_Mbx (4*0xfff)
187 #define AI_FIFO_DEPTH 2003
188 #define AO_FIFO_DEPTH 2048
192 #define CMD_GETBRDINFO 0
194 #define CMD_GETCONFIG 2
197 #define CMD_READSINGLE 5
198 #define CMD_WRITESINGLE 6
199 #define CMD_CALCCLOCK 7
200 #define CMD_READEVENTS 8
201 #define CMD_WRITECTCTRL 16
202 #define CMD_READCTCTRL 17
203 #define CMD_WRITECT 18
204 #define CMD_READCT 19
205 #define CMD_WRITEDATA 32
206 #define CMD_READDATA 33
207 #define CMD_WRITEIO 34
208 #define CMD_READIO 35
209 #define CMD_WRITECODE 36
210 #define CMD_READCODE 37
211 #define CMD_EXECUTE 38
221 /* interrupt flags */
222 #define DT3000_CMDONE 0x80
223 #define DT3000_CTDONE 0x40
224 #define DT3000_DAHWERR 0x20
225 #define DT3000_DASWERR 0x10
226 #define DT3000_DAEMPTY 0x08
227 #define DT3000_ADHWERR 0x04
228 #define DT3000_ADSWERR 0x02
229 #define DT3000_ADFULL 0x01
231 #define DT3000_COMPLETION_MASK 0xff00
232 #define DT3000_COMMAND_MASK 0x00ff
233 #define DT3000_NOTPROCESSED 0x0000
234 #define DT3000_NOERROR 0x5500
235 #define DT3000_ERROR 0xaa00
236 #define DT3000_NOTSUPPORTED 0xff00
238 #define DT3000_EXTERNAL_CLOCK 1
239 #define DT3000_RISING_EDGE 2
241 #define TMODE_MASK 0x1c
243 #define DT3000_AD_TRIG_INTERNAL (0<<2)
244 #define DT3000_AD_TRIG_EXTERNAL (1<<2)
245 #define DT3000_AD_RETRIG_INTERNAL (2<<2)
246 #define DT3000_AD_RETRIG_EXTERNAL (3<<2)
247 #define DT3000_AD_EXTRETRIG (4<<2)
249 #define DT3000_CHANNEL_MODE_SE 0
250 #define DT3000_CHANNEL_MODE_DI 1
252 struct dt3k_private
{
253 void __iomem
*io_addr
;
255 unsigned int ao_readback
[2];
256 unsigned int ai_front
;
257 unsigned int ai_rear
;
260 #define devpriv ((struct dt3k_private *)dev->private)
262 static void dt3k_ai_empty_fifo(struct comedi_device
*dev
,
263 struct comedi_subdevice
*s
);
264 static int dt3k_ns_to_timer(unsigned int timer_base
, unsigned int *arg
,
265 unsigned int round_mode
);
266 static int dt3k_ai_cancel(struct comedi_device
*dev
,
267 struct comedi_subdevice
*s
);
269 static void debug_intr_flags(unsigned int flags
);
274 static int dt3k_send_cmd(struct comedi_device
*dev
, unsigned int cmd
)
277 unsigned int status
= 0;
279 writew(cmd
, devpriv
->io_addr
+ DPR_Command_Mbx
);
281 for (i
= 0; i
< TIMEOUT
; i
++) {
282 status
= readw(devpriv
->io_addr
+ DPR_Command_Mbx
);
283 if ((status
& DT3000_COMPLETION_MASK
) != DT3000_NOTPROCESSED
)
287 if ((status
& DT3000_COMPLETION_MASK
) == DT3000_NOERROR
)
290 dev_dbg(dev
->class_dev
, "dt3k_send_cmd() timeout/error status=0x%04x\n",
296 static unsigned int dt3k_readsingle(struct comedi_device
*dev
,
297 unsigned int subsys
, unsigned int chan
,
300 writew(subsys
, devpriv
->io_addr
+ DPR_SubSys
);
302 writew(chan
, devpriv
->io_addr
+ DPR_Params(0));
303 writew(gain
, devpriv
->io_addr
+ DPR_Params(1));
305 dt3k_send_cmd(dev
, CMD_READSINGLE
);
307 return readw(devpriv
->io_addr
+ DPR_Params(2));
310 static void dt3k_writesingle(struct comedi_device
*dev
, unsigned int subsys
,
311 unsigned int chan
, unsigned int data
)
313 writew(subsys
, devpriv
->io_addr
+ DPR_SubSys
);
315 writew(chan
, devpriv
->io_addr
+ DPR_Params(0));
316 writew(0, devpriv
->io_addr
+ DPR_Params(1));
317 writew(data
, devpriv
->io_addr
+ DPR_Params(2));
319 dt3k_send_cmd(dev
, CMD_WRITESINGLE
);
322 static int debug_n_ints
;
324 /* FIXME! Assumes shared interrupt is for this card. */
325 /* What's this debug_n_ints stuff? Obviously needs some work... */
326 static irqreturn_t
dt3k_interrupt(int irq
, void *d
)
328 struct comedi_device
*dev
= d
;
329 struct comedi_subdevice
*s
;
335 s
= &dev
->subdevices
[0];
336 status
= readw(devpriv
->io_addr
+ DPR_Intr_Flag
);
338 debug_intr_flags(status
);
341 if (status
& DT3000_ADFULL
) {
342 dt3k_ai_empty_fifo(dev
, s
);
343 s
->async
->events
|= COMEDI_CB_BLOCK
;
346 if (status
& (DT3000_ADSWERR
| DT3000_ADHWERR
))
347 s
->async
->events
|= COMEDI_CB_ERROR
| COMEDI_CB_EOA
;
350 if (debug_n_ints
>= 10) {
351 dt3k_ai_cancel(dev
, s
);
352 s
->async
->events
|= COMEDI_CB_EOA
;
355 comedi_event(dev
, s
);
360 static char *intr_flags
[] = {
361 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
362 "DaSwError", "DaHwError", "CtDone", "CmDone",
365 static void debug_intr_flags(unsigned int flags
)
368 printk(KERN_DEBUG
"dt3k: intr_flags:");
369 for (i
= 0; i
< 8; i
++) {
370 if (flags
& (1 << i
))
371 printk(KERN_CONT
" %s", intr_flags
[i
]);
373 printk(KERN_CONT
"\n");
377 static void dt3k_ai_empty_fifo(struct comedi_device
*dev
,
378 struct comedi_subdevice
*s
)
386 front
= readw(devpriv
->io_addr
+ DPR_AD_Buf_Front
);
387 count
= front
- devpriv
->ai_front
;
389 count
+= AI_FIFO_DEPTH
;
391 dev_dbg(dev
->class_dev
, "reading %d samples\n", count
);
393 rear
= devpriv
->ai_rear
;
395 for (i
= 0; i
< count
; i
++) {
396 data
= readw(devpriv
->io_addr
+ DPR_ADC_buffer
+ rear
);
397 comedi_buf_put(s
->async
, data
);
399 if (rear
>= AI_FIFO_DEPTH
)
403 devpriv
->ai_rear
= rear
;
404 writew(rear
, devpriv
->io_addr
+ DPR_AD_Buf_Rear
);
407 static int dt3k_ai_cmdtest(struct comedi_device
*dev
,
408 struct comedi_subdevice
*s
, struct comedi_cmd
*cmd
)
413 /* Step 1 : check if triggers are trivially valid */
415 err
|= cfc_check_trigger_src(&cmd
->start_src
, TRIG_NOW
);
416 err
|= cfc_check_trigger_src(&cmd
->scan_begin_src
, TRIG_TIMER
);
417 err
|= cfc_check_trigger_src(&cmd
->convert_src
, TRIG_TIMER
);
418 err
|= cfc_check_trigger_src(&cmd
->scan_end_src
, TRIG_COUNT
);
419 err
|= cfc_check_trigger_src(&cmd
->stop_src
, TRIG_COUNT
);
424 /* Step 2a : make sure trigger sources are unique */
425 /* Step 2b : and mutually compatible */
430 /* step 3: make sure arguments are trivially compatible */
432 if (cmd
->start_arg
!= 0) {
437 if (cmd
->scan_begin_src
== TRIG_TIMER
) {
438 if (cmd
->scan_begin_arg
< this_board
->ai_speed
) {
439 cmd
->scan_begin_arg
= this_board
->ai_speed
;
442 if (cmd
->scan_begin_arg
> 100 * 16 * 65535) {
443 cmd
->scan_begin_arg
= 100 * 16 * 65535;
449 if (cmd
->convert_src
== TRIG_TIMER
) {
450 if (cmd
->convert_arg
< this_board
->ai_speed
) {
451 cmd
->convert_arg
= this_board
->ai_speed
;
454 if (cmd
->convert_arg
> 50 * 16 * 65535) {
455 cmd
->convert_arg
= 50 * 16 * 65535;
462 if (cmd
->scan_end_arg
!= cmd
->chanlist_len
) {
463 cmd
->scan_end_arg
= cmd
->chanlist_len
;
466 if (cmd
->stop_src
== TRIG_COUNT
) {
467 if (cmd
->stop_arg
> 0x00ffffff) {
468 cmd
->stop_arg
= 0x00ffffff;
473 if (cmd
->stop_arg
!= 0) {
482 /* step 4: fix up any arguments */
484 if (cmd
->scan_begin_src
== TRIG_TIMER
) {
485 tmp
= cmd
->scan_begin_arg
;
486 dt3k_ns_to_timer(100, &cmd
->scan_begin_arg
,
487 cmd
->flags
& TRIG_ROUND_MASK
);
488 if (tmp
!= cmd
->scan_begin_arg
)
493 if (cmd
->convert_src
== TRIG_TIMER
) {
494 tmp
= cmd
->convert_arg
;
495 dt3k_ns_to_timer(50, &cmd
->convert_arg
,
496 cmd
->flags
& TRIG_ROUND_MASK
);
497 if (tmp
!= cmd
->convert_arg
)
499 if (cmd
->scan_begin_src
== TRIG_TIMER
&&
500 cmd
->scan_begin_arg
<
501 cmd
->convert_arg
* cmd
->scan_end_arg
) {
502 cmd
->scan_begin_arg
=
503 cmd
->convert_arg
* cmd
->scan_end_arg
;
516 static int dt3k_ns_to_timer(unsigned int timer_base
, unsigned int *nanosec
,
517 unsigned int round_mode
)
519 int divider
, base
, prescale
;
521 /* This function needs improvment */
522 /* Don't know if divider==0 works. */
524 for (prescale
= 0; prescale
< 16; prescale
++) {
525 base
= timer_base
* (prescale
+ 1);
526 switch (round_mode
) {
527 case TRIG_ROUND_NEAREST
:
529 divider
= (*nanosec
+ base
/ 2) / base
;
531 case TRIG_ROUND_DOWN
:
532 divider
= (*nanosec
) / base
;
535 divider
= (*nanosec
) / base
;
538 if (divider
< 65536) {
539 *nanosec
= divider
* base
;
540 return (prescale
<< 16) | (divider
);
545 base
= timer_base
* (1 << prescale
);
547 *nanosec
= divider
* base
;
548 return (prescale
<< 16) | (divider
);
551 static int dt3k_ai_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
553 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
555 unsigned int chan
, range
, aref
;
556 unsigned int divider
;
557 unsigned int tscandiv
;
561 dev_dbg(dev
->class_dev
, "dt3k_ai_cmd:\n");
562 for (i
= 0; i
< cmd
->chanlist_len
; i
++) {
563 chan
= CR_CHAN(cmd
->chanlist
[i
]);
564 range
= CR_RANGE(cmd
->chanlist
[i
]);
566 writew((range
<< 6) | chan
,
567 devpriv
->io_addr
+ DPR_ADC_buffer
+ i
);
569 aref
= CR_AREF(cmd
->chanlist
[0]);
571 writew(cmd
->scan_end_arg
, devpriv
->io_addr
+ DPR_Params(0));
572 dev_dbg(dev
->class_dev
, "param[0]=0x%04x\n", cmd
->scan_end_arg
);
574 if (cmd
->convert_src
== TRIG_TIMER
) {
575 divider
= dt3k_ns_to_timer(50, &cmd
->convert_arg
,
576 cmd
->flags
& TRIG_ROUND_MASK
);
577 writew((divider
>> 16), devpriv
->io_addr
+ DPR_Params(1));
578 dev_dbg(dev
->class_dev
, "param[1]=0x%04x\n", divider
>> 16);
579 writew((divider
& 0xffff), devpriv
->io_addr
+ DPR_Params(2));
580 dev_dbg(dev
->class_dev
, "param[2]=0x%04x\n", divider
& 0xffff);
585 if (cmd
->scan_begin_src
== TRIG_TIMER
) {
586 tscandiv
= dt3k_ns_to_timer(100, &cmd
->scan_begin_arg
,
587 cmd
->flags
& TRIG_ROUND_MASK
);
588 writew((tscandiv
>> 16), devpriv
->io_addr
+ DPR_Params(3));
589 dev_dbg(dev
->class_dev
, "param[3]=0x%04x\n", tscandiv
>> 16);
590 writew((tscandiv
& 0xffff), devpriv
->io_addr
+ DPR_Params(4));
591 dev_dbg(dev
->class_dev
, "param[4]=0x%04x\n", tscandiv
& 0xffff);
596 mode
= DT3000_AD_RETRIG_INTERNAL
| 0 | 0;
597 writew(mode
, devpriv
->io_addr
+ DPR_Params(5));
598 dev_dbg(dev
->class_dev
, "param[5]=0x%04x\n", mode
);
599 writew(aref
== AREF_DIFF
, devpriv
->io_addr
+ DPR_Params(6));
600 dev_dbg(dev
->class_dev
, "param[6]=0x%04x\n", aref
== AREF_DIFF
);
602 writew(AI_FIFO_DEPTH
/ 2, devpriv
->io_addr
+ DPR_Params(7));
603 dev_dbg(dev
->class_dev
, "param[7]=0x%04x\n", AI_FIFO_DEPTH
/ 2);
605 writew(SUBS_AI
, devpriv
->io_addr
+ DPR_SubSys
);
606 ret
= dt3k_send_cmd(dev
, CMD_CONFIG
);
608 writew(DT3000_ADFULL
| DT3000_ADSWERR
| DT3000_ADHWERR
,
609 devpriv
->io_addr
+ DPR_Int_Mask
);
613 writew(SUBS_AI
, devpriv
->io_addr
+ DPR_SubSys
);
614 ret
= dt3k_send_cmd(dev
, CMD_START
);
619 static int dt3k_ai_cancel(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
623 writew(SUBS_AI
, devpriv
->io_addr
+ DPR_SubSys
);
624 ret
= dt3k_send_cmd(dev
, CMD_STOP
);
626 writew(0, devpriv
->io_addr
+ DPR_Int_Mask
);
631 static int dt3k_ai_insn(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
632 struct comedi_insn
*insn
, unsigned int *data
)
635 unsigned int chan
, gain
, aref
;
637 chan
= CR_CHAN(insn
->chanspec
);
638 gain
= CR_RANGE(insn
->chanspec
);
639 /* XXX docs don't explain how to select aref */
640 aref
= CR_AREF(insn
->chanspec
);
642 for (i
= 0; i
< insn
->n
; i
++)
643 data
[i
] = dt3k_readsingle(dev
, SUBS_AI
, chan
, gain
);
648 static int dt3k_ao_insn(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
649 struct comedi_insn
*insn
, unsigned int *data
)
654 chan
= CR_CHAN(insn
->chanspec
);
655 for (i
= 0; i
< insn
->n
; i
++) {
656 dt3k_writesingle(dev
, SUBS_AO
, chan
, data
[i
]);
657 devpriv
->ao_readback
[chan
] = data
[i
];
663 static int dt3k_ao_insn_read(struct comedi_device
*dev
,
664 struct comedi_subdevice
*s
,
665 struct comedi_insn
*insn
, unsigned int *data
)
670 chan
= CR_CHAN(insn
->chanspec
);
671 for (i
= 0; i
< insn
->n
; i
++)
672 data
[i
] = devpriv
->ao_readback
[chan
];
677 static void dt3k_dio_config(struct comedi_device
*dev
, int bits
)
680 writew(SUBS_DOUT
, devpriv
->io_addr
+ DPR_SubSys
);
682 writew(bits
, devpriv
->io_addr
+ DPR_Params(0));
685 writew(0, devpriv
->io_addr
+ DPR_Params(1));
686 writew(0, devpriv
->io_addr
+ DPR_Params(2));
689 dt3k_send_cmd(dev
, CMD_CONFIG
);
692 static int dt3k_dio_insn_config(struct comedi_device
*dev
,
693 struct comedi_subdevice
*s
,
694 struct comedi_insn
*insn
, unsigned int *data
)
698 mask
= (CR_CHAN(insn
->chanspec
) < 4) ? 0x0f : 0xf0;
701 case INSN_CONFIG_DIO_OUTPUT
:
704 case INSN_CONFIG_DIO_INPUT
:
707 case INSN_CONFIG_DIO_QUERY
:
710 io_bits
& (1 << CR_CHAN(insn
->chanspec
))) ? COMEDI_OUTPUT
:
718 mask
= (s
->io_bits
& 0x01) | ((s
->io_bits
& 0x10) >> 3);
719 dt3k_dio_config(dev
, mask
);
724 static int dt3k_dio_insn_bits(struct comedi_device
*dev
,
725 struct comedi_subdevice
*s
,
726 struct comedi_insn
*insn
, unsigned int *data
)
729 s
->state
&= ~data
[0];
730 s
->state
|= data
[1] & data
[0];
731 dt3k_writesingle(dev
, SUBS_DOUT
, 0, s
->state
);
733 data
[1] = dt3k_readsingle(dev
, SUBS_DIN
, 0, 0);
738 static int dt3k_mem_insn_read(struct comedi_device
*dev
,
739 struct comedi_subdevice
*s
,
740 struct comedi_insn
*insn
, unsigned int *data
)
742 unsigned int addr
= CR_CHAN(insn
->chanspec
);
745 for (i
= 0; i
< insn
->n
; i
++) {
746 writew(SUBS_MEM
, devpriv
->io_addr
+ DPR_SubSys
);
747 writew(addr
, devpriv
->io_addr
+ DPR_Params(0));
748 writew(1, devpriv
->io_addr
+ DPR_Params(1));
750 dt3k_send_cmd(dev
, CMD_READCODE
);
752 data
[i
] = readw(devpriv
->io_addr
+ DPR_Params(2));
758 static struct pci_dev
*dt3000_find_pci_dev(struct comedi_device
*dev
,
759 struct comedi_devconfig
*it
)
761 struct pci_dev
*pcidev
= NULL
;
762 int bus
= it
->options
[0];
763 int slot
= it
->options
[1];
766 for_each_pci_dev(pcidev
) {
768 if (bus
!= pcidev
->bus
->number
||
769 slot
!= PCI_SLOT(pcidev
->devfn
))
772 if (pcidev
->vendor
!= PCI_VENDOR_ID_DT
)
774 for (i
= 0; i
< ARRAY_SIZE(dt3k_boardtypes
); i
++) {
775 if (dt3k_boardtypes
[i
].device_id
!= pcidev
->device
)
777 dev
->board_ptr
= dt3k_boardtypes
+ i
;
781 dev_err(dev
->class_dev
,
782 "No supported board found! (req. bus %d, slot %d)\n",
787 static int dt3000_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
789 struct pci_dev
*pcidev
;
790 struct comedi_subdevice
*s
;
791 resource_size_t pci_base
;
794 dev_dbg(dev
->class_dev
, "dt3000:\n");
796 ret
= alloc_private(dev
, sizeof(struct dt3k_private
));
800 pcidev
= dt3000_find_pci_dev(dev
, it
);
803 comedi_set_hw_dev(dev
, &pcidev
->dev
);
805 ret
= comedi_pci_enable(pcidev
, "dt3000");
808 dev
->iobase
= 1; /* the "detach" needs this */
810 pci_base
= pci_resource_start(pcidev
, 0);
811 devpriv
->io_addr
= ioremap(pci_base
, DT3000_SIZE
);
812 if (!devpriv
->io_addr
)
815 dev
->board_name
= this_board
->name
;
817 if (request_irq(pcidev
->irq
, dt3k_interrupt
, IRQF_SHARED
,
819 dev_err(dev
->class_dev
, "unable to allocate IRQ %u\n",
823 dev
->irq
= pcidev
->irq
;
825 ret
= comedi_alloc_subdevices(dev
, 4);
829 s
= &dev
->subdevices
[0];
830 dev
->read_subdev
= s
;
833 s
->type
= COMEDI_SUBD_AI
;
834 s
->subdev_flags
= SDF_READABLE
| SDF_GROUND
| SDF_DIFF
| SDF_CMD_READ
;
835 s
->n_chan
= this_board
->adchan
;
836 s
->insn_read
= dt3k_ai_insn
;
837 s
->maxdata
= (1 << this_board
->adbits
) - 1;
838 s
->len_chanlist
= 512;
839 s
->range_table
= &range_dt3000_ai
; /* XXX */
840 s
->do_cmd
= dt3k_ai_cmd
;
841 s
->do_cmdtest
= dt3k_ai_cmdtest
;
842 s
->cancel
= dt3k_ai_cancel
;
844 s
= &dev
->subdevices
[1];
846 s
->type
= COMEDI_SUBD_AO
;
847 s
->subdev_flags
= SDF_WRITABLE
;
849 s
->insn_read
= dt3k_ao_insn_read
;
850 s
->insn_write
= dt3k_ao_insn
;
851 s
->maxdata
= (1 << this_board
->dabits
) - 1;
853 s
->range_table
= &range_bipolar10
;
855 s
= &dev
->subdevices
[2];
857 s
->type
= COMEDI_SUBD_DIO
;
858 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
860 s
->insn_config
= dt3k_dio_insn_config
;
861 s
->insn_bits
= dt3k_dio_insn_bits
;
864 s
->range_table
= &range_digital
;
866 s
= &dev
->subdevices
[3];
868 s
->type
= COMEDI_SUBD_MEMORY
;
869 s
->subdev_flags
= SDF_READABLE
;
871 s
->insn_read
= dt3k_mem_insn_read
;
874 s
->range_table
= &range_unknown
;
877 s
= &dev
->subdevices
[4];
879 s
->type
= COMEDI_SUBD_PROC
;
885 static void dt3000_detach(struct comedi_device
*dev
)
887 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
890 free_irq(dev
->irq
, dev
);
892 if (devpriv
->io_addr
)
893 iounmap(devpriv
->io_addr
);
897 comedi_pci_disable(pcidev
);
902 static struct comedi_driver dt3000_driver
= {
903 .driver_name
= "dt3000",
904 .module
= THIS_MODULE
,
905 .attach
= dt3000_attach
,
906 .detach
= dt3000_detach
,
909 static int __devinit
dt3000_pci_probe(struct pci_dev
*dev
,
910 const struct pci_device_id
*ent
)
912 return comedi_pci_auto_config(dev
, &dt3000_driver
);
915 static void __devexit
dt3000_pci_remove(struct pci_dev
*dev
)
917 comedi_pci_auto_unconfig(dev
);
920 static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table
) = {
921 { PCI_DEVICE(PCI_VENDOR_ID_DT
, 0x0022) },
922 { PCI_DEVICE(PCI_VENDOR_ID_DT
, 0x0027) },
923 { PCI_DEVICE(PCI_VENDOR_ID_DT
, 0x0023) },
924 { PCI_DEVICE(PCI_VENDOR_ID_DT
, 0x0024) },
925 { PCI_DEVICE(PCI_VENDOR_ID_DT
, 0x0028) },
926 { PCI_DEVICE(PCI_VENDOR_ID_DT
, 0x0025) },
927 { PCI_DEVICE(PCI_VENDOR_ID_DT
, 0x0026) },
930 MODULE_DEVICE_TABLE(pci
, dt3000_pci_table
);
932 static struct pci_driver dt3000_pci_driver
= {
934 .id_table
= dt3000_pci_table
,
935 .probe
= dt3000_pci_probe
,
936 .remove
= __devexit_p(dt3000_pci_remove
),
938 module_comedi_pci_driver(dt3000_driver
, dt3000_pci_driver
);
940 MODULE_AUTHOR("Comedi http://www.comedi.org");
941 MODULE_DESCRIPTION("Comedi low-level driver");
942 MODULE_LICENSE("GPL");