1 /*
2 comedi/drivers/dt3000.c
3 Data Translation DT3000 series driver
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1999 David A. Schleef <ds@schleef.org>
7
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.
12
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.
17 */
18 /*
19 Driver: dt3000
20 Description: Data Translation DT3000 series
21 Author: ds
22 Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003,
23 DT3003-PGL, DT3004, DT3005, DT3004-200
24 Updated: Mon, 14 Apr 2008 15:41:24 +0100
25 Status: works
26
27 Configuration Options: not applicable, uses PCI auto config
28
29 There is code to support AI commands, but it may not work.
30
31 AO commands are not supported.
32 */
33
34 /*
35 The DT3000 series is Data Translation's attempt to make a PCI
36 data acquisition board. The design of this series is very nice,
37 since each board has an on-board DSP (Texas Instruments TMS320C52).
38 However, a few details are a little annoying. The boards lack
39 bus-mastering DMA, which eliminates them from serious work.
40 They also are not capable of autocalibration, which is a common
41 feature in modern hardware. The default firmware is pretty bad,
42 making it nearly impossible to write an RT compatible driver.
43 It would make an interesting project to write a decent firmware
44 for these boards.
45
46 Data Translation originally wanted an NDA for the documentation
47 for the 3k series. However, if you ask nicely, they might send
48 you the docs without one, also.
49 */
50
51 #include <linux/module.h>
52 #include <linux/delay.h>
53 #include <linux/interrupt.h>
54
55 #include "../comedi_pci.h"
56
57 static const struct comedi_lrange range_dt3000_ai = {
58 4, {
59 BIP_RANGE(10),
60 BIP_RANGE(5),
61 BIP_RANGE(2.5),
62 BIP_RANGE(1.25)
63 }
64 };
65
66 static const struct comedi_lrange range_dt3000_ai_pgl = {
67 4, {
68 BIP_RANGE(10),
69 BIP_RANGE(1),
70 BIP_RANGE(0.1),
71 BIP_RANGE(0.02)
72 }
73 };
74
75 enum dt3k_boardid {
76 BOARD_DT3001,
77 BOARD_DT3001_PGL,
78 BOARD_DT3002,
79 BOARD_DT3003,
80 BOARD_DT3003_PGL,
81 BOARD_DT3004,
82 BOARD_DT3005,
83 };
84
85 struct dt3k_boardtype {
86 const char *name;
87 int adchan;
88 int adbits;
89 int ai_speed;
90 const struct comedi_lrange *adrange;
91 int dachan;
92 int dabits;
93 };
94
95 static const struct dt3k_boardtype dt3k_boardtypes[] = {
96 [BOARD_DT3001] = {
97 .name = "dt3001",
98 .adchan = 16,
99 .adbits = 12,
100 .adrange = &range_dt3000_ai,
101 .ai_speed = 3000,
102 .dachan = 2,
103 .dabits = 12,
104 },
105 [BOARD_DT3001_PGL] = {
106 .name = "dt3001-pgl",
107 .adchan = 16,
108 .adbits = 12,
109 .adrange = &range_dt3000_ai_pgl,
110 .ai_speed = 3000,
111 .dachan = 2,
112 .dabits = 12,
113 },
114 [BOARD_DT3002] = {
115 .name = "dt3002",
116 .adchan = 32,
117 .adbits = 12,
118 .adrange = &range_dt3000_ai,
119 .ai_speed = 3000,
120 },
121 [BOARD_DT3003] = {
122 .name = "dt3003",
123 .adchan = 64,
124 .adbits = 12,
125 .adrange = &range_dt3000_ai,
126 .ai_speed = 3000,
127 .dachan = 2,
128 .dabits = 12,
129 },
130 [BOARD_DT3003_PGL] = {
131 .name = "dt3003-pgl",
132 .adchan = 64,
133 .adbits = 12,
134 .adrange = &range_dt3000_ai_pgl,
135 .ai_speed = 3000,
136 .dachan = 2,
137 .dabits = 12,
138 },
139 [BOARD_DT3004] = {
140 .name = "dt3004",
141 .adchan = 16,
142 .adbits = 16,
143 .adrange = &range_dt3000_ai,
144 .ai_speed = 10000,
145 .dachan = 2,
146 .dabits = 12,
147 },
148 [BOARD_DT3005] = {
149 .name = "dt3005", /* a.k.a. 3004-200 */
150 .adchan = 16,
151 .adbits = 16,
152 .adrange = &range_dt3000_ai,
153 .ai_speed = 5000,
154 .dachan = 2,
155 .dabits = 12,
156 },
157 };
158
159 /* dual-ported RAM location definitions */
160
161 #define DPR_DAC_buffer (4*0x000)
162 #define DPR_ADC_buffer (4*0x800)
163 #define DPR_Command (4*0xfd3)
164 #define DPR_SubSys (4*0xfd3)
165 #define DPR_Encode (4*0xfd4)
166 #define DPR_Params(a) (4*(0xfd5+(a)))
167 #define DPR_Tick_Reg_Lo (4*0xff5)
168 #define DPR_Tick_Reg_Hi (4*0xff6)
169 #define DPR_DA_Buf_Front (4*0xff7)
170 #define DPR_DA_Buf_Rear (4*0xff8)
171 #define DPR_AD_Buf_Front (4*0xff9)
172 #define DPR_AD_Buf_Rear (4*0xffa)
173 #define DPR_Int_Mask (4*0xffb)
174 #define DPR_Intr_Flag (4*0xffc)
175 #define DPR_Response_Mbx (4*0xffe)
176 #define DPR_Command_Mbx (4*0xfff)
177
178 #define AI_FIFO_DEPTH 2003
179 #define AO_FIFO_DEPTH 2048
180
181 /* command list */
182
183 #define CMD_GETBRDINFO 0
184 #define CMD_CONFIG 1
185 #define CMD_GETCONFIG 2
186 #define CMD_START 3
187 #define CMD_STOP 4
188 #define CMD_READSINGLE 5
189 #define CMD_WRITESINGLE 6
190 #define CMD_CALCCLOCK 7
191 #define CMD_READEVENTS 8
192 #define CMD_WRITECTCTRL 16
193 #define CMD_READCTCTRL 17
194 #define CMD_WRITECT 18
195 #define CMD_READCT 19
196 #define CMD_WRITEDATA 32
197 #define CMD_READDATA 33
198 #define CMD_WRITEIO 34
199 #define CMD_READIO 35
200 #define CMD_WRITECODE 36
201 #define CMD_READCODE 37
202 #define CMD_EXECUTE 38
203 #define CMD_HALT 48
204
205 #define SUBS_AI 0
206 #define SUBS_AO 1
207 #define SUBS_DIN 2
208 #define SUBS_DOUT 3
209 #define SUBS_MEM 4
210 #define SUBS_CT 5
211
212 /* interrupt flags */
213 #define DT3000_CMDONE 0x80
214 #define DT3000_CTDONE 0x40
215 #define DT3000_DAHWERR 0x20
216 #define DT3000_DASWERR 0x10
217 #define DT3000_DAEMPTY 0x08
218 #define DT3000_ADHWERR 0x04
219 #define DT3000_ADSWERR 0x02
220 #define DT3000_ADFULL 0x01
221
222 #define DT3000_COMPLETION_MASK 0xff00
223 #define DT3000_COMMAND_MASK 0x00ff
224 #define DT3000_NOTPROCESSED 0x0000
225 #define DT3000_NOERROR 0x5500
226 #define DT3000_ERROR 0xaa00
227 #define DT3000_NOTSUPPORTED 0xff00
228
229 #define DT3000_EXTERNAL_CLOCK 1
230 #define DT3000_RISING_EDGE 2
231
232 #define TMODE_MASK 0x1c
233
234 #define DT3000_AD_TRIG_INTERNAL (0<<2)
235 #define DT3000_AD_TRIG_EXTERNAL (1<<2)
236 #define DT3000_AD_RETRIG_INTERNAL (2<<2)
237 #define DT3000_AD_RETRIG_EXTERNAL (3<<2)
238 #define DT3000_AD_EXTRETRIG (4<<2)
239
240 #define DT3000_CHANNEL_MODE_SE 0
241 #define DT3000_CHANNEL_MODE_DI 1
242
243 struct dt3k_private {
244 unsigned int lock;
245 unsigned int ai_front;
246 unsigned int ai_rear;
247 };
248
249 #define TIMEOUT 100
250
dt3k_send_cmd(struct comedi_device * dev,unsigned int cmd)251 static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
252 {
253 int i;
254 unsigned int status = 0;
255
256 writew(cmd, dev->mmio + DPR_Command_Mbx);
257
258 for (i = 0; i < TIMEOUT; i++) {
259 status = readw(dev->mmio + DPR_Command_Mbx);
260 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
261 break;
262 udelay(1);
263 }
264
265 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOERROR)
266 dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n",
267 __func__, status);
268 }
269
dt3k_readsingle(struct comedi_device * dev,unsigned int subsys,unsigned int chan,unsigned int gain)270 static unsigned int dt3k_readsingle(struct comedi_device *dev,
271 unsigned int subsys, unsigned int chan,
272 unsigned int gain)
273 {
274 writew(subsys, dev->mmio + DPR_SubSys);
275
276 writew(chan, dev->mmio + DPR_Params(0));
277 writew(gain, dev->mmio + DPR_Params(1));
278
279 dt3k_send_cmd(dev, CMD_READSINGLE);
280
281 return readw(dev->mmio + DPR_Params(2));
282 }
283
dt3k_writesingle(struct comedi_device * dev,unsigned int subsys,unsigned int chan,unsigned int data)284 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
285 unsigned int chan, unsigned int data)
286 {
287 writew(subsys, dev->mmio + DPR_SubSys);
288
289 writew(chan, dev->mmio + DPR_Params(0));
290 writew(0, dev->mmio + DPR_Params(1));
291 writew(data, dev->mmio + DPR_Params(2));
292
293 dt3k_send_cmd(dev, CMD_WRITESINGLE);
294 }
295
dt3k_ai_empty_fifo(struct comedi_device * dev,struct comedi_subdevice * s)296 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
297 struct comedi_subdevice *s)
298 {
299 struct dt3k_private *devpriv = dev->private;
300 int front;
301 int rear;
302 int count;
303 int i;
304 unsigned short data;
305
306 front = readw(dev->mmio + DPR_AD_Buf_Front);
307 count = front - devpriv->ai_front;
308 if (count < 0)
309 count += AI_FIFO_DEPTH;
310
311 rear = devpriv->ai_rear;
312
313 for (i = 0; i < count; i++) {
314 data = readw(dev->mmio + DPR_ADC_buffer + rear);
315 comedi_buf_write_samples(s, &data, 1);
316 rear++;
317 if (rear >= AI_FIFO_DEPTH)
318 rear = 0;
319 }
320
321 devpriv->ai_rear = rear;
322 writew(rear, dev->mmio + DPR_AD_Buf_Rear);
323 }
324
dt3k_ai_cancel(struct comedi_device * dev,struct comedi_subdevice * s)325 static int dt3k_ai_cancel(struct comedi_device *dev,
326 struct comedi_subdevice *s)
327 {
328 writew(SUBS_AI, dev->mmio + DPR_SubSys);
329 dt3k_send_cmd(dev, CMD_STOP);
330
331 writew(0, dev->mmio + DPR_Int_Mask);
332
333 return 0;
334 }
335
336 static int debug_n_ints;
337
338 /* FIXME! Assumes shared interrupt is for this card. */
339 /* What's this debug_n_ints stuff? Obviously needs some work... */
dt3k_interrupt(int irq,void * d)340 static irqreturn_t dt3k_interrupt(int irq, void *d)
341 {
342 struct comedi_device *dev = d;
343 struct comedi_subdevice *s = dev->read_subdev;
344 unsigned int status;
345
346 if (!dev->attached)
347 return IRQ_NONE;
348
349 status = readw(dev->mmio + DPR_Intr_Flag);
350
351 if (status & DT3000_ADFULL)
352 dt3k_ai_empty_fifo(dev, s);
353
354 if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
355 s->async->events |= COMEDI_CB_ERROR;
356
357 debug_n_ints++;
358 if (debug_n_ints >= 10)
359 s->async->events |= COMEDI_CB_EOA;
360
361 comedi_handle_events(dev, s);
362 return IRQ_HANDLED;
363 }
364
dt3k_ns_to_timer(unsigned int timer_base,unsigned int * nanosec,unsigned int flags)365 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
366 unsigned int flags)
367 {
368 int divider, base, prescale;
369
370 /* This function needs improvment */
371 /* Don't know if divider==0 works. */
372
373 for (prescale = 0; prescale < 16; prescale++) {
374 base = timer_base * (prescale + 1);
375 switch (flags & CMDF_ROUND_MASK) {
376 case CMDF_ROUND_NEAREST:
377 default:
378 divider = (*nanosec + base / 2) / base;
379 break;
380 case CMDF_ROUND_DOWN:
381 divider = (*nanosec) / base;
382 break;
383 case CMDF_ROUND_UP:
384 divider = (*nanosec) / base;
385 break;
386 }
387 if (divider < 65536) {
388 *nanosec = divider * base;
389 return (prescale << 16) | (divider);
390 }
391 }
392
393 prescale = 15;
394 base = timer_base * (1 << prescale);
395 divider = 65535;
396 *nanosec = divider * base;
397 return (prescale << 16) | (divider);
398 }
399
dt3k_ai_cmdtest(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)400 static int dt3k_ai_cmdtest(struct comedi_device *dev,
401 struct comedi_subdevice *s, struct comedi_cmd *cmd)
402 {
403 const struct dt3k_boardtype *this_board = dev->board_ptr;
404 int err = 0;
405 unsigned int arg;
406
407 /* Step 1 : check if triggers are trivially valid */
408
409 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
410 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
411 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
412 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
413 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
414
415 if (err)
416 return 1;
417
418 /* Step 2a : make sure trigger sources are unique */
419 /* Step 2b : and mutually compatible */
420
421 /* Step 3: check if arguments are trivially valid */
422
423 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
424
425 if (cmd->scan_begin_src == TRIG_TIMER) {
426 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
427 this_board->ai_speed);
428 err |= comedi_check_trigger_arg_max(&cmd->scan_begin_arg,
429 100 * 16 * 65535);
430 }
431
432 if (cmd->convert_src == TRIG_TIMER) {
433 err |= comedi_check_trigger_arg_min(&cmd->convert_arg,
434 this_board->ai_speed);
435 err |= comedi_check_trigger_arg_max(&cmd->convert_arg,
436 50 * 16 * 65535);
437 }
438
439 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
440 cmd->chanlist_len);
441
442 if (cmd->stop_src == TRIG_COUNT)
443 err |= comedi_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
444 else /* TRIG_NONE */
445 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
446
447 if (err)
448 return 3;
449
450 /* step 4: fix up any arguments */
451
452 if (cmd->scan_begin_src == TRIG_TIMER) {
453 arg = cmd->scan_begin_arg;
454 dt3k_ns_to_timer(100, &arg, cmd->flags);
455 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
456 }
457
458 if (cmd->convert_src == TRIG_TIMER) {
459 arg = cmd->convert_arg;
460 dt3k_ns_to_timer(50, &arg, cmd->flags);
461 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
462
463 if (cmd->scan_begin_src == TRIG_TIMER) {
464 arg = cmd->convert_arg * cmd->scan_end_arg;
465 err |= comedi_check_trigger_arg_min(&cmd->
466 scan_begin_arg,
467 arg);
468 }
469 }
470
471 if (err)
472 return 4;
473
474 return 0;
475 }
476
dt3k_ai_cmd(struct comedi_device * dev,struct comedi_subdevice * s)477 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
478 {
479 struct comedi_cmd *cmd = &s->async->cmd;
480 int i;
481 unsigned int chan, range, aref;
482 unsigned int divider;
483 unsigned int tscandiv;
484
485 for (i = 0; i < cmd->chanlist_len; i++) {
486 chan = CR_CHAN(cmd->chanlist[i]);
487 range = CR_RANGE(cmd->chanlist[i]);
488
489 writew((range << 6) | chan, dev->mmio + DPR_ADC_buffer + i);
490 }
491 aref = CR_AREF(cmd->chanlist[0]);
492
493 writew(cmd->scan_end_arg, dev->mmio + DPR_Params(0));
494
495 if (cmd->convert_src == TRIG_TIMER) {
496 divider = dt3k_ns_to_timer(50, &cmd->convert_arg, cmd->flags);
497 writew((divider >> 16), dev->mmio + DPR_Params(1));
498 writew((divider & 0xffff), dev->mmio + DPR_Params(2));
499 }
500
501 if (cmd->scan_begin_src == TRIG_TIMER) {
502 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
503 cmd->flags);
504 writew((tscandiv >> 16), dev->mmio + DPR_Params(3));
505 writew((tscandiv & 0xffff), dev->mmio + DPR_Params(4));
506 }
507
508 writew(DT3000_AD_RETRIG_INTERNAL, dev->mmio + DPR_Params(5));
509 writew(aref == AREF_DIFF, dev->mmio + DPR_Params(6));
510
511 writew(AI_FIFO_DEPTH / 2, dev->mmio + DPR_Params(7));
512
513 writew(SUBS_AI, dev->mmio + DPR_SubSys);
514 dt3k_send_cmd(dev, CMD_CONFIG);
515
516 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
517 dev->mmio + DPR_Int_Mask);
518
519 debug_n_ints = 0;
520
521 writew(SUBS_AI, dev->mmio + DPR_SubSys);
522 dt3k_send_cmd(dev, CMD_START);
523
524 return 0;
525 }
526
dt3k_ai_insn(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)527 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
528 struct comedi_insn *insn, unsigned int *data)
529 {
530 int i;
531 unsigned int chan, gain, aref;
532
533 chan = CR_CHAN(insn->chanspec);
534 gain = CR_RANGE(insn->chanspec);
535 /* XXX docs don't explain how to select aref */
536 aref = CR_AREF(insn->chanspec);
537
538 for (i = 0; i < insn->n; i++)
539 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
540
541 return i;
542 }
543
dt3k_ao_insn_write(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)544 static int dt3k_ao_insn_write(struct comedi_device *dev,
545 struct comedi_subdevice *s,
546 struct comedi_insn *insn,
547 unsigned int *data)
548 {
549 unsigned int chan = CR_CHAN(insn->chanspec);
550 unsigned int val = s->readback[chan];
551 int i;
552
553 for (i = 0; i < insn->n; i++) {
554 val = data[i];
555 dt3k_writesingle(dev, SUBS_AO, chan, val);
556 }
557 s->readback[chan] = val;
558
559 return insn->n;
560 }
561
dt3k_dio_config(struct comedi_device * dev,int bits)562 static void dt3k_dio_config(struct comedi_device *dev, int bits)
563 {
564 /* XXX */
565 writew(SUBS_DOUT, dev->mmio + DPR_SubSys);
566
567 writew(bits, dev->mmio + DPR_Params(0));
568 #if 0
569 /* don't know */
570 writew(0, dev->mmio + DPR_Params(1));
571 writew(0, dev->mmio + DPR_Params(2));
572 #endif
573
574 dt3k_send_cmd(dev, CMD_CONFIG);
575 }
576
dt3k_dio_insn_config(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)577 static int dt3k_dio_insn_config(struct comedi_device *dev,
578 struct comedi_subdevice *s,
579 struct comedi_insn *insn,
580 unsigned int *data)
581 {
582 unsigned int chan = CR_CHAN(insn->chanspec);
583 unsigned int mask;
584 int ret;
585
586 if (chan < 4)
587 mask = 0x0f;
588 else
589 mask = 0xf0;
590
591 ret = comedi_dio_insn_config(dev, s, insn, data, mask);
592 if (ret)
593 return ret;
594
595 dt3k_dio_config(dev, (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3));
596
597 return insn->n;
598 }
599
dt3k_dio_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)600 static int dt3k_dio_insn_bits(struct comedi_device *dev,
601 struct comedi_subdevice *s,
602 struct comedi_insn *insn,
603 unsigned int *data)
604 {
605 if (comedi_dio_update_state(s, data))
606 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
607
608 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
609
610 return insn->n;
611 }
612
dt3k_mem_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)613 static int dt3k_mem_insn_read(struct comedi_device *dev,
614 struct comedi_subdevice *s,
615 struct comedi_insn *insn,
616 unsigned int *data)
617 {
618 unsigned int addr = CR_CHAN(insn->chanspec);
619 int i;
620
621 for (i = 0; i < insn->n; i++) {
622 writew(SUBS_MEM, dev->mmio + DPR_SubSys);
623 writew(addr, dev->mmio + DPR_Params(0));
624 writew(1, dev->mmio + DPR_Params(1));
625
626 dt3k_send_cmd(dev, CMD_READCODE);
627
628 data[i] = readw(dev->mmio + DPR_Params(2));
629 }
630
631 return i;
632 }
633
dt3000_auto_attach(struct comedi_device * dev,unsigned long context)634 static int dt3000_auto_attach(struct comedi_device *dev,
635 unsigned long context)
636 {
637 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
638 const struct dt3k_boardtype *this_board = NULL;
639 struct dt3k_private *devpriv;
640 struct comedi_subdevice *s;
641 int ret = 0;
642
643 if (context < ARRAY_SIZE(dt3k_boardtypes))
644 this_board = &dt3k_boardtypes[context];
645 if (!this_board)
646 return -ENODEV;
647 dev->board_ptr = this_board;
648 dev->board_name = this_board->name;
649
650 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
651 if (!devpriv)
652 return -ENOMEM;
653
654 ret = comedi_pci_enable(dev);
655 if (ret < 0)
656 return ret;
657
658 dev->mmio = pci_ioremap_bar(pcidev, 0);
659 if (!dev->mmio)
660 return -ENOMEM;
661
662 if (pcidev->irq) {
663 ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
664 dev->board_name, dev);
665 if (ret == 0)
666 dev->irq = pcidev->irq;
667 }
668
669 ret = comedi_alloc_subdevices(dev, 4);
670 if (ret)
671 return ret;
672
673 s = &dev->subdevices[0];
674 /* ai subdevice */
675 s->type = COMEDI_SUBD_AI;
676 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
677 s->n_chan = this_board->adchan;
678 s->insn_read = dt3k_ai_insn;
679 s->maxdata = (1 << this_board->adbits) - 1;
680 s->range_table = &range_dt3000_ai; /* XXX */
681 if (dev->irq) {
682 dev->read_subdev = s;
683 s->subdev_flags |= SDF_CMD_READ;
684 s->len_chanlist = 512;
685 s->do_cmd = dt3k_ai_cmd;
686 s->do_cmdtest = dt3k_ai_cmdtest;
687 s->cancel = dt3k_ai_cancel;
688 }
689
690 s = &dev->subdevices[1];
691 /* ao subsystem */
692 s->type = COMEDI_SUBD_AO;
693 s->subdev_flags = SDF_WRITABLE;
694 s->n_chan = 2;
695 s->maxdata = (1 << this_board->dabits) - 1;
696 s->len_chanlist = 1;
697 s->range_table = &range_bipolar10;
698 s->insn_write = dt3k_ao_insn_write;
699
700 ret = comedi_alloc_subdev_readback(s);
701 if (ret)
702 return ret;
703
704 s = &dev->subdevices[2];
705 /* dio subsystem */
706 s->type = COMEDI_SUBD_DIO;
707 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
708 s->n_chan = 8;
709 s->insn_config = dt3k_dio_insn_config;
710 s->insn_bits = dt3k_dio_insn_bits;
711 s->maxdata = 1;
712 s->len_chanlist = 8;
713 s->range_table = &range_digital;
714
715 s = &dev->subdevices[3];
716 /* mem subsystem */
717 s->type = COMEDI_SUBD_MEMORY;
718 s->subdev_flags = SDF_READABLE;
719 s->n_chan = 0x1000;
720 s->insn_read = dt3k_mem_insn_read;
721 s->maxdata = 0xff;
722 s->len_chanlist = 1;
723 s->range_table = &range_unknown;
724
725 #if 0
726 s = &dev->subdevices[4];
727 /* proc subsystem */
728 s->type = COMEDI_SUBD_PROC;
729 #endif
730
731 return 0;
732 }
733
734 static struct comedi_driver dt3000_driver = {
735 .driver_name = "dt3000",
736 .module = THIS_MODULE,
737 .auto_attach = dt3000_auto_attach,
738 .detach = comedi_pci_detach,
739 };
740
dt3000_pci_probe(struct pci_dev * dev,const struct pci_device_id * id)741 static int dt3000_pci_probe(struct pci_dev *dev,
742 const struct pci_device_id *id)
743 {
744 return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data);
745 }
746
747 static const struct pci_device_id dt3000_pci_table[] = {
748 { PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 },
749 { PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 },
750 { PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 },
751 { PCI_VDEVICE(DT, 0x0025), BOARD_DT3004 },
752 { PCI_VDEVICE(DT, 0x0026), BOARD_DT3005 },
753 { PCI_VDEVICE(DT, 0x0027), BOARD_DT3001_PGL },
754 { PCI_VDEVICE(DT, 0x0028), BOARD_DT3003_PGL },
755 { 0 }
756 };
757 MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
758
759 static struct pci_driver dt3000_pci_driver = {
760 .name = "dt3000",
761 .id_table = dt3000_pci_table,
762 .probe = dt3000_pci_probe,
763 .remove = comedi_pci_auto_unconfig,
764 };
765 module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
766
767 MODULE_AUTHOR("Comedi http://www.comedi.org");
768 MODULE_DESCRIPTION("Comedi low-level driver");
769 MODULE_LICENSE("GPL");
770