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