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, {
77
static const struct comedi_lrange range_dt3000_ai_pgl = { 4, {
85
struct dt3k_boardtype {
88
unsigned int device_id;
92
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) = {
168
{PCI_VENDOR_ID_DT, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
169
{PCI_VENDOR_ID_DT, 0x0027, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
170
{PCI_VENDOR_ID_DT, 0x0023, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
171
{PCI_VENDOR_ID_DT, 0x0024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
172
{PCI_VENDOR_ID_DT, 0x0028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
173
{PCI_VENDOR_ID_DT, 0x0025, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
174
{PCI_VENDOR_ID_DT, 0x0026, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
178
MODULE_DEVICE_TABLE(pci, dt3k_pci_table);
180
#define DT3000_SIZE (4*0x1000)
182
/* dual-ported RAM location definitions */
184
#define DPR_DAC_buffer (4*0x000)
185
#define DPR_ADC_buffer (4*0x800)
186
#define DPR_Command (4*0xfd3)
187
#define DPR_SubSys (4*0xfd3)
188
#define DPR_Encode (4*0xfd4)
189
#define DPR_Params(a) (4*(0xfd5+(a)))
190
#define DPR_Tick_Reg_Lo (4*0xff5)
191
#define DPR_Tick_Reg_Hi (4*0xff6)
192
#define DPR_DA_Buf_Front (4*0xff7)
193
#define DPR_DA_Buf_Rear (4*0xff8)
194
#define DPR_AD_Buf_Front (4*0xff9)
195
#define DPR_AD_Buf_Rear (4*0xffa)
196
#define DPR_Int_Mask (4*0xffb)
197
#define DPR_Intr_Flag (4*0xffc)
198
#define DPR_Response_Mbx (4*0xffe)
199
#define DPR_Command_Mbx (4*0xfff)
201
#define AI_FIFO_DEPTH 2003
202
#define AO_FIFO_DEPTH 2048
206
#define CMD_GETBRDINFO 0
208
#define CMD_GETCONFIG 2
211
#define CMD_READSINGLE 5
212
#define CMD_WRITESINGLE 6
213
#define CMD_CALCCLOCK 7
214
#define CMD_READEVENTS 8
215
#define CMD_WRITECTCTRL 16
216
#define CMD_READCTCTRL 17
217
#define CMD_WRITECT 18
218
#define CMD_READCT 19
219
#define CMD_WRITEDATA 32
220
#define CMD_READDATA 33
221
#define CMD_WRITEIO 34
222
#define CMD_READIO 35
223
#define CMD_WRITECODE 36
224
#define CMD_READCODE 37
225
#define CMD_EXECUTE 38
235
/* interrupt flags */
236
#define DT3000_CMDONE 0x80
237
#define DT3000_CTDONE 0x40
238
#define DT3000_DAHWERR 0x20
239
#define DT3000_DASWERR 0x10
240
#define DT3000_DAEMPTY 0x08
241
#define DT3000_ADHWERR 0x04
242
#define DT3000_ADSWERR 0x02
243
#define DT3000_ADFULL 0x01
245
#define DT3000_COMPLETION_MASK 0xff00
246
#define DT3000_COMMAND_MASK 0x00ff
247
#define DT3000_NOTPROCESSED 0x0000
248
#define DT3000_NOERROR 0x5500
249
#define DT3000_ERROR 0xaa00
250
#define DT3000_NOTSUPPORTED 0xff00
252
#define DT3000_EXTERNAL_CLOCK 1
253
#define DT3000_RISING_EDGE 2
255
#define TMODE_MASK 0x1c
257
#define DT3000_AD_TRIG_INTERNAL (0<<2)
258
#define DT3000_AD_TRIG_EXTERNAL (1<<2)
259
#define DT3000_AD_RETRIG_INTERNAL (2<<2)
260
#define DT3000_AD_RETRIG_EXTERNAL (3<<2)
261
#define DT3000_AD_EXTRETRIG (4<<2)
263
#define DT3000_CHANNEL_MODE_SE 0
264
#define DT3000_CHANNEL_MODE_DI 1
266
struct dt3k_private {
268
struct pci_dev *pci_dev;
269
resource_size_t phys_addr;
272
unsigned int ao_readback[2];
273
unsigned int ai_front;
274
unsigned int ai_rear;
277
#define devpriv ((struct dt3k_private *)dev->private)
279
static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it);
280
static int dt3000_detach(struct comedi_device *dev);
281
static struct comedi_driver driver_dt3000 = {
282
.driver_name = "dt3000",
283
.module = THIS_MODULE,
284
.attach = dt3000_attach,
285
.detach = dt3000_detach,
288
COMEDI_PCI_INITCLEANUP(driver_dt3000, dt3k_pci_table);
290
static void dt3k_ai_empty_fifo(struct comedi_device *dev, struct comedi_subdevice *s);
291
static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
292
unsigned int round_mode);
293
static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
295
static void debug_intr_flags(unsigned int flags);
300
static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
303
unsigned int status = 0;
305
writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
307
for (i = 0; i < TIMEOUT; i++) {
308
status = readw(devpriv->io_addr + DPR_Command_Mbx);
309
if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
313
if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR) {
317
printk("dt3k_send_cmd() timeout/error status=0x%04x\n", status);
322
static unsigned int dt3k_readsingle(struct comedi_device *dev, unsigned int subsys,
323
unsigned int chan, unsigned int gain)
325
writew(subsys, devpriv->io_addr + DPR_SubSys);
327
writew(chan, devpriv->io_addr + DPR_Params(0));
328
writew(gain, devpriv->io_addr + DPR_Params(1));
330
dt3k_send_cmd(dev, CMD_READSINGLE);
332
return readw(devpriv->io_addr + DPR_Params(2));
335
static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
336
unsigned int chan, unsigned int data)
338
writew(subsys, devpriv->io_addr + DPR_SubSys);
340
writew(chan, devpriv->io_addr + DPR_Params(0));
341
writew(0, devpriv->io_addr + DPR_Params(1));
342
writew(data, devpriv->io_addr + DPR_Params(2));
344
dt3k_send_cmd(dev, CMD_WRITESINGLE);
347
static int debug_n_ints = 0;
349
/* FIXME! Assumes shared interrupt is for this card. */
350
/* What's this debug_n_ints stuff? Obviously needs some work... */
351
static irqreturn_t dt3k_interrupt(int irq, void *d)
353
struct comedi_device *dev = d;
354
struct comedi_subdevice *s;
357
if (!dev->attached) {
361
s = dev->subdevices + 0;
362
status = readw(devpriv->io_addr + DPR_Intr_Flag);
364
debug_intr_flags(status);
367
if (status & DT3000_ADFULL) {
368
dt3k_ai_empty_fifo(dev, s);
369
s->async->events |= COMEDI_CB_BLOCK;
372
if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) {
373
s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
377
if (debug_n_ints >= 10) {
378
dt3k_ai_cancel(dev, s);
379
s->async->events |= COMEDI_CB_EOA;
382
comedi_event(dev, s);
387
static char *intr_flags[] = {
388
"AdFull", "AdSwError", "AdHwError", "DaEmpty",
389
"DaSwError", "DaHwError", "CtDone", "CmDone",
391
static void debug_intr_flags(unsigned int flags)
394
printk("dt3k: intr_flags:");
395
for (i = 0; i < 8; i++) {
396
if (flags & (1 << i)) {
397
printk(" %s", intr_flags[i]);
404
static void dt3k_ai_empty_fifo(struct comedi_device *dev, struct comedi_subdevice *s)
412
front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
413
count = front - devpriv->ai_front;
415
count += AI_FIFO_DEPTH;
417
printk("reading %d samples\n", count);
419
rear = devpriv->ai_rear;
421
for (i = 0; i < count; i++) {
422
data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
423
comedi_buf_put(s->async, data);
425
if (rear >= AI_FIFO_DEPTH)
429
devpriv->ai_rear = rear;
430
writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
433
static int dt3k_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
434
struct comedi_cmd *cmd)
439
/* step 1: make sure trigger sources are trivially valid */
441
tmp = cmd->start_src;
442
cmd->start_src &= TRIG_NOW;
443
if (!cmd->start_src || tmp != cmd->start_src)
446
tmp = cmd->scan_begin_src;
447
cmd->scan_begin_src &= TRIG_TIMER;
448
if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
451
tmp = cmd->convert_src;
452
cmd->convert_src &= TRIG_TIMER;
453
if (!cmd->convert_src || tmp != cmd->convert_src)
456
tmp = cmd->scan_end_src;
457
cmd->scan_end_src &= TRIG_COUNT;
458
if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
462
cmd->stop_src &= TRIG_COUNT;
463
if (!cmd->stop_src || tmp != cmd->stop_src)
469
/* step 2: make sure trigger sources are unique and mutually compatible */
474
/* step 3: make sure arguments are trivially compatible */
476
if (cmd->start_arg != 0) {
481
if (cmd->scan_begin_src == TRIG_TIMER) {
482
if (cmd->scan_begin_arg < this_board->ai_speed) {
483
cmd->scan_begin_arg = this_board->ai_speed;
486
if (cmd->scan_begin_arg > 100 * 16 * 65535) {
487
cmd->scan_begin_arg = 100 * 16 * 65535;
493
if (cmd->convert_src == TRIG_TIMER) {
494
if (cmd->convert_arg < this_board->ai_speed) {
495
cmd->convert_arg = this_board->ai_speed;
498
if (cmd->convert_arg > 50 * 16 * 65535) {
499
cmd->convert_arg = 50 * 16 * 65535;
506
if (cmd->scan_end_arg != cmd->chanlist_len) {
507
cmd->scan_end_arg = cmd->chanlist_len;
510
if (cmd->stop_src == TRIG_COUNT) {
511
if (cmd->stop_arg > 0x00ffffff) {
512
cmd->stop_arg = 0x00ffffff;
517
if (cmd->stop_arg != 0) {
526
/* step 4: fix up any arguments */
528
if (cmd->scan_begin_src == TRIG_TIMER) {
529
tmp = cmd->scan_begin_arg;
530
dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
531
cmd->flags & TRIG_ROUND_MASK);
532
if (tmp != cmd->scan_begin_arg)
537
if (cmd->convert_src == TRIG_TIMER) {
538
tmp = cmd->convert_arg;
539
dt3k_ns_to_timer(50, &cmd->convert_arg,
540
cmd->flags & TRIG_ROUND_MASK);
541
if (tmp != cmd->convert_arg)
543
if (cmd->scan_begin_src == TRIG_TIMER &&
544
cmd->scan_begin_arg <
545
cmd->convert_arg * cmd->scan_end_arg) {
546
cmd->scan_begin_arg =
547
cmd->convert_arg * cmd->scan_end_arg;
560
static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
561
unsigned int round_mode)
563
int divider, base, prescale;
565
/* This function needs improvment */
566
/* Don't know if divider==0 works. */
568
for (prescale = 0; prescale < 16; prescale++) {
569
base = timer_base * (prescale + 1);
570
switch (round_mode) {
571
case TRIG_ROUND_NEAREST:
573
divider = (*nanosec + base / 2) / base;
575
case TRIG_ROUND_DOWN:
576
divider = (*nanosec) / base;
579
divider = (*nanosec) / base;
582
if (divider < 65536) {
583
*nanosec = divider * base;
584
return (prescale << 16) | (divider);
589
base = timer_base * (1 << prescale);
591
*nanosec = divider * base;
592
return (prescale << 16) | (divider);
595
static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
597
struct comedi_cmd *cmd = &s->async->cmd;
599
unsigned int chan, range, aref;
600
unsigned int divider;
601
unsigned int tscandiv;
605
printk("dt3k_ai_cmd:\n");
606
for (i = 0; i < cmd->chanlist_len; i++) {
607
chan = CR_CHAN(cmd->chanlist[i]);
608
range = CR_RANGE(cmd->chanlist[i]);
610
writew((range << 6) | chan,
611
devpriv->io_addr + DPR_ADC_buffer + i);
613
aref = CR_AREF(cmd->chanlist[0]);
615
writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
616
printk("param[0]=0x%04x\n", cmd->scan_end_arg);
618
if (cmd->convert_src == TRIG_TIMER) {
619
divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
620
cmd->flags & TRIG_ROUND_MASK);
621
writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
622
printk("param[1]=0x%04x\n", divider >> 16);
623
writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
624
printk("param[2]=0x%04x\n", divider & 0xffff);
629
if (cmd->scan_begin_src == TRIG_TIMER) {
630
tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
631
cmd->flags & TRIG_ROUND_MASK);
632
writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
633
printk("param[3]=0x%04x\n", tscandiv >> 16);
634
writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
635
printk("param[4]=0x%04x\n", tscandiv & 0xffff);
640
mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
641
writew(mode, devpriv->io_addr + DPR_Params(5));
642
printk("param[5]=0x%04x\n", mode);
643
writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
644
printk("param[6]=0x%04x\n", aref == AREF_DIFF);
646
writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
647
printk("param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
649
writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
650
ret = dt3k_send_cmd(dev, CMD_CONFIG);
652
writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
653
devpriv->io_addr + DPR_Int_Mask);
657
writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
658
ret = dt3k_send_cmd(dev, CMD_START);
663
static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
667
writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
668
ret = dt3k_send_cmd(dev, CMD_STOP);
670
writew(0, devpriv->io_addr + DPR_Int_Mask);
675
static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
676
struct comedi_insn *insn, unsigned int *data)
679
unsigned int chan, gain, aref;
681
chan = CR_CHAN(insn->chanspec);
682
gain = CR_RANGE(insn->chanspec);
683
/* XXX docs don't explain how to select aref */
684
aref = CR_AREF(insn->chanspec);
686
for (i = 0; i < insn->n; i++) {
687
data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
693
static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
694
struct comedi_insn *insn, unsigned int *data)
699
chan = CR_CHAN(insn->chanspec);
700
for (i = 0; i < insn->n; i++) {
701
dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
702
devpriv->ao_readback[chan] = data[i];
708
static int dt3k_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
709
struct comedi_insn *insn, unsigned int *data)
714
chan = CR_CHAN(insn->chanspec);
715
for (i = 0; i < insn->n; i++) {
716
data[i] = devpriv->ao_readback[chan];
722
static void dt3k_dio_config(struct comedi_device *dev, int bits)
725
writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
727
writew(bits, devpriv->io_addr + DPR_Params(0));
730
writew(0, devpriv->io_addr + DPR_Params(1));
731
writew(0, devpriv->io_addr + DPR_Params(2));
734
dt3k_send_cmd(dev, CMD_CONFIG);
737
static int dt3k_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
738
struct comedi_insn *insn, unsigned int *data)
742
mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
745
case INSN_CONFIG_DIO_OUTPUT:
748
case INSN_CONFIG_DIO_INPUT:
751
case INSN_CONFIG_DIO_QUERY:
753
(s->io_bits & (1 << CR_CHAN(insn->
754
chanspec))) ? COMEDI_OUTPUT :
762
mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
763
dt3k_dio_config(dev, mask);
768
static int dt3k_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
769
struct comedi_insn *insn, unsigned int *data)
775
s->state &= ~data[0];
776
s->state |= data[1] & data[0];
777
dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
779
data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
784
static int dt3k_mem_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
785
struct comedi_insn *insn, unsigned int *data)
787
unsigned int addr = CR_CHAN(insn->chanspec);
790
for (i = 0; i < insn->n; i++) {
791
writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
792
writew(addr, devpriv->io_addr + DPR_Params(0));
793
writew(1, devpriv->io_addr + DPR_Params(1));
795
dt3k_send_cmd(dev, CMD_READCODE);
797
data[i] = readw(devpriv->io_addr + DPR_Params(2));
803
static int dt_pci_probe(struct comedi_device *dev, int bus, int slot);
805
static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
807
struct comedi_subdevice *s;
812
bus = it->options[0];
813
slot = it->options[1];
815
ret = alloc_private(dev, sizeof(struct dt3k_private));
819
ret = dt_pci_probe(dev, bus, slot);
823
printk(" no DT board found\n");
827
dev->board_name = this_board->name;
829
if (request_irq(devpriv->pci_dev->irq, dt3k_interrupt, IRQF_SHARED,
831
printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq);
834
dev->irq = devpriv->pci_dev->irq;
836
ret = alloc_subdevices(dev, 4);
841
dev->read_subdev = s;
844
s->type = COMEDI_SUBD_AI;
845
s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
846
s->n_chan = this_board->adchan;
847
s->insn_read = dt3k_ai_insn;
848
s->maxdata = (1 << this_board->adbits) - 1;
849
s->len_chanlist = 512;
850
s->range_table = &range_dt3000_ai; /* XXX */
851
s->do_cmd = dt3k_ai_cmd;
852
s->do_cmdtest = dt3k_ai_cmdtest;
853
s->cancel = dt3k_ai_cancel;
857
s->type = COMEDI_SUBD_AO;
858
s->subdev_flags = SDF_WRITABLE;
860
s->insn_read = dt3k_ao_insn_read;
861
s->insn_write = dt3k_ao_insn;
862
s->maxdata = (1 << this_board->dabits) - 1;
864
s->range_table = &range_bipolar10;
868
s->type = COMEDI_SUBD_DIO;
869
s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
871
s->insn_config = dt3k_dio_insn_config;
872
s->insn_bits = dt3k_dio_insn_bits;
875
s->range_table = &range_digital;
879
s->type = COMEDI_SUBD_MEMORY;
880
s->subdev_flags = SDF_READABLE;
882
s->insn_read = dt3k_mem_insn_read;
885
s->range_table = &range_unknown;
890
s->type = COMEDI_SUBD_PROC;
896
static int dt3000_detach(struct comedi_device *dev)
899
free_irq(dev->irq, dev);
902
if (devpriv->pci_dev) {
903
if (devpriv->phys_addr) {
904
comedi_pci_disable(devpriv->pci_dev);
906
pci_dev_put(devpriv->pci_dev);
908
if (devpriv->io_addr)
909
iounmap(devpriv->io_addr);
916
static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
917
static int setup_pci(struct comedi_device *dev);
919
static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
923
struct pci_dev *pcidev;
926
while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
927
if ((bus == 0 && slot == 0) ||
928
(pcidev->bus->number == bus &&
929
PCI_SLOT(pcidev->devfn) == slot)) {
933
devpriv->pci_dev = pcidev;
936
dev->board_ptr = dt3k_boardtypes + board;
938
if (!devpriv->pci_dev)
941
ret = setup_pci(dev);
948
static int setup_pci(struct comedi_device *dev)
950
resource_size_t addr;
953
ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
957
addr = pci_resource_start(devpriv->pci_dev, 0);
958
devpriv->phys_addr = addr;
959
devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
960
if (!devpriv->io_addr)
963
printk("0x%08llx mapped to %p, ",
964
(unsigned long long)devpriv->phys_addr, devpriv->io_addr);
970
static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
974
for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
976
from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
977
for (i = 0; i < n_dt3k_boards; i++) {
978
if (from->device == dt3k_boardtypes[i].device_id) {
983
printk("unknown Data Translation PCI device found with device_id=0x%04x\n", from->device);