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