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