Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / staging / comedi / drivers / dt3000.c
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
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
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
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
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
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... */
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
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
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
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
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
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
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
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
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
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
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
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");