]> Pileus Git - ~andy/linux/blob - drivers/staging/comedi/drivers/dt3000.c
e71d880bddaa73f7c187731c8e7d006845f4dc22
[~andy/linux] / 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     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 */
23 /*
24 Driver: dt3000
25 Description: Data Translation DT3000 series
26 Author: ds
27 Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003,
28   DT3003-PGL, DT3004, DT3005, DT3004-200
29 Updated: Mon, 14 Apr 2008 15:41:24 +0100
30 Status: works
31
32 Configuration Options:
33   [0] - PCI bus of device (optional)
34   [1] - PCI slot of device (optional)
35   If bus/slot is not specified, the first supported
36   PCI device found will be used.
37
38 There is code to support AI commands, but it may not work.
39
40 AO commands are not supported.
41 */
42
43 /*
44    The DT3000 series is Data Translation's attempt to make a PCI
45    data acquisition board.  The design of this series is very nice,
46    since each board has an on-board DSP (Texas Instruments TMS320C52).
47    However, a few details are a little annoying.  The boards lack
48    bus-mastering DMA, which eliminates them from serious work.
49    They also are not capable of autocalibration, which is a common
50    feature in modern hardware.  The default firmware is pretty bad,
51    making it nearly impossible to write an RT compatible driver.
52    It would make an interesting project to write a decent firmware
53    for these boards.
54
55    Data Translation originally wanted an NDA for the documentation
56    for the 3k series.  However, if you ask nicely, they might send
57    you the docs without one, also.
58 */
59
60 #define DEBUG 1
61
62 #include <linux/interrupt.h>
63 #include "../comedidev.h"
64 #include <linux/delay.h>
65
66 #include "comedi_fc.h"
67
68 #define PCI_VENDOR_ID_DT        0x1116
69
70 static const struct comedi_lrange range_dt3000_ai = { 4, {
71                                                           RANGE(-10, 10),
72                                                           RANGE(-5, 5),
73                                                           RANGE(-2.5, 2.5),
74                                                           RANGE(-1.25, 1.25)
75                                                           }
76 };
77
78 static const struct comedi_lrange range_dt3000_ai_pgl = { 4, {
79                                                               RANGE(-10, 10),
80                                                               RANGE(-1, 1),
81                                                               RANGE(-0.1, 0.1),
82                                                               RANGE(-0.02, 0.02)
83                                                               }
84 };
85
86 struct dt3k_boardtype {
87
88         const char *name;
89         unsigned int device_id;
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         {.name = "dt3001",
100          .device_id = 0x22,
101          .adchan = 16,
102          .adbits = 12,
103          .adrange = &range_dt3000_ai,
104          .ai_speed = 3000,
105          .dachan = 2,
106          .dabits = 12,
107          },
108         {.name = "dt3001-pgl",
109          .device_id = 0x27,
110          .adchan = 16,
111          .adbits = 12,
112          .adrange = &range_dt3000_ai_pgl,
113          .ai_speed = 3000,
114          .dachan = 2,
115          .dabits = 12,
116          },
117         {.name = "dt3002",
118          .device_id = 0x23,
119          .adchan = 32,
120          .adbits = 12,
121          .adrange = &range_dt3000_ai,
122          .ai_speed = 3000,
123          .dachan = 0,
124          .dabits = 0,
125          },
126         {.name = "dt3003",
127          .device_id = 0x24,
128          .adchan = 64,
129          .adbits = 12,
130          .adrange = &range_dt3000_ai,
131          .ai_speed = 3000,
132          .dachan = 2,
133          .dabits = 12,
134          },
135         {.name = "dt3003-pgl",
136          .device_id = 0x28,
137          .adchan = 64,
138          .adbits = 12,
139          .adrange = &range_dt3000_ai_pgl,
140          .ai_speed = 3000,
141          .dachan = 2,
142          .dabits = 12,
143          },
144         {.name = "dt3004",
145          .device_id = 0x25,
146          .adchan = 16,
147          .adbits = 16,
148          .adrange = &range_dt3000_ai,
149          .ai_speed = 10000,
150          .dachan = 2,
151          .dabits = 12,
152          },
153         {.name = "dt3005",      /* a.k.a. 3004-200 */
154          .device_id = 0x26,
155          .adchan = 16,
156          .adbits = 16,
157          .adrange = &range_dt3000_ai,
158          .ai_speed = 5000,
159          .dachan = 2,
160          .dabits = 12,
161          },
162 };
163
164 #define this_board ((const struct dt3k_boardtype *)dev->board_ptr)
165
166 #define DT3000_SIZE             (4*0x1000)
167
168 /* dual-ported RAM location definitions */
169
170 #define DPR_DAC_buffer          (4*0x000)
171 #define DPR_ADC_buffer          (4*0x800)
172 #define DPR_Command             (4*0xfd3)
173 #define DPR_SubSys              (4*0xfd3)
174 #define DPR_Encode              (4*0xfd4)
175 #define DPR_Params(a)           (4*(0xfd5+(a)))
176 #define DPR_Tick_Reg_Lo         (4*0xff5)
177 #define DPR_Tick_Reg_Hi         (4*0xff6)
178 #define DPR_DA_Buf_Front        (4*0xff7)
179 #define DPR_DA_Buf_Rear         (4*0xff8)
180 #define DPR_AD_Buf_Front        (4*0xff9)
181 #define DPR_AD_Buf_Rear         (4*0xffa)
182 #define DPR_Int_Mask            (4*0xffb)
183 #define DPR_Intr_Flag           (4*0xffc)
184 #define DPR_Response_Mbx        (4*0xffe)
185 #define DPR_Command_Mbx         (4*0xfff)
186
187 #define AI_FIFO_DEPTH   2003
188 #define AO_FIFO_DEPTH   2048
189
190 /* command list */
191
192 #define CMD_GETBRDINFO          0
193 #define CMD_CONFIG              1
194 #define CMD_GETCONFIG           2
195 #define CMD_START               3
196 #define CMD_STOP                4
197 #define CMD_READSINGLE          5
198 #define CMD_WRITESINGLE         6
199 #define CMD_CALCCLOCK           7
200 #define CMD_READEVENTS          8
201 #define CMD_WRITECTCTRL         16
202 #define CMD_READCTCTRL          17
203 #define CMD_WRITECT             18
204 #define CMD_READCT              19
205 #define CMD_WRITEDATA           32
206 #define CMD_READDATA            33
207 #define CMD_WRITEIO             34
208 #define CMD_READIO              35
209 #define CMD_WRITECODE           36
210 #define CMD_READCODE            37
211 #define CMD_EXECUTE             38
212 #define CMD_HALT                48
213
214 #define SUBS_AI         0
215 #define SUBS_AO         1
216 #define SUBS_DIN        2
217 #define SUBS_DOUT       3
218 #define SUBS_MEM        4
219 #define SUBS_CT         5
220
221 /* interrupt flags */
222 #define DT3000_CMDONE           0x80
223 #define DT3000_CTDONE           0x40
224 #define DT3000_DAHWERR          0x20
225 #define DT3000_DASWERR          0x10
226 #define DT3000_DAEMPTY          0x08
227 #define DT3000_ADHWERR          0x04
228 #define DT3000_ADSWERR          0x02
229 #define DT3000_ADFULL           0x01
230
231 #define DT3000_COMPLETION_MASK  0xff00
232 #define DT3000_COMMAND_MASK     0x00ff
233 #define DT3000_NOTPROCESSED     0x0000
234 #define DT3000_NOERROR          0x5500
235 #define DT3000_ERROR            0xaa00
236 #define DT3000_NOTSUPPORTED     0xff00
237
238 #define DT3000_EXTERNAL_CLOCK   1
239 #define DT3000_RISING_EDGE      2
240
241 #define TMODE_MASK              0x1c
242
243 #define DT3000_AD_TRIG_INTERNAL         (0<<2)
244 #define DT3000_AD_TRIG_EXTERNAL         (1<<2)
245 #define DT3000_AD_RETRIG_INTERNAL       (2<<2)
246 #define DT3000_AD_RETRIG_EXTERNAL       (3<<2)
247 #define DT3000_AD_EXTRETRIG             (4<<2)
248
249 #define DT3000_CHANNEL_MODE_SE          0
250 #define DT3000_CHANNEL_MODE_DI          1
251
252 struct dt3k_private {
253         void __iomem *io_addr;
254         unsigned int lock;
255         unsigned int ao_readback[2];
256         unsigned int ai_front;
257         unsigned int ai_rear;
258 };
259
260 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
261                                struct comedi_subdevice *s);
262 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
263                             unsigned int round_mode);
264 static int dt3k_ai_cancel(struct comedi_device *dev,
265                           struct comedi_subdevice *s);
266 #ifdef DEBUG
267 static void debug_intr_flags(unsigned int flags);
268 #endif
269
270 #define TIMEOUT 100
271
272 static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
273 {
274         struct dt3k_private *devpriv = dev->private;
275         int i;
276         unsigned int status = 0;
277
278         writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
279
280         for (i = 0; i < TIMEOUT; i++) {
281                 status = readw(devpriv->io_addr + DPR_Command_Mbx);
282                 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
283                         break;
284                 udelay(1);
285         }
286         if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR)
287                 return 0;
288
289         dev_dbg(dev->class_dev, "dt3k_send_cmd() timeout/error status=0x%04x\n",
290                 status);
291
292         return -ETIME;
293 }
294
295 static unsigned int dt3k_readsingle(struct comedi_device *dev,
296                                     unsigned int subsys, unsigned int chan,
297                                     unsigned int gain)
298 {
299         struct dt3k_private *devpriv = dev->private;
300
301         writew(subsys, devpriv->io_addr + DPR_SubSys);
302
303         writew(chan, devpriv->io_addr + DPR_Params(0));
304         writew(gain, devpriv->io_addr + DPR_Params(1));
305
306         dt3k_send_cmd(dev, CMD_READSINGLE);
307
308         return readw(devpriv->io_addr + DPR_Params(2));
309 }
310
311 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
312                              unsigned int chan, unsigned int data)
313 {
314         struct dt3k_private *devpriv = dev->private;
315
316         writew(subsys, devpriv->io_addr + DPR_SubSys);
317
318         writew(chan, devpriv->io_addr + DPR_Params(0));
319         writew(0, devpriv->io_addr + DPR_Params(1));
320         writew(data, devpriv->io_addr + DPR_Params(2));
321
322         dt3k_send_cmd(dev, CMD_WRITESINGLE);
323 }
324
325 static int debug_n_ints;
326
327 /* FIXME! Assumes shared interrupt is for this card. */
328 /* What's this debug_n_ints stuff? Obviously needs some work... */
329 static irqreturn_t dt3k_interrupt(int irq, void *d)
330 {
331         struct comedi_device *dev = d;
332         struct dt3k_private *devpriv = dev->private;
333         struct comedi_subdevice *s;
334         unsigned int status;
335
336         if (!dev->attached)
337                 return IRQ_NONE;
338
339         s = &dev->subdevices[0];
340         status = readw(devpriv->io_addr + DPR_Intr_Flag);
341 #ifdef DEBUG
342         debug_intr_flags(status);
343 #endif
344
345         if (status & DT3000_ADFULL) {
346                 dt3k_ai_empty_fifo(dev, s);
347                 s->async->events |= COMEDI_CB_BLOCK;
348         }
349
350         if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
351                 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
352
353         debug_n_ints++;
354         if (debug_n_ints >= 10) {
355                 dt3k_ai_cancel(dev, s);
356                 s->async->events |= COMEDI_CB_EOA;
357         }
358
359         comedi_event(dev, s);
360         return IRQ_HANDLED;
361 }
362
363 #ifdef DEBUG
364 static char *intr_flags[] = {
365         "AdFull", "AdSwError", "AdHwError", "DaEmpty",
366         "DaSwError", "DaHwError", "CtDone", "CmDone",
367 };
368
369 static void debug_intr_flags(unsigned int flags)
370 {
371         int i;
372         printk(KERN_DEBUG "dt3k: intr_flags:");
373         for (i = 0; i < 8; i++) {
374                 if (flags & (1 << i))
375                         printk(KERN_CONT " %s", intr_flags[i]);
376         }
377         printk(KERN_CONT "\n");
378 }
379 #endif
380
381 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
382                                struct comedi_subdevice *s)
383 {
384         struct dt3k_private *devpriv = dev->private;
385         int front;
386         int rear;
387         int count;
388         int i;
389         short data;
390
391         front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
392         count = front - devpriv->ai_front;
393         if (count < 0)
394                 count += AI_FIFO_DEPTH;
395
396         dev_dbg(dev->class_dev, "reading %d samples\n", count);
397
398         rear = devpriv->ai_rear;
399
400         for (i = 0; i < count; i++) {
401                 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
402                 comedi_buf_put(s->async, data);
403                 rear++;
404                 if (rear >= AI_FIFO_DEPTH)
405                         rear = 0;
406         }
407
408         devpriv->ai_rear = rear;
409         writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
410 }
411
412 static int dt3k_ai_cmdtest(struct comedi_device *dev,
413                            struct comedi_subdevice *s, struct comedi_cmd *cmd)
414 {
415         int err = 0;
416         int tmp;
417
418         /* Step 1 : check if triggers are trivially valid */
419
420         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
421         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
422         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
423         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
424         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
425
426         if (err)
427                 return 1;
428
429         /* Step 2a : make sure trigger sources are unique */
430         /* Step 2b : and mutually compatible */
431
432         if (err)
433                 return 2;
434
435         /* step 3: make sure arguments are trivially compatible */
436
437         if (cmd->start_arg != 0) {
438                 cmd->start_arg = 0;
439                 err++;
440         }
441
442         if (cmd->scan_begin_src == TRIG_TIMER) {
443                 if (cmd->scan_begin_arg < this_board->ai_speed) {
444                         cmd->scan_begin_arg = this_board->ai_speed;
445                         err++;
446                 }
447                 if (cmd->scan_begin_arg > 100 * 16 * 65535) {
448                         cmd->scan_begin_arg = 100 * 16 * 65535;
449                         err++;
450                 }
451         } else {
452                 /* not supported */
453         }
454         if (cmd->convert_src == TRIG_TIMER) {
455                 if (cmd->convert_arg < this_board->ai_speed) {
456                         cmd->convert_arg = this_board->ai_speed;
457                         err++;
458                 }
459                 if (cmd->convert_arg > 50 * 16 * 65535) {
460                         cmd->convert_arg = 50 * 16 * 65535;
461                         err++;
462                 }
463         } else {
464                 /* not supported */
465         }
466
467         if (cmd->scan_end_arg != cmd->chanlist_len) {
468                 cmd->scan_end_arg = cmd->chanlist_len;
469                 err++;
470         }
471         if (cmd->stop_src == TRIG_COUNT) {
472                 if (cmd->stop_arg > 0x00ffffff) {
473                         cmd->stop_arg = 0x00ffffff;
474                         err++;
475                 }
476         } else {
477                 /* TRIG_NONE */
478                 if (cmd->stop_arg != 0) {
479                         cmd->stop_arg = 0;
480                         err++;
481                 }
482         }
483
484         if (err)
485                 return 3;
486
487         /* step 4: fix up any arguments */
488
489         if (cmd->scan_begin_src == TRIG_TIMER) {
490                 tmp = cmd->scan_begin_arg;
491                 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
492                                  cmd->flags & TRIG_ROUND_MASK);
493                 if (tmp != cmd->scan_begin_arg)
494                         err++;
495         } else {
496                 /* not supported */
497         }
498         if (cmd->convert_src == TRIG_TIMER) {
499                 tmp = cmd->convert_arg;
500                 dt3k_ns_to_timer(50, &cmd->convert_arg,
501                                  cmd->flags & TRIG_ROUND_MASK);
502                 if (tmp != cmd->convert_arg)
503                         err++;
504                 if (cmd->scan_begin_src == TRIG_TIMER &&
505                     cmd->scan_begin_arg <
506                     cmd->convert_arg * cmd->scan_end_arg) {
507                         cmd->scan_begin_arg =
508                             cmd->convert_arg * cmd->scan_end_arg;
509                         err++;
510                 }
511         } else {
512                 /* not supported */
513         }
514
515         if (err)
516                 return 4;
517
518         return 0;
519 }
520
521 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
522                             unsigned int round_mode)
523 {
524         int divider, base, prescale;
525
526         /* This function needs improvment */
527         /* Don't know if divider==0 works. */
528
529         for (prescale = 0; prescale < 16; prescale++) {
530                 base = timer_base * (prescale + 1);
531                 switch (round_mode) {
532                 case TRIG_ROUND_NEAREST:
533                 default:
534                         divider = (*nanosec + base / 2) / base;
535                         break;
536                 case TRIG_ROUND_DOWN:
537                         divider = (*nanosec) / base;
538                         break;
539                 case TRIG_ROUND_UP:
540                         divider = (*nanosec) / base;
541                         break;
542                 }
543                 if (divider < 65536) {
544                         *nanosec = divider * base;
545                         return (prescale << 16) | (divider);
546                 }
547         }
548
549         prescale = 15;
550         base = timer_base * (1 << prescale);
551         divider = 65535;
552         *nanosec = divider * base;
553         return (prescale << 16) | (divider);
554 }
555
556 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
557 {
558         struct dt3k_private *devpriv = dev->private;
559         struct comedi_cmd *cmd = &s->async->cmd;
560         int i;
561         unsigned int chan, range, aref;
562         unsigned int divider;
563         unsigned int tscandiv;
564         int ret;
565         unsigned int mode;
566
567         dev_dbg(dev->class_dev, "dt3k_ai_cmd:\n");
568         for (i = 0; i < cmd->chanlist_len; i++) {
569                 chan = CR_CHAN(cmd->chanlist[i]);
570                 range = CR_RANGE(cmd->chanlist[i]);
571
572                 writew((range << 6) | chan,
573                        devpriv->io_addr + DPR_ADC_buffer + i);
574         }
575         aref = CR_AREF(cmd->chanlist[0]);
576
577         writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
578         dev_dbg(dev->class_dev, "param[0]=0x%04x\n", cmd->scan_end_arg);
579
580         if (cmd->convert_src == TRIG_TIMER) {
581                 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
582                                            cmd->flags & TRIG_ROUND_MASK);
583                 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
584                 dev_dbg(dev->class_dev, "param[1]=0x%04x\n", divider >> 16);
585                 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
586                 dev_dbg(dev->class_dev, "param[2]=0x%04x\n", divider & 0xffff);
587         } else {
588                 /* not supported */
589         }
590
591         if (cmd->scan_begin_src == TRIG_TIMER) {
592                 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
593                                             cmd->flags & TRIG_ROUND_MASK);
594                 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
595                 dev_dbg(dev->class_dev, "param[3]=0x%04x\n", tscandiv >> 16);
596                 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
597                 dev_dbg(dev->class_dev, "param[4]=0x%04x\n", tscandiv & 0xffff);
598         } else {
599                 /* not supported */
600         }
601
602         mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
603         writew(mode, devpriv->io_addr + DPR_Params(5));
604         dev_dbg(dev->class_dev, "param[5]=0x%04x\n", mode);
605         writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
606         dev_dbg(dev->class_dev, "param[6]=0x%04x\n", aref == AREF_DIFF);
607
608         writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
609         dev_dbg(dev->class_dev, "param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
610
611         writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
612         ret = dt3k_send_cmd(dev, CMD_CONFIG);
613
614         writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
615                devpriv->io_addr + DPR_Int_Mask);
616
617         debug_n_ints = 0;
618
619         writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
620         ret = dt3k_send_cmd(dev, CMD_START);
621
622         return 0;
623 }
624
625 static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
626 {
627         struct dt3k_private *devpriv = dev->private;
628         int ret;
629
630         writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
631         ret = dt3k_send_cmd(dev, CMD_STOP);
632
633         writew(0, devpriv->io_addr + DPR_Int_Mask);
634
635         return 0;
636 }
637
638 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
639                         struct comedi_insn *insn, unsigned int *data)
640 {
641         int i;
642         unsigned int chan, gain, aref;
643
644         chan = CR_CHAN(insn->chanspec);
645         gain = CR_RANGE(insn->chanspec);
646         /* XXX docs don't explain how to select aref */
647         aref = CR_AREF(insn->chanspec);
648
649         for (i = 0; i < insn->n; i++)
650                 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
651
652         return i;
653 }
654
655 static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
656                         struct comedi_insn *insn, unsigned int *data)
657 {
658         struct dt3k_private *devpriv = dev->private;
659         int i;
660         unsigned int chan;
661
662         chan = CR_CHAN(insn->chanspec);
663         for (i = 0; i < insn->n; i++) {
664                 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
665                 devpriv->ao_readback[chan] = data[i];
666         }
667
668         return i;
669 }
670
671 static int dt3k_ao_insn_read(struct comedi_device *dev,
672                              struct comedi_subdevice *s,
673                              struct comedi_insn *insn, unsigned int *data)
674 {
675         struct dt3k_private *devpriv = dev->private;
676         int i;
677         unsigned int chan;
678
679         chan = CR_CHAN(insn->chanspec);
680         for (i = 0; i < insn->n; i++)
681                 data[i] = devpriv->ao_readback[chan];
682
683         return i;
684 }
685
686 static void dt3k_dio_config(struct comedi_device *dev, int bits)
687 {
688         struct dt3k_private *devpriv = dev->private;
689
690         /* XXX */
691         writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
692
693         writew(bits, devpriv->io_addr + DPR_Params(0));
694 #if 0
695         /* don't know */
696         writew(0, devpriv->io_addr + DPR_Params(1));
697         writew(0, devpriv->io_addr + DPR_Params(2));
698 #endif
699
700         dt3k_send_cmd(dev, CMD_CONFIG);
701 }
702
703 static int dt3k_dio_insn_config(struct comedi_device *dev,
704                                 struct comedi_subdevice *s,
705                                 struct comedi_insn *insn, unsigned int *data)
706 {
707         int mask;
708
709         mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
710
711         switch (data[0]) {
712         case INSN_CONFIG_DIO_OUTPUT:
713                 s->io_bits |= mask;
714                 break;
715         case INSN_CONFIG_DIO_INPUT:
716                 s->io_bits &= ~mask;
717                 break;
718         case INSN_CONFIG_DIO_QUERY:
719                 data[1] =
720                     (s->
721                      io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
722                     COMEDI_INPUT;
723                 return insn->n;
724                 break;
725         default:
726                 return -EINVAL;
727                 break;
728         }
729         mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
730         dt3k_dio_config(dev, mask);
731
732         return insn->n;
733 }
734
735 static int dt3k_dio_insn_bits(struct comedi_device *dev,
736                               struct comedi_subdevice *s,
737                               struct comedi_insn *insn, unsigned int *data)
738 {
739         if (data[0]) {
740                 s->state &= ~data[0];
741                 s->state |= data[1] & data[0];
742                 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
743         }
744         data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
745
746         return insn->n;
747 }
748
749 static int dt3k_mem_insn_read(struct comedi_device *dev,
750                               struct comedi_subdevice *s,
751                               struct comedi_insn *insn, unsigned int *data)
752 {
753         struct dt3k_private *devpriv = dev->private;
754         unsigned int addr = CR_CHAN(insn->chanspec);
755         int i;
756
757         for (i = 0; i < insn->n; i++) {
758                 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
759                 writew(addr, devpriv->io_addr + DPR_Params(0));
760                 writew(1, devpriv->io_addr + DPR_Params(1));
761
762                 dt3k_send_cmd(dev, CMD_READCODE);
763
764                 data[i] = readw(devpriv->io_addr + DPR_Params(2));
765         }
766
767         return i;
768 }
769
770 static struct pci_dev *dt3000_find_pci_dev(struct comedi_device *dev,
771                                            struct comedi_devconfig *it)
772 {
773         struct pci_dev *pcidev = NULL;
774         int bus = it->options[0];
775         int slot = it->options[1];
776         int i;
777
778         for_each_pci_dev(pcidev) {
779                 if (bus || slot) {
780                         if (bus != pcidev->bus->number ||
781                             slot != PCI_SLOT(pcidev->devfn))
782                                 continue;
783                 }
784                 if (pcidev->vendor != PCI_VENDOR_ID_DT)
785                         continue;
786                 for (i = 0; i < ARRAY_SIZE(dt3k_boardtypes); i++) {
787                         if (dt3k_boardtypes[i].device_id != pcidev->device)
788                                 continue;
789                         dev->board_ptr = dt3k_boardtypes + i;
790                         return pcidev;
791                 }
792         }
793         dev_err(dev->class_dev,
794                 "No supported board found! (req. bus %d, slot %d)\n",
795                 bus, slot);
796         return NULL;
797 }
798
799 static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
800 {
801         struct dt3k_private *devpriv;
802         struct pci_dev *pcidev;
803         struct comedi_subdevice *s;
804         resource_size_t pci_base;
805         int ret = 0;
806
807         dev_dbg(dev->class_dev, "dt3000:\n");
808
809         ret = alloc_private(dev, sizeof(*devpriv));
810         if (ret)
811                 return ret;
812         devpriv = dev->private;
813
814         pcidev = dt3000_find_pci_dev(dev, it);
815         if (!pcidev)
816                 return -EIO;
817         comedi_set_hw_dev(dev, &pcidev->dev);
818
819         ret = comedi_pci_enable(pcidev, "dt3000");
820         if (ret < 0)
821                 return ret;
822         dev->iobase = 1;        /* the "detach" needs this */
823
824         pci_base  = pci_resource_start(pcidev, 0);
825         devpriv->io_addr = ioremap(pci_base, DT3000_SIZE);
826         if (!devpriv->io_addr)
827                 return -ENOMEM;
828
829         dev->board_name = this_board->name;
830
831         if (request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
832                         "dt3000", dev)) {
833                 dev_err(dev->class_dev, "unable to allocate IRQ %u\n",
834                         pcidev->irq);
835                 return -EINVAL;
836         }
837         dev->irq = pcidev->irq;
838
839         ret = comedi_alloc_subdevices(dev, 4);
840         if (ret)
841                 return ret;
842
843         s = &dev->subdevices[0];
844         dev->read_subdev = s;
845
846         /* ai subdevice */
847         s->type = COMEDI_SUBD_AI;
848         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
849         s->n_chan = this_board->adchan;
850         s->insn_read = dt3k_ai_insn;
851         s->maxdata = (1 << this_board->adbits) - 1;
852         s->len_chanlist = 512;
853         s->range_table = &range_dt3000_ai;      /* XXX */
854         s->do_cmd = dt3k_ai_cmd;
855         s->do_cmdtest = dt3k_ai_cmdtest;
856         s->cancel = dt3k_ai_cancel;
857
858         s = &dev->subdevices[1];
859         /* ao subsystem */
860         s->type = COMEDI_SUBD_AO;
861         s->subdev_flags = SDF_WRITABLE;
862         s->n_chan = 2;
863         s->insn_read = dt3k_ao_insn_read;
864         s->insn_write = dt3k_ao_insn;
865         s->maxdata = (1 << this_board->dabits) - 1;
866         s->len_chanlist = 1;
867         s->range_table = &range_bipolar10;
868
869         s = &dev->subdevices[2];
870         /* dio subsystem */
871         s->type = COMEDI_SUBD_DIO;
872         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
873         s->n_chan = 8;
874         s->insn_config = dt3k_dio_insn_config;
875         s->insn_bits = dt3k_dio_insn_bits;
876         s->maxdata = 1;
877         s->len_chanlist = 8;
878         s->range_table = &range_digital;
879
880         s = &dev->subdevices[3];
881         /* mem subsystem */
882         s->type = COMEDI_SUBD_MEMORY;
883         s->subdev_flags = SDF_READABLE;
884         s->n_chan = 0x1000;
885         s->insn_read = dt3k_mem_insn_read;
886         s->maxdata = 0xff;
887         s->len_chanlist = 1;
888         s->range_table = &range_unknown;
889
890 #if 0
891         s = &dev->subdevices[4];
892         /* proc subsystem */
893         s->type = COMEDI_SUBD_PROC;
894 #endif
895
896         return 0;
897 }
898
899 static void dt3000_detach(struct comedi_device *dev)
900 {
901         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
902         struct dt3k_private *devpriv = dev->private;
903
904         if (dev->irq)
905                 free_irq(dev->irq, dev);
906         if (devpriv) {
907                 if (devpriv->io_addr)
908                         iounmap(devpriv->io_addr);
909         }
910         if (pcidev) {
911                 if (dev->iobase)
912                         comedi_pci_disable(pcidev);
913                 pci_dev_put(pcidev);
914         }
915 }
916
917 static struct comedi_driver dt3000_driver = {
918         .driver_name    = "dt3000",
919         .module         = THIS_MODULE,
920         .attach         = dt3000_attach,
921         .detach         = dt3000_detach,
922 };
923
924 static int __devinit dt3000_pci_probe(struct pci_dev *dev,
925                                       const struct pci_device_id *ent)
926 {
927         return comedi_pci_auto_config(dev, &dt3000_driver);
928 }
929
930 static void __devexit dt3000_pci_remove(struct pci_dev *dev)
931 {
932         comedi_pci_auto_unconfig(dev);
933 }
934
935 static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table) = {
936         { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0022) },
937         { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0027) },
938         { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0023) },
939         { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0024) },
940         { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0028) },
941         { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0025) },
942         { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0026) },
943         { 0 }
944 };
945 MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
946
947 static struct pci_driver dt3000_pci_driver = {
948         .name           = "dt3000",
949         .id_table       = dt3000_pci_table,
950         .probe          = dt3000_pci_probe,
951         .remove         = __devexit_p(dt3000_pci_remove),
952 };
953 module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
954
955 MODULE_AUTHOR("Comedi http://www.comedi.org");
956 MODULE_DESCRIPTION("Comedi low-level driver");
957 MODULE_LICENSE("GPL");