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