Staging: comedi: remove C99 comments in hwdrv_apci3120.c
[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 struct dt3k_private {
266
267         struct pci_dev *pci_dev;
268         resource_size_t phys_addr;
269         void *io_addr;
270         unsigned int lock;
271         unsigned int ao_readback[2];
272         unsigned int ai_front;
273         unsigned int ai_rear;
274 };
275
276 #define devpriv ((struct dt3k_private *)dev->private)
277
278 static int dt3000_attach(struct comedi_device * dev, struct comedi_devconfig * it);
279 static int dt3000_detach(struct comedi_device * dev);
280 static struct comedi_driver driver_dt3000 = {
281       driver_name:"dt3000",
282       module:THIS_MODULE,
283       attach:dt3000_attach,
284       detach:dt3000_detach,
285 };
286
287 COMEDI_PCI_INITCLEANUP(driver_dt3000, dt3k_pci_table);
288
289 static void dt3k_ai_empty_fifo(struct comedi_device * dev, struct comedi_subdevice * s);
290 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
291         unsigned int round_mode);
292 static int dt3k_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s);
293 #ifdef DEBUG
294 static void debug_intr_flags(unsigned int flags);
295 #endif
296
297 #define TIMEOUT 100
298
299 static int dt3k_send_cmd(struct comedi_device * dev, unsigned int cmd)
300 {
301         int i;
302         unsigned int status = 0;
303
304         writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
305
306         for (i = 0; i < TIMEOUT; i++) {
307                 status = readw(devpriv->io_addr + DPR_Command_Mbx);
308                 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
309                         break;
310                 comedi_udelay(1);
311         }
312         if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR) {
313                 return 0;
314         }
315
316         printk("dt3k_send_cmd() timeout/error status=0x%04x\n", status);
317
318         return -ETIME;
319 }
320
321 static unsigned int dt3k_readsingle(struct comedi_device * dev, unsigned int subsys,
322         unsigned int chan, unsigned int gain)
323 {
324         writew(subsys, devpriv->io_addr + DPR_SubSys);
325
326         writew(chan, devpriv->io_addr + DPR_Params(0));
327         writew(gain, devpriv->io_addr + DPR_Params(1));
328
329         dt3k_send_cmd(dev, CMD_READSINGLE);
330
331         return readw(devpriv->io_addr + DPR_Params(2));
332 }
333
334 static void dt3k_writesingle(struct comedi_device * dev, unsigned int subsys,
335         unsigned int chan, unsigned int data)
336 {
337         writew(subsys, devpriv->io_addr + DPR_SubSys);
338
339         writew(chan, devpriv->io_addr + DPR_Params(0));
340         writew(0, devpriv->io_addr + DPR_Params(1));
341         writew(data, devpriv->io_addr + DPR_Params(2));
342
343         dt3k_send_cmd(dev, CMD_WRITESINGLE);
344 }
345
346 static int debug_n_ints = 0;
347
348 // FIXME! Assumes shared interrupt is for this card.
349 // What's this debug_n_ints stuff? Obviously needs some work...
350 static irqreturn_t dt3k_interrupt(int irq, void *d PT_REGS_ARG)
351 {
352         struct comedi_device *dev = d;
353         struct comedi_subdevice *s;
354         unsigned int status;
355
356         if (!dev->attached) {
357                 return IRQ_NONE;
358         }
359
360         s = dev->subdevices + 0;
361         status = readw(devpriv->io_addr + DPR_Intr_Flag);
362 #ifdef DEBUG
363         debug_intr_flags(status);
364 #endif
365
366         if (status & DT3000_ADFULL) {
367                 dt3k_ai_empty_fifo(dev, s);
368                 s->async->events |= COMEDI_CB_BLOCK;
369         }
370
371         if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) {
372                 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
373         }
374
375         debug_n_ints++;
376         if (debug_n_ints >= 10) {
377                 dt3k_ai_cancel(dev, s);
378                 s->async->events |= COMEDI_CB_EOA;
379         }
380
381         comedi_event(dev, s);
382         return IRQ_HANDLED;
383 }
384
385 #ifdef DEBUG
386 static char *intr_flags[] = {
387         "AdFull", "AdSwError", "AdHwError", "DaEmpty",
388         "DaSwError", "DaHwError", "CtDone", "CmDone",
389 };
390 static void debug_intr_flags(unsigned int flags)
391 {
392         int i;
393         printk("dt3k: intr_flags:");
394         for (i = 0; i < 8; i++) {
395                 if (flags & (1 << i)) {
396                         printk(" %s", intr_flags[i]);
397                 }
398         }
399         printk("\n");
400 }
401 #endif
402
403 static void dt3k_ai_empty_fifo(struct comedi_device * dev, struct comedi_subdevice * s)
404 {
405         int front;
406         int rear;
407         int count;
408         int i;
409         short data;
410
411         front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
412         count = front - devpriv->ai_front;
413         if (count < 0)
414                 count += AI_FIFO_DEPTH;
415
416         printk("reading %d samples\n", count);
417
418         rear = devpriv->ai_rear;
419
420         for (i = 0; i < count; i++) {
421                 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
422                 comedi_buf_put(s->async, data);
423                 rear++;
424                 if (rear >= AI_FIFO_DEPTH)
425                         rear = 0;
426         }
427
428         devpriv->ai_rear = rear;
429         writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
430 }
431
432 static int dt3k_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s,
433         struct comedi_cmd * cmd)
434 {
435         int err = 0;
436         int tmp;
437
438         /* step 1: make sure trigger sources are trivially valid */
439
440         tmp = cmd->start_src;
441         cmd->start_src &= TRIG_NOW;
442         if (!cmd->start_src || tmp != cmd->start_src)
443                 err++;
444
445         tmp = cmd->scan_begin_src;
446         cmd->scan_begin_src &= TRIG_TIMER;
447         if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
448                 err++;
449
450         tmp = cmd->convert_src;
451         cmd->convert_src &= TRIG_TIMER;
452         if (!cmd->convert_src || tmp != cmd->convert_src)
453                 err++;
454
455         tmp = cmd->scan_end_src;
456         cmd->scan_end_src &= TRIG_COUNT;
457         if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
458                 err++;
459
460         tmp = cmd->stop_src;
461         cmd->stop_src &= TRIG_COUNT;
462         if (!cmd->stop_src || tmp != cmd->stop_src)
463                 err++;
464
465         if (err)
466                 return 1;
467
468         /* step 2: make sure trigger sources are unique and mutually compatible */
469
470         if (err)
471                 return 2;
472
473         /* step 3: make sure arguments are trivially compatible */
474
475         if (cmd->start_arg != 0) {
476                 cmd->start_arg = 0;
477                 err++;
478         }
479
480         if (cmd->scan_begin_src == TRIG_TIMER) {
481                 if (cmd->scan_begin_arg < this_board->ai_speed) {
482                         cmd->scan_begin_arg = this_board->ai_speed;
483                         err++;
484                 }
485                 if (cmd->scan_begin_arg > 100 * 16 * 65535) {
486                         cmd->scan_begin_arg = 100 * 16 * 65535;
487                         err++;
488                 }
489         } else {
490                 /* not supported */
491         }
492         if (cmd->convert_src == TRIG_TIMER) {
493                 if (cmd->convert_arg < this_board->ai_speed) {
494                         cmd->convert_arg = this_board->ai_speed;
495                         err++;
496                 }
497                 if (cmd->convert_arg > 50 * 16 * 65535) {
498                         cmd->convert_arg = 50 * 16 * 65535;
499                         err++;
500                 }
501         } else {
502                 /* not supported */
503         }
504
505         if (cmd->scan_end_arg != cmd->chanlist_len) {
506                 cmd->scan_end_arg = cmd->chanlist_len;
507                 err++;
508         }
509         if (cmd->stop_src == TRIG_COUNT) {
510                 if (cmd->stop_arg > 0x00ffffff) {
511                         cmd->stop_arg = 0x00ffffff;
512                         err++;
513                 }
514         } else {
515                 /* TRIG_NONE */
516                 if (cmd->stop_arg != 0) {
517                         cmd->stop_arg = 0;
518                         err++;
519                 }
520         }
521
522         if (err)
523                 return 3;
524
525         /* step 4: fix up any arguments */
526
527         if (cmd->scan_begin_src == TRIG_TIMER) {
528                 tmp = cmd->scan_begin_arg;
529                 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
530                         cmd->flags & TRIG_ROUND_MASK);
531                 if (tmp != cmd->scan_begin_arg)
532                         err++;
533         } else {
534                 /* not supported */
535         }
536         if (cmd->convert_src == TRIG_TIMER) {
537                 tmp = cmd->convert_arg;
538                 dt3k_ns_to_timer(50, &cmd->convert_arg,
539                         cmd->flags & TRIG_ROUND_MASK);
540                 if (tmp != cmd->convert_arg)
541                         err++;
542                 if (cmd->scan_begin_src == TRIG_TIMER &&
543                         cmd->scan_begin_arg <
544                         cmd->convert_arg * cmd->scan_end_arg) {
545                         cmd->scan_begin_arg =
546                                 cmd->convert_arg * cmd->scan_end_arg;
547                         err++;
548                 }
549         } else {
550                 /* not supported */
551         }
552
553         if (err)
554                 return 4;
555
556         return 0;
557 }
558
559 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
560         unsigned int round_mode)
561 {
562         int divider, base, prescale;
563
564         /* This function needs improvment */
565         /* Don't know if divider==0 works. */
566
567         for (prescale = 0; prescale < 16; prescale++) {
568                 base = timer_base * (prescale + 1);
569                 switch (round_mode) {
570                 case TRIG_ROUND_NEAREST:
571                 default:
572                         divider = (*nanosec + base / 2) / base;
573                         break;
574                 case TRIG_ROUND_DOWN:
575                         divider = (*nanosec) / base;
576                         break;
577                 case TRIG_ROUND_UP:
578                         divider = (*nanosec) / base;
579                         break;
580                 }
581                 if (divider < 65536) {
582                         *nanosec = divider * base;
583                         return (prescale << 16) | (divider);
584                 }
585         }
586
587         prescale = 15;
588         base = timer_base * (1 << prescale);
589         divider = 65535;
590         *nanosec = divider * base;
591         return (prescale << 16) | (divider);
592 }
593
594 static int dt3k_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s)
595 {
596         struct comedi_cmd *cmd = &s->async->cmd;
597         int i;
598         unsigned int chan, range, aref;
599         unsigned int divider;
600         unsigned int tscandiv;
601         int ret;
602         unsigned int mode;
603
604         printk("dt3k_ai_cmd:\n");
605         for (i = 0; i < cmd->chanlist_len; i++) {
606                 chan = CR_CHAN(cmd->chanlist[i]);
607                 range = CR_RANGE(cmd->chanlist[i]);
608
609                 writew((range << 6) | chan,
610                         devpriv->io_addr + DPR_ADC_buffer + i);
611         }
612         aref = CR_AREF(cmd->chanlist[0]);
613
614         writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
615         printk("param[0]=0x%04x\n", cmd->scan_end_arg);
616
617         if (cmd->convert_src == TRIG_TIMER) {
618                 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
619                         cmd->flags & TRIG_ROUND_MASK);
620                 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
621                 printk("param[1]=0x%04x\n", divider >> 16);
622                 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
623                 printk("param[2]=0x%04x\n", divider & 0xffff);
624         } else {
625                 /* not supported */
626         }
627
628         if (cmd->scan_begin_src == TRIG_TIMER) {
629                 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
630                         cmd->flags & TRIG_ROUND_MASK);
631                 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
632                 printk("param[3]=0x%04x\n", tscandiv >> 16);
633                 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
634                 printk("param[4]=0x%04x\n", tscandiv & 0xffff);
635         } else {
636                 /* not supported */
637         }
638
639         mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
640         writew(mode, devpriv->io_addr + DPR_Params(5));
641         printk("param[5]=0x%04x\n", mode);
642         writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
643         printk("param[6]=0x%04x\n", aref == AREF_DIFF);
644
645         writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
646         printk("param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
647
648         writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
649         ret = dt3k_send_cmd(dev, CMD_CONFIG);
650
651         writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
652                 devpriv->io_addr + DPR_Int_Mask);
653
654         debug_n_ints = 0;
655
656         writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
657         ret = dt3k_send_cmd(dev, CMD_START);
658
659         return 0;
660 }
661
662 static int dt3k_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s)
663 {
664         int ret;
665
666         writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
667         ret = dt3k_send_cmd(dev, CMD_STOP);
668
669         writew(0, devpriv->io_addr + DPR_Int_Mask);
670
671         return 0;
672 }
673
674 static int dt3k_ai_insn(struct comedi_device * dev, struct comedi_subdevice * s,
675         struct comedi_insn * insn, unsigned int * data)
676 {
677         int i;
678         unsigned int chan, gain, aref;
679
680         chan = CR_CHAN(insn->chanspec);
681         gain = CR_RANGE(insn->chanspec);
682         /* XXX docs don't explain how to select aref */
683         aref = CR_AREF(insn->chanspec);
684
685         for (i = 0; i < insn->n; i++) {
686                 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
687         }
688
689         return i;
690 }
691
692 static int dt3k_ao_insn(struct comedi_device * dev, struct comedi_subdevice * s,
693         struct comedi_insn * insn, unsigned int * data)
694 {
695         int i;
696         unsigned int chan;
697
698         chan = CR_CHAN(insn->chanspec);
699         for (i = 0; i < insn->n; i++) {
700                 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
701                 devpriv->ao_readback[chan] = data[i];
702         }
703
704         return i;
705 }
706
707 static int dt3k_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
708         struct comedi_insn * insn, unsigned int * data)
709 {
710         int i;
711         unsigned int chan;
712
713         chan = CR_CHAN(insn->chanspec);
714         for (i = 0; i < insn->n; i++) {
715                 data[i] = devpriv->ao_readback[chan];
716         }
717
718         return i;
719 }
720
721 static void dt3k_dio_config(struct comedi_device * dev, int bits)
722 {
723         /* XXX */
724         writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
725
726         writew(bits, devpriv->io_addr + DPR_Params(0));
727 #if 0
728         /* don't know */
729         writew(0, devpriv->io_addr + DPR_Params(1));
730         writew(0, devpriv->io_addr + DPR_Params(2));
731 #endif
732
733         dt3k_send_cmd(dev, CMD_CONFIG);
734 }
735
736 static int dt3k_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
737         struct comedi_insn * insn, unsigned int * data)
738 {
739         int mask;
740
741         mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
742
743         switch (data[0]) {
744         case INSN_CONFIG_DIO_OUTPUT:
745                 s->io_bits |= mask;
746                 break;
747         case INSN_CONFIG_DIO_INPUT:
748                 s->io_bits &= ~mask;
749                 break;
750         case INSN_CONFIG_DIO_QUERY:
751                 data[1] =
752                         (s->io_bits & (1 << CR_CHAN(insn->
753                                         chanspec))) ? COMEDI_OUTPUT :
754                         COMEDI_INPUT;
755                 return insn->n;
756                 break;
757         default:
758                 return -EINVAL;
759                 break;
760         }
761         mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
762         dt3k_dio_config(dev, mask);
763
764         return insn->n;
765 }
766
767 static int dt3k_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
768         struct comedi_insn * insn, unsigned int * data)
769 {
770         if (insn->n != 2)
771                 return -EINVAL;
772
773         if (data[0]) {
774                 s->state &= ~data[0];
775                 s->state |= data[1] & data[0];
776                 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
777         }
778         data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
779
780         return 2;
781 }
782
783 static int dt3k_mem_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
784         struct comedi_insn * insn, unsigned int * data)
785 {
786         unsigned int addr = CR_CHAN(insn->chanspec);
787         int i;
788
789         for (i = 0; i < insn->n; i++) {
790                 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
791                 writew(addr, devpriv->io_addr + DPR_Params(0));
792                 writew(1, devpriv->io_addr + DPR_Params(1));
793
794                 dt3k_send_cmd(dev, CMD_READCODE);
795
796                 data[i] = readw(devpriv->io_addr + DPR_Params(2));
797         }
798
799         return i;
800 }
801
802 static int dt_pci_probe(struct comedi_device * dev, int bus, int slot);
803
804 static int dt3000_attach(struct comedi_device * dev, struct comedi_devconfig * it)
805 {
806         struct comedi_subdevice *s;
807         int bus, slot;
808         int ret = 0;
809
810         printk("dt3000:");
811         bus = it->options[0];
812         slot = it->options[1];
813
814         if ((ret = alloc_private(dev, sizeof(struct dt3k_private))) < 0)
815                 return ret;
816
817         ret = dt_pci_probe(dev, bus, slot);
818         if (ret < 0)
819                 return ret;
820         if (ret == 0) {
821                 printk(" no DT board found\n");
822                 return -ENODEV;
823         }
824
825         dev->board_name = this_board->name;
826
827         if (comedi_request_irq(devpriv->pci_dev->irq, dt3k_interrupt,
828                         IRQF_SHARED, "dt3000", dev)) {
829                 printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq);
830                 return -EINVAL;
831         }
832         dev->irq = devpriv->pci_dev->irq;
833
834         if ((ret = alloc_subdevices(dev, 4)) < 0)
835                 return ret;
836
837         s = dev->subdevices;
838         dev->read_subdev = s;
839
840         /* ai subdevice */
841         s->type = COMEDI_SUBD_AI;
842         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
843         s->n_chan = this_board->adchan;
844         s->insn_read = dt3k_ai_insn;
845         s->maxdata = (1 << this_board->adbits) - 1;
846         s->len_chanlist = 512;
847         s->range_table = &range_dt3000_ai;      /* XXX */
848         s->do_cmd = dt3k_ai_cmd;
849         s->do_cmdtest = dt3k_ai_cmdtest;
850         s->cancel = dt3k_ai_cancel;
851
852         s++;
853         /* ao subsystem */
854         s->type = COMEDI_SUBD_AO;
855         s->subdev_flags = SDF_WRITABLE;
856         s->n_chan = 2;
857         s->insn_read = dt3k_ao_insn_read;
858         s->insn_write = dt3k_ao_insn;
859         s->maxdata = (1 << this_board->dabits) - 1;
860         s->len_chanlist = 1;
861         s->range_table = &range_bipolar10;
862
863         s++;
864         /* dio subsystem */
865         s->type = COMEDI_SUBD_DIO;
866         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
867         s->n_chan = 8;
868         s->insn_config = dt3k_dio_insn_config;
869         s->insn_bits = dt3k_dio_insn_bits;
870         s->maxdata = 1;
871         s->len_chanlist = 8;
872         s->range_table = &range_digital;
873
874         s++;
875         /* mem subsystem */
876         s->type = COMEDI_SUBD_MEMORY;
877         s->subdev_flags = SDF_READABLE;
878         s->n_chan = 0x1000;
879         s->insn_read = dt3k_mem_insn_read;
880         s->maxdata = 0xff;
881         s->len_chanlist = 1;
882         s->range_table = &range_unknown;
883
884 #if 0
885         s++;
886         /* proc subsystem */
887         s->type = COMEDI_SUBD_PROC;
888 #endif
889
890         return 0;
891 }
892
893 static int dt3000_detach(struct comedi_device * dev)
894 {
895         if (dev->irq)
896                 comedi_free_irq(dev->irq, dev);
897
898         if (devpriv) {
899                 if (devpriv->pci_dev) {
900                         if (devpriv->phys_addr) {
901                                 comedi_pci_disable(devpriv->pci_dev);
902                         }
903                         pci_dev_put(devpriv->pci_dev);
904                 }
905                 if (devpriv->io_addr)
906                         iounmap(devpriv->io_addr);
907         }
908         /* XXX */
909
910         return 0;
911 }
912
913 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
914 static int setup_pci(struct comedi_device * dev);
915
916 static int dt_pci_probe(struct comedi_device * dev, int bus, int slot)
917 {
918         int board;
919         int ret;
920         struct pci_dev *pcidev;
921
922         pcidev = NULL;
923         while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
924                 if ((bus == 0 && slot == 0) ||
925                         (pcidev->bus->number == bus &&
926                          PCI_SLOT(pcidev->devfn) == slot)) {
927                         break;
928                 }
929         }
930         devpriv->pci_dev = pcidev;
931
932         if (board >= 0)
933                 dev->board_ptr = dt3k_boardtypes + board;
934
935         if (!devpriv->pci_dev)
936                 return 0;
937
938         if ((ret = setup_pci(dev)) < 0)
939                 return ret;
940
941         return 1;
942 }
943
944 static int setup_pci(struct comedi_device * dev)
945 {
946         resource_size_t addr;
947         int ret;
948
949         ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
950         if (ret < 0)
951                 return ret;
952
953         addr = pci_resource_start(devpriv->pci_dev, 0);
954         devpriv->phys_addr = addr;
955         devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
956         if (!devpriv->io_addr)
957                 return -ENOMEM;
958 #if DEBUG
959         printk("0x%08llx mapped to %p, ",
960                 (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
961 #endif
962
963         return 0;
964 }
965
966 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
967 {
968         int i;
969
970         for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
971                 from != NULL;
972                 from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
973                 for (i = 0; i < n_dt3k_boards; i++) {
974                         if (from->device == dt3k_boardtypes[i].device_id) {
975                                 *board = i;
976                                 return from;
977                         }
978                 }
979                 printk("unknown Data Translation PCI device found with device_id=0x%04x\n", from->device);
980         }
981         *board = -1;
982         return from;
983 }