fdae78d1690dec82e8b45530b5f54e49de51044f
[firefly-linux-kernel-4.4.55.git] / drivers / staging / comedi / drivers / dt3000.c
1 /*
2  * 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 /*
20  * Driver: dt3000
21  * Description: Data Translation DT3000 series
22  * Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003,
23  *   DT3003-PGL, DT3004, DT3005, DT3004-200
24  * Author: ds
25  * Updated: Mon, 14 Apr 2008 15:41:24 +0100
26  * Status: works
27  *
28  * Configuration Options: not applicable, uses PCI auto config
29  *
30  * There is code to support AI commands, but it may not work.
31  *
32  * AO commands are not supported.
33  */
34
35 /*
36  * The DT3000 series is Data Translation's attempt to make a PCI
37  * data acquisition board.  The design of this series is very nice,
38  * since each board has an on-board DSP (Texas Instruments TMS320C52).
39  * However, a few details are a little annoying.  The boards lack
40  * bus-mastering DMA, which eliminates them from serious work.
41  * They also are not capable of autocalibration, which is a common
42  * feature in modern hardware.  The default firmware is pretty bad,
43  * making it nearly impossible to write an RT compatible driver.
44  * It would make an interesting project to write a decent firmware
45  * for these boards.
46  *
47  * Data Translation originally wanted an NDA for the documentation
48  * for the 3k series.  However, if you ask nicely, they might send
49  * you the docs without one, also.
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  * PCI BAR0 - dual-ported RAM location definitions (dev->mmio)
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
140 static 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
149 static 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
158 enum 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
168 struct dt3k_boardtype {
169         const char *name;
170         int adchan;
171         int adbits;
172         int ai_speed;
173         const struct comedi_lrange *adrange;
174         int dachan;
175         int dabits;
176 };
177
178 static const struct dt3k_boardtype dt3k_boardtypes[] = {
179         [BOARD_DT3001] = {
180                 .name           = "dt3001",
181                 .adchan         = 16,
182                 .adbits         = 12,
183                 .adrange        = &range_dt3000_ai,
184                 .ai_speed       = 3000,
185                 .dachan         = 2,
186                 .dabits         = 12,
187         },
188         [BOARD_DT3001_PGL] = {
189                 .name           = "dt3001-pgl",
190                 .adchan         = 16,
191                 .adbits         = 12,
192                 .adrange        = &range_dt3000_ai_pgl,
193                 .ai_speed       = 3000,
194                 .dachan         = 2,
195                 .dabits         = 12,
196         },
197         [BOARD_DT3002] = {
198                 .name           = "dt3002",
199                 .adchan         = 32,
200                 .adbits         = 12,
201                 .adrange        = &range_dt3000_ai,
202                 .ai_speed       = 3000,
203         },
204         [BOARD_DT3003] = {
205                 .name           = "dt3003",
206                 .adchan         = 64,
207                 .adbits         = 12,
208                 .adrange        = &range_dt3000_ai,
209                 .ai_speed       = 3000,
210                 .dachan         = 2,
211                 .dabits         = 12,
212         },
213         [BOARD_DT3003_PGL] = {
214                 .name           = "dt3003-pgl",
215                 .adchan         = 64,
216                 .adbits         = 12,
217                 .adrange        = &range_dt3000_ai_pgl,
218                 .ai_speed       = 3000,
219                 .dachan         = 2,
220                 .dabits         = 12,
221         },
222         [BOARD_DT3004] = {
223                 .name           = "dt3004",
224                 .adchan         = 16,
225                 .adbits         = 16,
226                 .adrange        = &range_dt3000_ai,
227                 .ai_speed       = 10000,
228                 .dachan         = 2,
229                 .dabits         = 12,
230         },
231         [BOARD_DT3005] = {
232                 .name           = "dt3005",     /* a.k.a. 3004-200 */
233                 .adchan         = 16,
234                 .adbits         = 16,
235                 .adrange        = &range_dt3000_ai,
236                 .ai_speed       = 5000,
237                 .dachan         = 2,
238                 .dabits         = 12,
239         },
240 };
241
242 struct dt3k_private {
243         unsigned int lock;
244         unsigned int ai_front;
245         unsigned int ai_rear;
246 };
247
248 static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
249 {
250         int i;
251         unsigned int status = 0;
252
253         writew(cmd, dev->mmio + DPR_CMD_MBX);
254
255         for (i = 0; i < DPR_CMD_TIMEOUT; i++) {
256                 status = readw(dev->mmio + DPR_CMD_MBX);
257                 status &= DPR_CMD_COMPLETION_MASK;
258                 if (status != DPR_CMD_NOTPROCESSED)
259                         break;
260                 udelay(1);
261         }
262
263         if (status != DPR_CMD_NOERROR)
264                 dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n",
265                         __func__, status);
266 }
267
268 static unsigned int dt3k_readsingle(struct comedi_device *dev,
269                                     unsigned int subsys, unsigned int chan,
270                                     unsigned int gain)
271 {
272         writew(subsys, dev->mmio + DPR_SUBSYS);
273
274         writew(chan, dev->mmio + DPR_PARAMS(0));
275         writew(gain, dev->mmio + DPR_PARAMS(1));
276
277         dt3k_send_cmd(dev, DPR_CMD_READSINGLE);
278
279         return readw(dev->mmio + DPR_PARAMS(2));
280 }
281
282 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
283                              unsigned int chan, unsigned int data)
284 {
285         writew(subsys, dev->mmio + DPR_SUBSYS);
286
287         writew(chan, dev->mmio + DPR_PARAMS(0));
288         writew(0, dev->mmio + DPR_PARAMS(1));
289         writew(data, dev->mmio + DPR_PARAMS(2));
290
291         dt3k_send_cmd(dev, DPR_CMD_WRITESINGLE);
292 }
293
294 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
295                                struct comedi_subdevice *s)
296 {
297         struct dt3k_private *devpriv = dev->private;
298         int front;
299         int rear;
300         int count;
301         int i;
302         unsigned short data;
303
304         front = readw(dev->mmio + DPR_AD_BUF_FRONT);
305         count = front - devpriv->ai_front;
306         if (count < 0)
307                 count += DPR_AI_FIFO_DEPTH;
308
309         rear = devpriv->ai_rear;
310
311         for (i = 0; i < count; i++) {
312                 data = readw(dev->mmio + DPR_ADC_BUFFER + rear);
313                 comedi_buf_write_samples(s, &data, 1);
314                 rear++;
315                 if (rear >= DPR_AI_FIFO_DEPTH)
316                         rear = 0;
317         }
318
319         devpriv->ai_rear = rear;
320         writew(rear, dev->mmio + DPR_AD_BUF_REAR);
321 }
322
323 static int dt3k_ai_cancel(struct comedi_device *dev,
324                           struct comedi_subdevice *s)
325 {
326         writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS);
327         dt3k_send_cmd(dev, DPR_CMD_STOP);
328
329         writew(0, dev->mmio + DPR_INT_MASK);
330
331         return 0;
332 }
333
334 static int debug_n_ints;
335
336 /* FIXME! Assumes shared interrupt is for this card. */
337 /* What's this debug_n_ints stuff? Obviously needs some work... */
338 static irqreturn_t dt3k_interrupt(int irq, void *d)
339 {
340         struct comedi_device *dev = d;
341         struct comedi_subdevice *s = dev->read_subdev;
342         unsigned int status;
343
344         if (!dev->attached)
345                 return IRQ_NONE;
346
347         status = readw(dev->mmio + DPR_INTR_FLAG);
348
349         if (status & DPR_INTR_ADFULL)
350                 dt3k_ai_empty_fifo(dev, s);
351
352         if (status & (DPR_INTR_ADSWERR | DPR_INTR_ADHWERR))
353                 s->async->events |= COMEDI_CB_ERROR;
354
355         debug_n_ints++;
356         if (debug_n_ints >= 10)
357                 s->async->events |= COMEDI_CB_EOA;
358
359         comedi_handle_events(dev, s);
360         return IRQ_HANDLED;
361 }
362
363 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
364                             unsigned int flags)
365 {
366         int divider, base, prescale;
367
368         /* This function needs improvment */
369         /* Don't know if divider==0 works. */
370
371         for (prescale = 0; prescale < 16; prescale++) {
372                 base = timer_base * (prescale + 1);
373                 switch (flags & CMDF_ROUND_MASK) {
374                 case CMDF_ROUND_NEAREST:
375                 default:
376                         divider = (*nanosec + base / 2) / base;
377                         break;
378                 case CMDF_ROUND_DOWN:
379                         divider = (*nanosec) / base;
380                         break;
381                 case CMDF_ROUND_UP:
382                         divider = (*nanosec) / base;
383                         break;
384                 }
385                 if (divider < 65536) {
386                         *nanosec = divider * base;
387                         return (prescale << 16) | (divider);
388                 }
389         }
390
391         prescale = 15;
392         base = timer_base * (1 << prescale);
393         divider = 65535;
394         *nanosec = divider * base;
395         return (prescale << 16) | (divider);
396 }
397
398 static int dt3k_ai_cmdtest(struct comedi_device *dev,
399                            struct comedi_subdevice *s, struct comedi_cmd *cmd)
400 {
401         const struct dt3k_boardtype *board = dev->board_ptr;
402         int err = 0;
403         unsigned int arg;
404
405         /* Step 1 : check if triggers are trivially valid */
406
407         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
408         err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
409         err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
410         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
411         err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
412
413         if (err)
414                 return 1;
415
416         /* Step 2a : make sure trigger sources are unique */
417         /* Step 2b : and mutually compatible */
418
419         /* Step 3: check if arguments are trivially valid */
420
421         err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
422
423         if (cmd->scan_begin_src == TRIG_TIMER) {
424                 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
425                                                     board->ai_speed);
426                 err |= comedi_check_trigger_arg_max(&cmd->scan_begin_arg,
427                                                     100 * 16 * 65535);
428         }
429
430         if (cmd->convert_src == TRIG_TIMER) {
431                 err |= comedi_check_trigger_arg_min(&cmd->convert_arg,
432                                                     board->ai_speed);
433                 err |= comedi_check_trigger_arg_max(&cmd->convert_arg,
434                                                     50 * 16 * 65535);
435         }
436
437         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
438                                            cmd->chanlist_len);
439
440         if (cmd->stop_src == TRIG_COUNT)
441                 err |= comedi_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
442         else    /* TRIG_NONE */
443                 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
444
445         if (err)
446                 return 3;
447
448         /* step 4: fix up any arguments */
449
450         if (cmd->scan_begin_src == TRIG_TIMER) {
451                 arg = cmd->scan_begin_arg;
452                 dt3k_ns_to_timer(100, &arg, cmd->flags);
453                 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
454         }
455
456         if (cmd->convert_src == TRIG_TIMER) {
457                 arg = cmd->convert_arg;
458                 dt3k_ns_to_timer(50, &arg, cmd->flags);
459                 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
460
461                 if (cmd->scan_begin_src == TRIG_TIMER) {
462                         arg = cmd->convert_arg * cmd->scan_end_arg;
463                         err |= comedi_check_trigger_arg_min(&cmd->
464                                                             scan_begin_arg,
465                                                             arg);
466                 }
467         }
468
469         if (err)
470                 return 4;
471
472         return 0;
473 }
474
475 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
476 {
477         struct comedi_cmd *cmd = &s->async->cmd;
478         int i;
479         unsigned int chan, range, aref;
480         unsigned int divider;
481         unsigned int tscandiv;
482
483         for (i = 0; i < cmd->chanlist_len; i++) {
484                 chan = CR_CHAN(cmd->chanlist[i]);
485                 range = CR_RANGE(cmd->chanlist[i]);
486
487                 writew((range << 6) | chan, dev->mmio + DPR_ADC_BUFFER + i);
488         }
489         aref = CR_AREF(cmd->chanlist[0]);
490
491         writew(cmd->scan_end_arg, dev->mmio + DPR_PARAMS(0));
492
493         if (cmd->convert_src == TRIG_TIMER) {
494                 divider = dt3k_ns_to_timer(50, &cmd->convert_arg, cmd->flags);
495                 writew((divider >> 16), dev->mmio + DPR_PARAMS(1));
496                 writew((divider & 0xffff), dev->mmio + DPR_PARAMS(2));
497         }
498
499         if (cmd->scan_begin_src == TRIG_TIMER) {
500                 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
501                                             cmd->flags);
502                 writew((tscandiv >> 16), dev->mmio + DPR_PARAMS(3));
503                 writew((tscandiv & 0xffff), dev->mmio + DPR_PARAMS(4));
504         }
505
506         writew(DPR_PARAM5_AD_TRIG_INT_RETRIG, dev->mmio + DPR_PARAMS(5));
507         writew((aref == AREF_DIFF) ? DPR_PARAM6_AD_DIFF : 0,
508                dev->mmio + DPR_PARAMS(6));
509
510         writew(DPR_AI_FIFO_DEPTH / 2, dev->mmio + DPR_PARAMS(7));
511
512         writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS);
513         dt3k_send_cmd(dev, DPR_CMD_CONFIG);
514
515         writew(DPR_INTR_ADFULL | DPR_INTR_ADSWERR | DPR_INTR_ADHWERR,
516                dev->mmio + DPR_INT_MASK);
517
518         debug_n_ints = 0;
519
520         writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS);
521         dt3k_send_cmd(dev, DPR_CMD_START);
522
523         return 0;
524 }
525
526 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
527                         struct comedi_insn *insn, unsigned int *data)
528 {
529         int i;
530         unsigned int chan, gain, aref;
531
532         chan = CR_CHAN(insn->chanspec);
533         gain = CR_RANGE(insn->chanspec);
534         /* XXX docs don't explain how to select aref */
535         aref = CR_AREF(insn->chanspec);
536
537         for (i = 0; i < insn->n; i++)
538                 data[i] = dt3k_readsingle(dev, DPR_SUBSYS_AI, chan, gain);
539
540         return i;
541 }
542
543 static int dt3k_ao_insn_write(struct comedi_device *dev,
544                               struct comedi_subdevice *s,
545                               struct comedi_insn *insn,
546                               unsigned int *data)
547 {
548         unsigned int chan = CR_CHAN(insn->chanspec);
549         unsigned int val = s->readback[chan];
550         int i;
551
552         for (i = 0; i < insn->n; i++) {
553                 val = data[i];
554                 dt3k_writesingle(dev, DPR_SUBSYS_AO, chan, val);
555         }
556         s->readback[chan] = val;
557
558         return insn->n;
559 }
560
561 static void dt3k_dio_config(struct comedi_device *dev, int bits)
562 {
563         /* XXX */
564         writew(DPR_SUBSYS_DOUT, dev->mmio + DPR_SUBSYS);
565
566         writew(bits, dev->mmio + DPR_PARAMS(0));
567 #if 0
568         /* don't know */
569         writew(0, dev->mmio + DPR_PARAMS(1));
570         writew(0, dev->mmio + DPR_PARAMS(2));
571 #endif
572
573         dt3k_send_cmd(dev, DPR_CMD_CONFIG);
574 }
575
576 static int dt3k_dio_insn_config(struct comedi_device *dev,
577                                 struct comedi_subdevice *s,
578                                 struct comedi_insn *insn,
579                                 unsigned int *data)
580 {
581         unsigned int chan = CR_CHAN(insn->chanspec);
582         unsigned int mask;
583         int ret;
584
585         if (chan < 4)
586                 mask = 0x0f;
587         else
588                 mask = 0xf0;
589
590         ret = comedi_dio_insn_config(dev, s, insn, data, mask);
591         if (ret)
592                 return ret;
593
594         dt3k_dio_config(dev, (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3));
595
596         return insn->n;
597 }
598
599 static int dt3k_dio_insn_bits(struct comedi_device *dev,
600                               struct comedi_subdevice *s,
601                               struct comedi_insn *insn,
602                               unsigned int *data)
603 {
604         if (comedi_dio_update_state(s, data))
605                 dt3k_writesingle(dev, DPR_SUBSYS_DOUT, 0, s->state);
606
607         data[1] = dt3k_readsingle(dev, DPR_SUBSYS_DIN, 0, 0);
608
609         return insn->n;
610 }
611
612 static int dt3k_mem_insn_read(struct comedi_device *dev,
613                               struct comedi_subdevice *s,
614                               struct comedi_insn *insn,
615                               unsigned int *data)
616 {
617         unsigned int addr = CR_CHAN(insn->chanspec);
618         int i;
619
620         for (i = 0; i < insn->n; i++) {
621                 writew(DPR_SUBSYS_MEM, dev->mmio + DPR_SUBSYS);
622                 writew(addr, dev->mmio + DPR_PARAMS(0));
623                 writew(1, dev->mmio + DPR_PARAMS(1));
624
625                 dt3k_send_cmd(dev, DPR_CMD_READCODE);
626
627                 data[i] = readw(dev->mmio + DPR_PARAMS(2));
628         }
629
630         return i;
631 }
632
633 static int dt3000_auto_attach(struct comedi_device *dev,
634                               unsigned long context)
635 {
636         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
637         const struct dt3k_boardtype *board = NULL;
638         struct dt3k_private *devpriv;
639         struct comedi_subdevice *s;
640         int ret = 0;
641
642         if (context < ARRAY_SIZE(dt3k_boardtypes))
643                 board = &dt3k_boardtypes[context];
644         if (!board)
645                 return -ENODEV;
646         dev->board_ptr = board;
647         dev->board_name = board->name;
648
649         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
650         if (!devpriv)
651                 return -ENOMEM;
652
653         ret = comedi_pci_enable(dev);
654         if (ret < 0)
655                 return ret;
656
657         dev->mmio = pci_ioremap_bar(pcidev, 0);
658         if (!dev->mmio)
659                 return -ENOMEM;
660
661         if (pcidev->irq) {
662                 ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
663                                   dev->board_name, dev);
664                 if (ret == 0)
665                         dev->irq = pcidev->irq;
666         }
667
668         ret = comedi_alloc_subdevices(dev, 4);
669         if (ret)
670                 return ret;
671
672         s = &dev->subdevices[0];
673         /* ai subdevice */
674         s->type         = COMEDI_SUBD_AI;
675         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
676         s->n_chan       = board->adchan;
677         s->insn_read    = dt3k_ai_insn;
678         s->maxdata      = (1 << board->adbits) - 1;
679         s->range_table  = &range_dt3000_ai;     /* XXX */
680         if (dev->irq) {
681                 dev->read_subdev = s;
682                 s->subdev_flags |= SDF_CMD_READ;
683                 s->len_chanlist = 512;
684                 s->do_cmd       = dt3k_ai_cmd;
685                 s->do_cmdtest   = dt3k_ai_cmdtest;
686                 s->cancel       = dt3k_ai_cancel;
687         }
688
689         s = &dev->subdevices[1];
690         /* ao subsystem */
691         s->type         = COMEDI_SUBD_AO;
692         s->subdev_flags = SDF_WRITABLE;
693         s->n_chan       = 2;
694         s->maxdata      = (1 << board->dabits) - 1;
695         s->len_chanlist = 1;
696         s->range_table  = &range_bipolar10;
697         s->insn_write   = dt3k_ao_insn_write;
698
699         ret = comedi_alloc_subdev_readback(s);
700         if (ret)
701                 return ret;
702
703         s = &dev->subdevices[2];
704         /* dio subsystem */
705         s->type         = COMEDI_SUBD_DIO;
706         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
707         s->n_chan       = 8;
708         s->insn_config  = dt3k_dio_insn_config;
709         s->insn_bits    = dt3k_dio_insn_bits;
710         s->maxdata      = 1;
711         s->len_chanlist = 8;
712         s->range_table  = &range_digital;
713
714         s = &dev->subdevices[3];
715         /* mem subsystem */
716         s->type         = COMEDI_SUBD_MEMORY;
717         s->subdev_flags = SDF_READABLE;
718         s->n_chan       = 0x1000;
719         s->insn_read    = dt3k_mem_insn_read;
720         s->maxdata      = 0xff;
721         s->len_chanlist = 1;
722         s->range_table  = &range_unknown;
723
724         return 0;
725 }
726
727 static struct comedi_driver dt3000_driver = {
728         .driver_name    = "dt3000",
729         .module         = THIS_MODULE,
730         .auto_attach    = dt3000_auto_attach,
731         .detach         = comedi_pci_detach,
732 };
733
734 static int dt3000_pci_probe(struct pci_dev *dev,
735                             const struct pci_device_id *id)
736 {
737         return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data);
738 }
739
740 static const struct pci_device_id dt3000_pci_table[] = {
741         { PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 },
742         { PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 },
743         { PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 },
744         { PCI_VDEVICE(DT, 0x0025), BOARD_DT3004 },
745         { PCI_VDEVICE(DT, 0x0026), BOARD_DT3005 },
746         { PCI_VDEVICE(DT, 0x0027), BOARD_DT3001_PGL },
747         { PCI_VDEVICE(DT, 0x0028), BOARD_DT3003_PGL },
748         { 0 }
749 };
750 MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
751
752 static struct pci_driver dt3000_pci_driver = {
753         .name           = "dt3000",
754         .id_table       = dt3000_pci_table,
755         .probe          = dt3000_pci_probe,
756         .remove         = comedi_pci_auto_unconfig,
757 };
758 module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
759
760 MODULE_AUTHOR("Comedi http://www.comedi.org");
761 MODULE_DESCRIPTION("Comedi low-level driver");
762 MODULE_LICENSE("GPL");