1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52#include <linux/module.h>
53#include <linux/delay.h>
54#include <linux/interrupt.h>
55
56#include "../comedi_pci.h"
57
58
59
60
61#define DPR_DAC_BUFFER (4 * 0x000)
62#define DPR_ADC_BUFFER (4 * 0x800)
63#define DPR_COMMAND (4 * 0xfd3)
64#define DPR_SUBSYS (4 * 0xfd3)
65#define DPR_SUBSYS_AI 0
66#define DPR_SUBSYS_AO 1
67#define DPR_SUBSYS_DIN 2
68#define DPR_SUBSYS_DOUT 3
69#define DPR_SUBSYS_MEM 4
70#define DPR_SUBSYS_CT 5
71#define DPR_ENCODE (4 * 0xfd4)
72#define DPR_PARAMS(x) (4 * (0xfd5 + (x)))
73#define DPR_TICK_REG_LO (4 * 0xff5)
74#define DPR_TICK_REG_HI (4 * 0xff6)
75#define DPR_DA_BUF_FRONT (4 * 0xff7)
76#define DPR_DA_BUF_REAR (4 * 0xff8)
77#define DPR_AD_BUF_FRONT (4 * 0xff9)
78#define DPR_AD_BUF_REAR (4 * 0xffa)
79#define DPR_INT_MASK (4 * 0xffb)
80#define DPR_INTR_FLAG (4 * 0xffc)
81#define DPR_INTR_CMDONE BIT(7)
82#define DPR_INTR_CTDONE BIT(6)
83#define DPR_INTR_DAHWERR BIT(5)
84#define DPR_INTR_DASWERR BIT(4)
85#define DPR_INTR_DAEMPTY BIT(3)
86#define DPR_INTR_ADHWERR BIT(2)
87#define DPR_INTR_ADSWERR BIT(1)
88#define DPR_INTR_ADFULL BIT(0)
89#define DPR_RESPONSE_MBX (4 * 0xffe)
90#define DPR_CMD_MBX (4 * 0xfff)
91#define DPR_CMD_COMPLETION(x) ((x) << 8)
92#define DPR_CMD_NOTPROCESSED DPR_CMD_COMPLETION(0x00)
93#define DPR_CMD_NOERROR DPR_CMD_COMPLETION(0x55)
94#define DPR_CMD_ERROR DPR_CMD_COMPLETION(0xaa)
95#define DPR_CMD_NOTSUPPORTED DPR_CMD_COMPLETION(0xff)
96#define DPR_CMD_COMPLETION_MASK DPR_CMD_COMPLETION(0xff)
97#define DPR_CMD(x) ((x) << 0)
98#define DPR_CMD_GETBRDINFO DPR_CMD(0)
99#define DPR_CMD_CONFIG DPR_CMD(1)
100#define DPR_CMD_GETCONFIG DPR_CMD(2)
101#define DPR_CMD_START DPR_CMD(3)
102#define DPR_CMD_STOP DPR_CMD(4)
103#define DPR_CMD_READSINGLE DPR_CMD(5)
104#define DPR_CMD_WRITESINGLE DPR_CMD(6)
105#define DPR_CMD_CALCCLOCK DPR_CMD(7)
106#define DPR_CMD_READEVENTS DPR_CMD(8)
107#define DPR_CMD_WRITECTCTRL DPR_CMD(16)
108#define DPR_CMD_READCTCTRL DPR_CMD(17)
109#define DPR_CMD_WRITECT DPR_CMD(18)
110#define DPR_CMD_READCT DPR_CMD(19)
111#define DPR_CMD_WRITEDATA DPR_CMD(32)
112#define DPR_CMD_READDATA DPR_CMD(33)
113#define DPR_CMD_WRITEIO DPR_CMD(34)
114#define DPR_CMD_READIO DPR_CMD(35)
115#define DPR_CMD_WRITECODE DPR_CMD(36)
116#define DPR_CMD_READCODE DPR_CMD(37)
117#define DPR_CMD_EXECUTE DPR_CMD(38)
118#define DPR_CMD_HALT DPR_CMD(48)
119#define DPR_CMD_MASK DPR_CMD(0xff)
120
121#define DPR_PARAM5_AD_TRIG(x) (((x) & 0x7) << 2)
122#define DPR_PARAM5_AD_TRIG_INT DPR_PARAM5_AD_TRIG(0)
123#define DPR_PARAM5_AD_TRIG_EXT DPR_PARAM5_AD_TRIG(1)
124#define DPR_PARAM5_AD_TRIG_INT_RETRIG DPR_PARAM5_AD_TRIG(2)
125#define DPR_PARAM5_AD_TRIG_EXT_RETRIG DPR_PARAM5_AD_TRIG(3)
126#define DPR_PARAM5_AD_TRIG_INT_RETRIG2 DPR_PARAM5_AD_TRIG(4)
127
128#define DPR_PARAM6_AD_DIFF BIT(0)
129
130#define DPR_AI_FIFO_DEPTH 2003
131#define DPR_AO_FIFO_DEPTH 2048
132
133#define DPR_EXTERNAL_CLOCK 1
134#define DPR_RISING_EDGE 2
135
136#define DPR_TMODE_MASK 0x1c
137
138#define DPR_CMD_TIMEOUT 100
139
140static const struct comedi_lrange range_dt3000_ai = {
141 4, {
142 BIP_RANGE(10),
143 BIP_RANGE(5),
144 BIP_RANGE(2.5),
145 BIP_RANGE(1.25)
146 }
147};
148
149static const struct comedi_lrange range_dt3000_ai_pgl = {
150 4, {
151 BIP_RANGE(10),
152 BIP_RANGE(1),
153 BIP_RANGE(0.1),
154 BIP_RANGE(0.02)
155 }
156};
157
158enum dt3k_boardid {
159 BOARD_DT3001,
160 BOARD_DT3001_PGL,
161 BOARD_DT3002,
162 BOARD_DT3003,
163 BOARD_DT3003_PGL,
164 BOARD_DT3004,
165 BOARD_DT3005,
166};
167
168struct dt3k_boardtype {
169 const char *name;
170 int adchan;
171 int ai_speed;
172 const struct comedi_lrange *adrange;
173 unsigned int ai_is_16bit:1;
174 unsigned int has_ao:1;
175};
176
177static const struct dt3k_boardtype dt3k_boardtypes[] = {
178 [BOARD_DT3001] = {
179 .name = "dt3001",
180 .adchan = 16,
181 .adrange = &range_dt3000_ai,
182 .ai_speed = 3000,
183 .has_ao = 1,
184 },
185 [BOARD_DT3001_PGL] = {
186 .name = "dt3001-pgl",
187 .adchan = 16,
188 .adrange = &range_dt3000_ai_pgl,
189 .ai_speed = 3000,
190 .has_ao = 1,
191 },
192 [BOARD_DT3002] = {
193 .name = "dt3002",
194 .adchan = 32,
195 .adrange = &range_dt3000_ai,
196 .ai_speed = 3000,
197 },
198 [BOARD_DT3003] = {
199 .name = "dt3003",
200 .adchan = 64,
201 .adrange = &range_dt3000_ai,
202 .ai_speed = 3000,
203 .has_ao = 1,
204 },
205 [BOARD_DT3003_PGL] = {
206 .name = "dt3003-pgl",
207 .adchan = 64,
208 .adrange = &range_dt3000_ai_pgl,
209 .ai_speed = 3000,
210 .has_ao = 1,
211 },
212 [BOARD_DT3004] = {
213 .name = "dt3004",
214 .adchan = 16,
215 .adrange = &range_dt3000_ai,
216 .ai_speed = 10000,
217 .ai_is_16bit = 1,
218 .has_ao = 1,
219 },
220 [BOARD_DT3005] = {
221 .name = "dt3005",
222 .adchan = 16,
223 .adrange = &range_dt3000_ai,
224 .ai_speed = 5000,
225 .ai_is_16bit = 1,
226 .has_ao = 1,
227 },
228};
229
230struct dt3k_private {
231 unsigned int lock;
232 unsigned int ai_front;
233 unsigned int ai_rear;
234};
235
236static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
237{
238 int i;
239 unsigned int status = 0;
240
241 writew(cmd, dev->mmio + DPR_CMD_MBX);
242
243 for (i = 0; i < DPR_CMD_TIMEOUT; i++) {
244 status = readw(dev->mmio + DPR_CMD_MBX);
245 status &= DPR_CMD_COMPLETION_MASK;
246 if (status != DPR_CMD_NOTPROCESSED)
247 break;
248 udelay(1);
249 }
250
251 if (status != DPR_CMD_NOERROR)
252 dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n",
253 __func__, status);
254}
255
256static unsigned int dt3k_readsingle(struct comedi_device *dev,
257 unsigned int subsys, unsigned int chan,
258 unsigned int gain)
259{
260 writew(subsys, dev->mmio + DPR_SUBSYS);
261
262 writew(chan, dev->mmio + DPR_PARAMS(0));
263 writew(gain, dev->mmio + DPR_PARAMS(1));
264
265 dt3k_send_cmd(dev, DPR_CMD_READSINGLE);
266
267 return readw(dev->mmio + DPR_PARAMS(2));
268}
269
270static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
271 unsigned int chan, unsigned int data)
272{
273 writew(subsys, dev->mmio + DPR_SUBSYS);
274
275 writew(chan, dev->mmio + DPR_PARAMS(0));
276 writew(0, dev->mmio + DPR_PARAMS(1));
277 writew(data, dev->mmio + DPR_PARAMS(2));
278
279 dt3k_send_cmd(dev, DPR_CMD_WRITESINGLE);
280}
281
282static void dt3k_ai_empty_fifo(struct comedi_device *dev,
283 struct comedi_subdevice *s)
284{
285 struct dt3k_private *devpriv = dev->private;
286 int front;
287 int rear;
288 int count;
289 int i;
290 unsigned short data;
291
292 front = readw(dev->mmio + DPR_AD_BUF_FRONT);
293 count = front - devpriv->ai_front;
294 if (count < 0)
295 count += DPR_AI_FIFO_DEPTH;
296
297 rear = devpriv->ai_rear;
298
299 for (i = 0; i < count; i++) {
300 data = readw(dev->mmio + DPR_ADC_BUFFER + rear);
301 comedi_buf_write_samples(s, &data, 1);
302 rear++;
303 if (rear >= DPR_AI_FIFO_DEPTH)
304 rear = 0;
305 }
306
307 devpriv->ai_rear = rear;
308 writew(rear, dev->mmio + DPR_AD_BUF_REAR);
309}
310
311static int dt3k_ai_cancel(struct comedi_device *dev,
312 struct comedi_subdevice *s)
313{
314 writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS);
315 dt3k_send_cmd(dev, DPR_CMD_STOP);
316
317 writew(0, dev->mmio + DPR_INT_MASK);
318
319 return 0;
320}
321
322static int debug_n_ints;
323
324
325
326static irqreturn_t dt3k_interrupt(int irq, void *d)
327{
328 struct comedi_device *dev = d;
329 struct comedi_subdevice *s = dev->read_subdev;
330 unsigned int status;
331
332 if (!dev->attached)
333 return IRQ_NONE;
334
335 status = readw(dev->mmio + DPR_INTR_FLAG);
336
337 if (status & DPR_INTR_ADFULL)
338 dt3k_ai_empty_fifo(dev, s);
339
340 if (status & (DPR_INTR_ADSWERR | DPR_INTR_ADHWERR))
341 s->async->events |= COMEDI_CB_ERROR;
342
343 debug_n_ints++;
344 if (debug_n_ints >= 10)
345 s->async->events |= COMEDI_CB_EOA;
346
347 comedi_handle_events(dev, s);
348 return IRQ_HANDLED;
349}
350
351static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
352 unsigned int flags)
353{
354 int divider, base, prescale;
355
356
357
358
359 for (prescale = 0; prescale < 16; prescale++) {
360 base = timer_base * (prescale + 1);
361 switch (flags & CMDF_ROUND_MASK) {
362 case CMDF_ROUND_NEAREST:
363 default:
364 divider = DIV_ROUND_CLOSEST(*nanosec, base);
365 break;
366 case CMDF_ROUND_DOWN:
367 divider = (*nanosec) / base;
368 break;
369 case CMDF_ROUND_UP:
370 divider = (*nanosec) / base;
371 break;
372 }
373 if (divider < 65536) {
374 *nanosec = divider * base;
375 return (prescale << 16) | (divider);
376 }
377 }
378
379 prescale = 15;
380 base = timer_base * (1 << prescale);
381 divider = 65535;
382 *nanosec = divider * base;
383 return (prescale << 16) | (divider);
384}
385
386static int dt3k_ai_cmdtest(struct comedi_device *dev,
387 struct comedi_subdevice *s, struct comedi_cmd *cmd)
388{
389 const struct dt3k_boardtype *board = dev->board_ptr;
390 int err = 0;
391 unsigned int arg;
392
393
394
395 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
396 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
397 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
398 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
399 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
400
401 if (err)
402 return 1;
403
404
405
406
407
408
409 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
410
411 if (cmd->scan_begin_src == TRIG_TIMER) {
412 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
413 board->ai_speed);
414 err |= comedi_check_trigger_arg_max(&cmd->scan_begin_arg,
415 100 * 16 * 65535);
416 }
417
418 if (cmd->convert_src == TRIG_TIMER) {
419 err |= comedi_check_trigger_arg_min(&cmd->convert_arg,
420 board->ai_speed);
421 err |= comedi_check_trigger_arg_max(&cmd->convert_arg,
422 50 * 16 * 65535);
423 }
424
425 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
426 cmd->chanlist_len);
427
428 if (cmd->stop_src == TRIG_COUNT)
429 err |= comedi_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
430 else
431 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
432
433 if (err)
434 return 3;
435
436
437
438 if (cmd->scan_begin_src == TRIG_TIMER) {
439 arg = cmd->scan_begin_arg;
440 dt3k_ns_to_timer(100, &arg, cmd->flags);
441 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
442 }
443
444 if (cmd->convert_src == TRIG_TIMER) {
445 arg = cmd->convert_arg;
446 dt3k_ns_to_timer(50, &arg, cmd->flags);
447 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
448
449 if (cmd->scan_begin_src == TRIG_TIMER) {
450 arg = cmd->convert_arg * cmd->scan_end_arg;
451 err |= comedi_check_trigger_arg_min(&cmd->
452 scan_begin_arg,
453 arg);
454 }
455 }
456
457 if (err)
458 return 4;
459
460 return 0;
461}
462
463static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
464{
465 struct comedi_cmd *cmd = &s->async->cmd;
466 int i;
467 unsigned int chan, range, aref;
468 unsigned int divider;
469 unsigned int tscandiv;
470
471 for (i = 0; i < cmd->chanlist_len; i++) {
472 chan = CR_CHAN(cmd->chanlist[i]);
473 range = CR_RANGE(cmd->chanlist[i]);
474
475 writew((range << 6) | chan, dev->mmio + DPR_ADC_BUFFER + i);
476 }
477 aref = CR_AREF(cmd->chanlist[0]);
478
479 writew(cmd->scan_end_arg, dev->mmio + DPR_PARAMS(0));
480
481 if (cmd->convert_src == TRIG_TIMER) {
482 divider = dt3k_ns_to_timer(50, &cmd->convert_arg, cmd->flags);
483 writew((divider >> 16), dev->mmio + DPR_PARAMS(1));
484 writew((divider & 0xffff), dev->mmio + DPR_PARAMS(2));
485 }
486
487 if (cmd->scan_begin_src == TRIG_TIMER) {
488 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
489 cmd->flags);
490 writew((tscandiv >> 16), dev->mmio + DPR_PARAMS(3));
491 writew((tscandiv & 0xffff), dev->mmio + DPR_PARAMS(4));
492 }
493
494 writew(DPR_PARAM5_AD_TRIG_INT_RETRIG, dev->mmio + DPR_PARAMS(5));
495 writew((aref == AREF_DIFF) ? DPR_PARAM6_AD_DIFF : 0,
496 dev->mmio + DPR_PARAMS(6));
497
498 writew(DPR_AI_FIFO_DEPTH / 2, dev->mmio + DPR_PARAMS(7));
499
500 writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS);
501 dt3k_send_cmd(dev, DPR_CMD_CONFIG);
502
503 writew(DPR_INTR_ADFULL | DPR_INTR_ADSWERR | DPR_INTR_ADHWERR,
504 dev->mmio + DPR_INT_MASK);
505
506 debug_n_ints = 0;
507
508 writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS);
509 dt3k_send_cmd(dev, DPR_CMD_START);
510
511 return 0;
512}
513
514static int dt3k_ai_insn_read(struct comedi_device *dev,
515 struct comedi_subdevice *s,
516 struct comedi_insn *insn,
517 unsigned int *data)
518{
519 int i;
520 unsigned int chan, gain, aref;
521
522 chan = CR_CHAN(insn->chanspec);
523 gain = CR_RANGE(insn->chanspec);
524
525 aref = CR_AREF(insn->chanspec);
526
527 for (i = 0; i < insn->n; i++)
528 data[i] = dt3k_readsingle(dev, DPR_SUBSYS_AI, chan, gain);
529
530 return i;
531}
532
533static int dt3k_ao_insn_write(struct comedi_device *dev,
534 struct comedi_subdevice *s,
535 struct comedi_insn *insn,
536 unsigned int *data)
537{
538 unsigned int chan = CR_CHAN(insn->chanspec);
539 unsigned int val = s->readback[chan];
540 int i;
541
542 for (i = 0; i < insn->n; i++) {
543 val = data[i];
544 dt3k_writesingle(dev, DPR_SUBSYS_AO, chan, val);
545 }
546 s->readback[chan] = val;
547
548 return insn->n;
549}
550
551static void dt3k_dio_config(struct comedi_device *dev, int bits)
552{
553
554 writew(DPR_SUBSYS_DOUT, dev->mmio + DPR_SUBSYS);
555
556 writew(bits, dev->mmio + DPR_PARAMS(0));
557
558
559
560 dt3k_send_cmd(dev, DPR_CMD_CONFIG);
561}
562
563static int dt3k_dio_insn_config(struct comedi_device *dev,
564 struct comedi_subdevice *s,
565 struct comedi_insn *insn,
566 unsigned int *data)
567{
568 unsigned int chan = CR_CHAN(insn->chanspec);
569 unsigned int mask;
570 int ret;
571
572 if (chan < 4)
573 mask = 0x0f;
574 else
575 mask = 0xf0;
576
577 ret = comedi_dio_insn_config(dev, s, insn, data, mask);
578 if (ret)
579 return ret;
580
581 dt3k_dio_config(dev, (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3));
582
583 return insn->n;
584}
585
586static int dt3k_dio_insn_bits(struct comedi_device *dev,
587 struct comedi_subdevice *s,
588 struct comedi_insn *insn,
589 unsigned int *data)
590{
591 if (comedi_dio_update_state(s, data))
592 dt3k_writesingle(dev, DPR_SUBSYS_DOUT, 0, s->state);
593
594 data[1] = dt3k_readsingle(dev, DPR_SUBSYS_DIN, 0, 0);
595
596 return insn->n;
597}
598
599static int dt3k_mem_insn_read(struct comedi_device *dev,
600 struct comedi_subdevice *s,
601 struct comedi_insn *insn,
602 unsigned int *data)
603{
604 unsigned int addr = CR_CHAN(insn->chanspec);
605 int i;
606
607 for (i = 0; i < insn->n; i++) {
608 writew(DPR_SUBSYS_MEM, dev->mmio + DPR_SUBSYS);
609 writew(addr, dev->mmio + DPR_PARAMS(0));
610 writew(1, dev->mmio + DPR_PARAMS(1));
611
612 dt3k_send_cmd(dev, DPR_CMD_READCODE);
613
614 data[i] = readw(dev->mmio + DPR_PARAMS(2));
615 }
616
617 return i;
618}
619
620static int dt3000_auto_attach(struct comedi_device *dev,
621 unsigned long context)
622{
623 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
624 const struct dt3k_boardtype *board = NULL;
625 struct dt3k_private *devpriv;
626 struct comedi_subdevice *s;
627 int ret = 0;
628
629 if (context < ARRAY_SIZE(dt3k_boardtypes))
630 board = &dt3k_boardtypes[context];
631 if (!board)
632 return -ENODEV;
633 dev->board_ptr = board;
634 dev->board_name = board->name;
635
636 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
637 if (!devpriv)
638 return -ENOMEM;
639
640 ret = comedi_pci_enable(dev);
641 if (ret < 0)
642 return ret;
643
644 dev->mmio = pci_ioremap_bar(pcidev, 0);
645 if (!dev->mmio)
646 return -ENOMEM;
647
648 if (pcidev->irq) {
649 ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
650 dev->board_name, dev);
651 if (ret == 0)
652 dev->irq = pcidev->irq;
653 }
654
655 ret = comedi_alloc_subdevices(dev, 4);
656 if (ret)
657 return ret;
658
659
660 s = &dev->subdevices[0];
661 s->type = COMEDI_SUBD_AI;
662 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
663 s->n_chan = board->adchan;
664 s->maxdata = board->ai_is_16bit ? 0xffff : 0x0fff;
665 s->range_table = &range_dt3000_ai;
666 s->insn_read = dt3k_ai_insn_read;
667 if (dev->irq) {
668 dev->read_subdev = s;
669 s->subdev_flags |= SDF_CMD_READ;
670 s->len_chanlist = 512;
671 s->do_cmd = dt3k_ai_cmd;
672 s->do_cmdtest = dt3k_ai_cmdtest;
673 s->cancel = dt3k_ai_cancel;
674 }
675
676
677 s = &dev->subdevices[1];
678 if (board->has_ao) {
679 s->type = COMEDI_SUBD_AO;
680 s->subdev_flags = SDF_WRITABLE;
681 s->n_chan = 2;
682 s->maxdata = 0x0fff;
683 s->range_table = &range_bipolar10;
684 s->insn_write = dt3k_ao_insn_write;
685
686 ret = comedi_alloc_subdev_readback(s);
687 if (ret)
688 return ret;
689
690 } else {
691 s->type = COMEDI_SUBD_UNUSED;
692 }
693
694
695 s = &dev->subdevices[2];
696 s->type = COMEDI_SUBD_DIO;
697 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
698 s->n_chan = 8;
699 s->maxdata = 1;
700 s->range_table = &range_digital;
701 s->insn_config = dt3k_dio_insn_config;
702 s->insn_bits = dt3k_dio_insn_bits;
703
704
705 s = &dev->subdevices[3];
706 s->type = COMEDI_SUBD_MEMORY;
707 s->subdev_flags = SDF_READABLE;
708 s->n_chan = 0x1000;
709 s->maxdata = 0xff;
710 s->range_table = &range_unknown;
711 s->insn_read = dt3k_mem_insn_read;
712
713 return 0;
714}
715
716static struct comedi_driver dt3000_driver = {
717 .driver_name = "dt3000",
718 .module = THIS_MODULE,
719 .auto_attach = dt3000_auto_attach,
720 .detach = comedi_pci_detach,
721};
722
723static int dt3000_pci_probe(struct pci_dev *dev,
724 const struct pci_device_id *id)
725{
726 return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data);
727}
728
729static const struct pci_device_id dt3000_pci_table[] = {
730 { PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 },
731 { PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 },
732 { PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 },
733 { PCI_VDEVICE(DT, 0x0025), BOARD_DT3004 },
734 { PCI_VDEVICE(DT, 0x0026), BOARD_DT3005 },
735 { PCI_VDEVICE(DT, 0x0027), BOARD_DT3001_PGL },
736 { PCI_VDEVICE(DT, 0x0028), BOARD_DT3003_PGL },
737 { 0 }
738};
739MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
740
741static struct pci_driver dt3000_pci_driver = {
742 .name = "dt3000",
743 .id_table = dt3000_pci_table,
744 .probe = dt3000_pci_probe,
745 .remove = comedi_pci_auto_unconfig,
746};
747module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
748
749MODULE_AUTHOR("Comedi http://www.comedi.org");
750MODULE_DESCRIPTION("Comedi driver for Data Translation DT3000 series boards");
751MODULE_LICENSE("GPL");
752