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 static void dt3k_ai_empty_fifo(struct comedi_device
*dev
,
261 struct comedi_subdevice
*s
);
262 static int dt3k_ns_to_timer(unsigned int timer_base
, unsigned int *arg
,
263 unsigned int round_mode
);
264 static int dt3k_ai_cancel(struct comedi_device
*dev
,
265 struct comedi_subdevice
*s
);
267 static void debug_intr_flags(unsigned int flags
);
272 static int dt3k_send_cmd(struct comedi_device
*dev
, unsigned int cmd
)
274 struct dt3k_private
*devpriv
= dev
->private;
276 unsigned int status
= 0;
278 writew(cmd
, devpriv
->io_addr
+ DPR_Command_Mbx
);
280 for (i
= 0; i
< TIMEOUT
; i
++) {
281 status
= readw(devpriv
->io_addr
+ DPR_Command_Mbx
);
282 if ((status
& DT3000_COMPLETION_MASK
) != DT3000_NOTPROCESSED
)
286 if ((status
& DT3000_COMPLETION_MASK
) == DT3000_NOERROR
)
289 dev_dbg(dev
->class_dev
, "dt3k_send_cmd() timeout/error status=0x%04x\n",
295 static unsigned int dt3k_readsingle(struct comedi_device
*dev
,
296 unsigned int subsys
, unsigned int chan
,
299 struct dt3k_private
*devpriv
= dev
->private;
301 writew(subsys
, devpriv
->io_addr
+ DPR_SubSys
);
303 writew(chan
, devpriv
->io_addr
+ DPR_Params(0));
304 writew(gain
, devpriv
->io_addr
+ DPR_Params(1));
306 dt3k_send_cmd(dev
, CMD_READSINGLE
);
308 return readw(devpriv
->io_addr
+ DPR_Params(2));
311 static void dt3k_writesingle(struct comedi_device
*dev
, unsigned int subsys
,
312 unsigned int chan
, unsigned int data
)
314 struct dt3k_private
*devpriv
= dev
->private;
316 writew(subsys
, devpriv
->io_addr
+ DPR_SubSys
);
318 writew(chan
, devpriv
->io_addr
+ DPR_Params(0));
319 writew(0, devpriv
->io_addr
+ DPR_Params(1));
320 writew(data
, devpriv
->io_addr
+ DPR_Params(2));
322 dt3k_send_cmd(dev
, CMD_WRITESINGLE
);
325 static int debug_n_ints
;
327 /* FIXME! Assumes shared interrupt is for this card. */
328 /* What's this debug_n_ints stuff? Obviously needs some work... */
329 static irqreturn_t
dt3k_interrupt(int irq
, void *d
)
331 struct comedi_device
*dev
= d
;
332 struct dt3k_private
*devpriv
= dev
->private;
333 struct comedi_subdevice
*s
;
339 s
= &dev
->subdevices
[0];
340 status
= readw(devpriv
->io_addr
+ DPR_Intr_Flag
);
342 debug_intr_flags(status
);
345 if (status
& DT3000_ADFULL
) {
346 dt3k_ai_empty_fifo(dev
, s
);
347 s
->async
->events
|= COMEDI_CB_BLOCK
;
350 if (status
& (DT3000_ADSWERR
| DT3000_ADHWERR
))
351 s
->async
->events
|= COMEDI_CB_ERROR
| COMEDI_CB_EOA
;
354 if (debug_n_ints
>= 10) {
355 dt3k_ai_cancel(dev
, s
);
356 s
->async
->events
|= COMEDI_CB_EOA
;
359 comedi_event(dev
, s
);
364 static char *intr_flags
[] = {
365 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
366 "DaSwError", "DaHwError", "CtDone", "CmDone",
369 static void debug_intr_flags(unsigned int flags
)
372 printk(KERN_DEBUG
"dt3k: intr_flags:");
373 for (i
= 0; i
< 8; i
++) {
374 if (flags
& (1 << i
))
375 printk(KERN_CONT
" %s", intr_flags
[i
]);
377 printk(KERN_CONT
"\n");
381 static void dt3k_ai_empty_fifo(struct comedi_device
*dev
,
382 struct comedi_subdevice
*s
)
384 struct dt3k_private
*devpriv
= dev
->private;
391 front
= readw(devpriv
->io_addr
+ DPR_AD_Buf_Front
);
392 count
= front
- devpriv
->ai_front
;
394 count
+= AI_FIFO_DEPTH
;
396 dev_dbg(dev
->class_dev
, "reading %d samples\n", count
);
398 rear
= devpriv
->ai_rear
;
400 for (i
= 0; i
< count
; i
++) {
401 data
= readw(devpriv
->io_addr
+ DPR_ADC_buffer
+ rear
);
402 comedi_buf_put(s
->async
, data
);
404 if (rear
>= AI_FIFO_DEPTH
)
408 devpriv
->ai_rear
= rear
;
409 writew(rear
, devpriv
->io_addr
+ DPR_AD_Buf_Rear
);
412 static int dt3k_ai_cmdtest(struct comedi_device
*dev
,
413 struct comedi_subdevice
*s
, struct comedi_cmd
*cmd
)
418 /* Step 1 : check if triggers are trivially valid */
420 err
|= cfc_check_trigger_src(&cmd
->start_src
, TRIG_NOW
);
421 err
|= cfc_check_trigger_src(&cmd
->scan_begin_src
, TRIG_TIMER
);
422 err
|= cfc_check_trigger_src(&cmd
->convert_src
, TRIG_TIMER
);
423 err
|= cfc_check_trigger_src(&cmd
->scan_end_src
, TRIG_COUNT
);
424 err
|= cfc_check_trigger_src(&cmd
->stop_src
, TRIG_COUNT
);
429 /* Step 2a : make sure trigger sources are unique */
430 /* Step 2b : and mutually compatible */
435 /* step 3: make sure arguments are trivially compatible */
437 if (cmd
->start_arg
!= 0) {
442 if (cmd
->scan_begin_src
== TRIG_TIMER
) {
443 if (cmd
->scan_begin_arg
< this_board
->ai_speed
) {
444 cmd
->scan_begin_arg
= this_board
->ai_speed
;
447 if (cmd
->scan_begin_arg
> 100 * 16 * 65535) {
448 cmd
->scan_begin_arg
= 100 * 16 * 65535;
454 if (cmd
->convert_src
== TRIG_TIMER
) {
455 if (cmd
->convert_arg
< this_board
->ai_speed
) {
456 cmd
->convert_arg
= this_board
->ai_speed
;
459 if (cmd
->convert_arg
> 50 * 16 * 65535) {
460 cmd
->convert_arg
= 50 * 16 * 65535;
467 if (cmd
->scan_end_arg
!= cmd
->chanlist_len
) {
468 cmd
->scan_end_arg
= cmd
->chanlist_len
;
471 if (cmd
->stop_src
== TRIG_COUNT
) {
472 if (cmd
->stop_arg
> 0x00ffffff) {
473 cmd
->stop_arg
= 0x00ffffff;
478 if (cmd
->stop_arg
!= 0) {
487 /* step 4: fix up any arguments */
489 if (cmd
->scan_begin_src
== TRIG_TIMER
) {
490 tmp
= cmd
->scan_begin_arg
;
491 dt3k_ns_to_timer(100, &cmd
->scan_begin_arg
,
492 cmd
->flags
& TRIG_ROUND_MASK
);
493 if (tmp
!= cmd
->scan_begin_arg
)
498 if (cmd
->convert_src
== TRIG_TIMER
) {
499 tmp
= cmd
->convert_arg
;
500 dt3k_ns_to_timer(50, &cmd
->convert_arg
,
501 cmd
->flags
& TRIG_ROUND_MASK
);
502 if (tmp
!= cmd
->convert_arg
)
504 if (cmd
->scan_begin_src
== TRIG_TIMER
&&
505 cmd
->scan_begin_arg
<
506 cmd
->convert_arg
* cmd
->scan_end_arg
) {
507 cmd
->scan_begin_arg
=
508 cmd
->convert_arg
* cmd
->scan_end_arg
;
521 static int dt3k_ns_to_timer(unsigned int timer_base
, unsigned int *nanosec
,
522 unsigned int round_mode
)
524 int divider
, base
, prescale
;
526 /* This function needs improvment */
527 /* Don't know if divider==0 works. */
529 for (prescale
= 0; prescale
< 16; prescale
++) {
530 base
= timer_base
* (prescale
+ 1);
531 switch (round_mode
) {
532 case TRIG_ROUND_NEAREST
:
534 divider
= (*nanosec
+ base
/ 2) / base
;
536 case TRIG_ROUND_DOWN
:
537 divider
= (*nanosec
) / base
;
540 divider
= (*nanosec
) / base
;
543 if (divider
< 65536) {
544 *nanosec
= divider
* base
;
545 return (prescale
<< 16) | (divider
);
550 base
= timer_base
* (1 << prescale
);
552 *nanosec
= divider
* base
;
553 return (prescale
<< 16) | (divider
);
556 static int dt3k_ai_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
558 struct dt3k_private
*devpriv
= dev
->private;
559 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
561 unsigned int chan
, range
, aref
;
562 unsigned int divider
;
563 unsigned int tscandiv
;
567 dev_dbg(dev
->class_dev
, "dt3k_ai_cmd:\n");
568 for (i
= 0; i
< cmd
->chanlist_len
; i
++) {
569 chan
= CR_CHAN(cmd
->chanlist
[i
]);
570 range
= CR_RANGE(cmd
->chanlist
[i
]);
572 writew((range
<< 6) | chan
,
573 devpriv
->io_addr
+ DPR_ADC_buffer
+ i
);
575 aref
= CR_AREF(cmd
->chanlist
[0]);
577 writew(cmd
->scan_end_arg
, devpriv
->io_addr
+ DPR_Params(0));
578 dev_dbg(dev
->class_dev
, "param[0]=0x%04x\n", cmd
->scan_end_arg
);
580 if (cmd
->convert_src
== TRIG_TIMER
) {
581 divider
= dt3k_ns_to_timer(50, &cmd
->convert_arg
,
582 cmd
->flags
& TRIG_ROUND_MASK
);
583 writew((divider
>> 16), devpriv
->io_addr
+ DPR_Params(1));
584 dev_dbg(dev
->class_dev
, "param[1]=0x%04x\n", divider
>> 16);
585 writew((divider
& 0xffff), devpriv
->io_addr
+ DPR_Params(2));
586 dev_dbg(dev
->class_dev
, "param[2]=0x%04x\n", divider
& 0xffff);
591 if (cmd
->scan_begin_src
== TRIG_TIMER
) {
592 tscandiv
= dt3k_ns_to_timer(100, &cmd
->scan_begin_arg
,
593 cmd
->flags
& TRIG_ROUND_MASK
);
594 writew((tscandiv
>> 16), devpriv
->io_addr
+ DPR_Params(3));
595 dev_dbg(dev
->class_dev
, "param[3]=0x%04x\n", tscandiv
>> 16);
596 writew((tscandiv
& 0xffff), devpriv
->io_addr
+ DPR_Params(4));
597 dev_dbg(dev
->class_dev
, "param[4]=0x%04x\n", tscandiv
& 0xffff);
602 mode
= DT3000_AD_RETRIG_INTERNAL
| 0 | 0;
603 writew(mode
, devpriv
->io_addr
+ DPR_Params(5));
604 dev_dbg(dev
->class_dev
, "param[5]=0x%04x\n", mode
);
605 writew(aref
== AREF_DIFF
, devpriv
->io_addr
+ DPR_Params(6));
606 dev_dbg(dev
->class_dev
, "param[6]=0x%04x\n", aref
== AREF_DIFF
);
608 writew(AI_FIFO_DEPTH
/ 2, devpriv
->io_addr
+ DPR_Params(7));
609 dev_dbg(dev
->class_dev
, "param[7]=0x%04x\n", AI_FIFO_DEPTH
/ 2);
611 writew(SUBS_AI
, devpriv
->io_addr
+ DPR_SubSys
);
612 ret
= dt3k_send_cmd(dev
, CMD_CONFIG
);
614 writew(DT3000_ADFULL
| DT3000_ADSWERR
| DT3000_ADHWERR
,
615 devpriv
->io_addr
+ DPR_Int_Mask
);
619 writew(SUBS_AI
, devpriv
->io_addr
+ DPR_SubSys
);
620 ret
= dt3k_send_cmd(dev
, CMD_START
);
625 static int dt3k_ai_cancel(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
627 struct dt3k_private
*devpriv
= dev
->private;
630 writew(SUBS_AI
, devpriv
->io_addr
+ DPR_SubSys
);
631 ret
= dt3k_send_cmd(dev
, CMD_STOP
);
633 writew(0, devpriv
->io_addr
+ DPR_Int_Mask
);
638 static int dt3k_ai_insn(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
639 struct comedi_insn
*insn
, unsigned int *data
)
642 unsigned int chan
, gain
, aref
;
644 chan
= CR_CHAN(insn
->chanspec
);
645 gain
= CR_RANGE(insn
->chanspec
);
646 /* XXX docs don't explain how to select aref */
647 aref
= CR_AREF(insn
->chanspec
);
649 for (i
= 0; i
< insn
->n
; i
++)
650 data
[i
] = dt3k_readsingle(dev
, SUBS_AI
, chan
, gain
);
655 static int dt3k_ao_insn(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
656 struct comedi_insn
*insn
, unsigned int *data
)
658 struct dt3k_private
*devpriv
= dev
->private;
662 chan
= CR_CHAN(insn
->chanspec
);
663 for (i
= 0; i
< insn
->n
; i
++) {
664 dt3k_writesingle(dev
, SUBS_AO
, chan
, data
[i
]);
665 devpriv
->ao_readback
[chan
] = data
[i
];
671 static int dt3k_ao_insn_read(struct comedi_device
*dev
,
672 struct comedi_subdevice
*s
,
673 struct comedi_insn
*insn
, unsigned int *data
)
675 struct dt3k_private
*devpriv
= dev
->private;
679 chan
= CR_CHAN(insn
->chanspec
);
680 for (i
= 0; i
< insn
->n
; i
++)
681 data
[i
] = devpriv
->ao_readback
[chan
];
686 static void dt3k_dio_config(struct comedi_device
*dev
, int bits
)
688 struct dt3k_private
*devpriv
= dev
->private;
691 writew(SUBS_DOUT
, devpriv
->io_addr
+ DPR_SubSys
);
693 writew(bits
, devpriv
->io_addr
+ DPR_Params(0));
696 writew(0, devpriv
->io_addr
+ DPR_Params(1));
697 writew(0, devpriv
->io_addr
+ DPR_Params(2));
700 dt3k_send_cmd(dev
, CMD_CONFIG
);
703 static int dt3k_dio_insn_config(struct comedi_device
*dev
,
704 struct comedi_subdevice
*s
,
705 struct comedi_insn
*insn
, unsigned int *data
)
709 mask
= (CR_CHAN(insn
->chanspec
) < 4) ? 0x0f : 0xf0;
712 case INSN_CONFIG_DIO_OUTPUT
:
715 case INSN_CONFIG_DIO_INPUT
:
718 case INSN_CONFIG_DIO_QUERY
:
721 io_bits
& (1 << CR_CHAN(insn
->chanspec
))) ? COMEDI_OUTPUT
:
729 mask
= (s
->io_bits
& 0x01) | ((s
->io_bits
& 0x10) >> 3);
730 dt3k_dio_config(dev
, mask
);
735 static int dt3k_dio_insn_bits(struct comedi_device
*dev
,
736 struct comedi_subdevice
*s
,
737 struct comedi_insn
*insn
, unsigned int *data
)
740 s
->state
&= ~data
[0];
741 s
->state
|= data
[1] & data
[0];
742 dt3k_writesingle(dev
, SUBS_DOUT
, 0, s
->state
);
744 data
[1] = dt3k_readsingle(dev
, SUBS_DIN
, 0, 0);
749 static int dt3k_mem_insn_read(struct comedi_device
*dev
,
750 struct comedi_subdevice
*s
,
751 struct comedi_insn
*insn
, unsigned int *data
)
753 struct dt3k_private
*devpriv
= dev
->private;
754 unsigned int addr
= CR_CHAN(insn
->chanspec
);
757 for (i
= 0; i
< insn
->n
; i
++) {
758 writew(SUBS_MEM
, devpriv
->io_addr
+ DPR_SubSys
);
759 writew(addr
, devpriv
->io_addr
+ DPR_Params(0));
760 writew(1, devpriv
->io_addr
+ DPR_Params(1));
762 dt3k_send_cmd(dev
, CMD_READCODE
);
764 data
[i
] = readw(devpriv
->io_addr
+ DPR_Params(2));
770 static struct pci_dev
*dt3000_find_pci_dev(struct comedi_device
*dev
,
771 struct comedi_devconfig
*it
)
773 struct pci_dev
*pcidev
= NULL
;
774 int bus
= it
->options
[0];
775 int slot
= it
->options
[1];
778 for_each_pci_dev(pcidev
) {
780 if (bus
!= pcidev
->bus
->number
||
781 slot
!= PCI_SLOT(pcidev
->devfn
))
784 if (pcidev
->vendor
!= PCI_VENDOR_ID_DT
)
786 for (i
= 0; i
< ARRAY_SIZE(dt3k_boardtypes
); i
++) {
787 if (dt3k_boardtypes
[i
].device_id
!= pcidev
->device
)
789 dev
->board_ptr
= dt3k_boardtypes
+ i
;
793 dev_err(dev
->class_dev
,
794 "No supported board found! (req. bus %d, slot %d)\n",
799 static int dt3000_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
801 struct dt3k_private
*devpriv
;
802 struct pci_dev
*pcidev
;
803 struct comedi_subdevice
*s
;
804 resource_size_t pci_base
;
807 dev_dbg(dev
->class_dev
, "dt3000:\n");
809 ret
= alloc_private(dev
, sizeof(*devpriv
));
812 devpriv
= dev
->private;
814 pcidev
= dt3000_find_pci_dev(dev
, it
);
817 comedi_set_hw_dev(dev
, &pcidev
->dev
);
819 ret
= comedi_pci_enable(pcidev
, "dt3000");
822 dev
->iobase
= 1; /* the "detach" needs this */
824 pci_base
= pci_resource_start(pcidev
, 0);
825 devpriv
->io_addr
= ioremap(pci_base
, DT3000_SIZE
);
826 if (!devpriv
->io_addr
)
829 dev
->board_name
= this_board
->name
;
831 if (request_irq(pcidev
->irq
, dt3k_interrupt
, IRQF_SHARED
,
833 dev_err(dev
->class_dev
, "unable to allocate IRQ %u\n",
837 dev
->irq
= pcidev
->irq
;
839 ret
= comedi_alloc_subdevices(dev
, 4);
843 s
= &dev
->subdevices
[0];
844 dev
->read_subdev
= s
;
847 s
->type
= COMEDI_SUBD_AI
;
848 s
->subdev_flags
= SDF_READABLE
| SDF_GROUND
| SDF_DIFF
| SDF_CMD_READ
;
849 s
->n_chan
= this_board
->adchan
;
850 s
->insn_read
= dt3k_ai_insn
;
851 s
->maxdata
= (1 << this_board
->adbits
) - 1;
852 s
->len_chanlist
= 512;
853 s
->range_table
= &range_dt3000_ai
; /* XXX */
854 s
->do_cmd
= dt3k_ai_cmd
;
855 s
->do_cmdtest
= dt3k_ai_cmdtest
;
856 s
->cancel
= dt3k_ai_cancel
;
858 s
= &dev
->subdevices
[1];
860 s
->type
= COMEDI_SUBD_AO
;
861 s
->subdev_flags
= SDF_WRITABLE
;
863 s
->insn_read
= dt3k_ao_insn_read
;
864 s
->insn_write
= dt3k_ao_insn
;
865 s
->maxdata
= (1 << this_board
->dabits
) - 1;
867 s
->range_table
= &range_bipolar10
;
869 s
= &dev
->subdevices
[2];
871 s
->type
= COMEDI_SUBD_DIO
;
872 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
874 s
->insn_config
= dt3k_dio_insn_config
;
875 s
->insn_bits
= dt3k_dio_insn_bits
;
878 s
->range_table
= &range_digital
;
880 s
= &dev
->subdevices
[3];
882 s
->type
= COMEDI_SUBD_MEMORY
;
883 s
->subdev_flags
= SDF_READABLE
;
885 s
->insn_read
= dt3k_mem_insn_read
;
888 s
->range_table
= &range_unknown
;
891 s
= &dev
->subdevices
[4];
893 s
->type
= COMEDI_SUBD_PROC
;
899 static void dt3000_detach(struct comedi_device
*dev
)
901 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
902 struct dt3k_private
*devpriv
= dev
->private;
905 free_irq(dev
->irq
, dev
);
907 if (devpriv
->io_addr
)
908 iounmap(devpriv
->io_addr
);
912 comedi_pci_disable(pcidev
);
917 static struct comedi_driver dt3000_driver
= {
918 .driver_name
= "dt3000",
919 .module
= THIS_MODULE
,
920 .attach
= dt3000_attach
,
921 .detach
= dt3000_detach
,
924 static int __devinit
dt3000_pci_probe(struct pci_dev
*dev
,
925 const struct pci_device_id
*ent
)
927 return comedi_pci_auto_config(dev
, &dt3000_driver
);
930 static void __devexit
dt3000_pci_remove(struct pci_dev
*dev
)
932 comedi_pci_auto_unconfig(dev
);
935 static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table
) = {
936 { PCI_DEVICE(PCI_VENDOR_ID_DT
, 0x0022) },
937 { PCI_DEVICE(PCI_VENDOR_ID_DT
, 0x0027) },
938 { PCI_DEVICE(PCI_VENDOR_ID_DT
, 0x0023) },
939 { PCI_DEVICE(PCI_VENDOR_ID_DT
, 0x0024) },
940 { PCI_DEVICE(PCI_VENDOR_ID_DT
, 0x0028) },
941 { PCI_DEVICE(PCI_VENDOR_ID_DT
, 0x0025) },
942 { PCI_DEVICE(PCI_VENDOR_ID_DT
, 0x0026) },
945 MODULE_DEVICE_TABLE(pci
, dt3000_pci_table
);
947 static struct pci_driver dt3000_pci_driver
= {
949 .id_table
= dt3000_pci_table
,
950 .probe
= dt3000_pci_probe
,
951 .remove
= __devexit_p(dt3000_pci_remove
),
953 module_comedi_pci_driver(dt3000_driver
, dt3000_pci_driver
);
955 MODULE_AUTHOR("Comedi http://www.comedi.org");
956 MODULE_DESCRIPTION("Comedi low-level driver");
957 MODULE_LICENSE("GPL");