Staging: comedi: non working tests on unsigned cmd->convert_arg
[linux-2.6] / drivers / staging / comedi / drivers / dt2811.c
1 /*
2    comedi/drivers/dt2811.c
3    Hardware driver for Data Translation DT2811
4
5    COMEDI - Linux Control and Measurement Device Interface
6    History:
7    Base Version  - David A. Schleef <ds@schleef.org>
8    December 1998 - Updated to work.  David does not have a DT2811
9    board any longer so this was suffering from bitrot.
10    Updated performed by ...
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 2 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program; if not, write to the Free Software
24    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  */
26 /*
27 Driver: dt2811
28 Description: Data Translation DT2811
29 Author: ds
30 Devices: [Data Translation] DT2811-PGL (dt2811-pgl), DT2811-PGH (dt2811-pgh)
31 Status: works
32
33 Configuration options:
34   [0] - I/O port base address
35   [1] - IRQ, although this is currently unused
36   [2] - A/D reference
37           0 = signle-ended
38           1 = differential
39           2 = pseudo-differential (common reference)
40   [3] - A/D range
41           0 = [-5,5]
42           1 = [-2.5,2.5]
43           2 = [0,5]
44   [4] - D/A 0 range (same choices)
45   [4] - D/A 1 range (same choices)
46 */
47
48 #include "../comedidev.h"
49
50 #include <linux/ioport.h>
51
52 static const char *driver_name = "dt2811";
53
54 static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = { 4, {
55                         RANGE(0, 5),
56                         RANGE(0, 2.5),
57                         RANGE(0, 1.25),
58                         RANGE(0, 0.625)
59         }
60 };
61 static const struct comedi_lrange range_dt2811_pgh_ai_2_5_bipolar = { 4, {
62                         RANGE(-2.5, 2.5),
63                         RANGE(-1.25, 1.25),
64                         RANGE(-0.625, 0.625),
65                         RANGE(-0.3125, 0.3125)
66         }
67 };
68 static const struct comedi_lrange range_dt2811_pgh_ai_5_bipolar = { 4, {
69                         RANGE(-5, 5),
70                         RANGE(-2.5, 2.5),
71                         RANGE(-1.25, 1.25),
72                         RANGE(-0.625, 0.625)
73         }
74 };
75 static const struct comedi_lrange range_dt2811_pgl_ai_5_unipolar = { 4, {
76                         RANGE(0, 5),
77                         RANGE(0, 0.5),
78                         RANGE(0, 0.05),
79                         RANGE(0, 0.01)
80         }
81 };
82 static const struct comedi_lrange range_dt2811_pgl_ai_2_5_bipolar = { 4, {
83                         RANGE(-2.5, 2.5),
84                         RANGE(-0.25, 0.25),
85                         RANGE(-0.025, 0.025),
86                         RANGE(-0.005, 0.005)
87         }
88 };
89 static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { 4, {
90                         RANGE(-5, 5),
91                         RANGE(-0.5, 0.5),
92                         RANGE(-0.05, 0.05),
93                         RANGE(-0.01, 0.01)
94         }
95 };
96
97 /*
98
99    0x00    ADCSR R/W  A/D Control/Status Register
100    bit 7 - (R) 1 indicates A/D conversion done
101    reading ADDAT clears bit
102    (W) ignored
103    bit 6 - (R) 1 indicates A/D error
104    (W) ignored
105    bit 5 - (R) 1 indicates A/D busy, cleared at end
106    of conversion
107    (W) ignored
108    bit 4 - (R) 0
109    (W)
110    bit 3 - (R) 0
111    bit 2 - (R/W) 1 indicates interrupts enabled
112    bits 1,0 - (R/W) mode bits
113    00  single conversion on ADGCR load
114    01  continuous conversion, internal clock,
115    (clock enabled on ADGCR load)
116    10  continuous conversion, internal clock,
117    external trigger
118    11  continuous conversion, external clock,
119    external trigger
120
121    0x01    ADGCR R/W A/D Gain/Channel Register
122    bit 6,7 - (R/W) gain select
123    00  gain=1, both PGH, PGL models
124    01  gain=2 PGH, 10 PGL
125    10  gain=4 PGH, 100 PGL
126    11  gain=8 PGH, 500 PGL
127    bit 4,5 - reserved
128    bit 3-0 - (R/W) channel select
129    channel number from 0-15
130
131    0x02,0x03 (R) ADDAT A/D Data Register
132    (W) DADAT0 D/A Data Register 0
133    0x02 low byte
134    0x03 high byte
135
136    0x04,0x05 (W) DADAT0 D/A Data Register 1
137
138    0x06 (R) DIO0 Digital Input Port 0
139    (W) DIO1 Digital Output Port 1
140
141    0x07 TMRCTR (R/W) Timer/Counter Register
142    bits 6,7 - reserved
143    bits 5-3 - Timer frequency control (mantissa)
144    543  divisor  freqency (kHz)
145    000  1        600
146    001  10       60
147    010  2        300
148    011  3        200
149    100  4        150
150    101  5        120
151    110  6        100
152    111  12       50
153    bits 2-0 - Timer frequency control (exponent)
154    210  multiply divisor/divide frequency by
155    000  1
156    001  10
157    010  100
158    011  1000
159    100  10000
160    101  100000
161    110  1000000
162    111  10000000
163
164  */
165
166 #define TIMEOUT 10000
167
168 #define DT2811_SIZE 8
169
170 #define DT2811_ADCSR 0
171 #define DT2811_ADGCR 1
172 #define DT2811_ADDATLO 2
173 #define DT2811_ADDATHI 3
174 #define DT2811_DADAT0LO 2
175 #define DT2811_DADAT0HI 3
176 #define DT2811_DADAT1LO 4
177 #define DT2811_DADAT1HI 5
178 #define DT2811_DIO 6
179 #define DT2811_TMRCTR 7
180
181 /*
182  * flags
183  */
184
185 /* ADCSR */
186
187 #define DT2811_ADDONE   0x80
188 #define DT2811_ADERROR  0x40
189 #define DT2811_ADBUSY   0x20
190 #define DT2811_CLRERROR 0x10
191 #define DT2811_INTENB   0x04
192 #define DT2811_ADMODE   0x03
193
194 struct dt2811_board {
195
196         const char *name;
197         const struct comedi_lrange *bip_5;
198         const struct comedi_lrange *bip_2_5;
199         const struct comedi_lrange *unip_5;
200 };
201
202 static const struct dt2811_board boardtypes[] = {
203         {"dt2811-pgh",
204                         &range_dt2811_pgh_ai_5_bipolar,
205                         &range_dt2811_pgh_ai_2_5_bipolar,
206                         &range_dt2811_pgh_ai_5_unipolar,
207                 },
208         {"dt2811-pgl",
209                         &range_dt2811_pgl_ai_5_bipolar,
210                         &range_dt2811_pgl_ai_2_5_bipolar,
211                         &range_dt2811_pgl_ai_5_unipolar,
212                 },
213 };
214
215 #define this_board ((const struct dt2811_board *)dev->board_ptr)
216
217 static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it);
218 static int dt2811_detach(struct comedi_device *dev);
219 static struct comedi_driver driver_dt2811 = {
220       driver_name:"dt2811",
221       module:THIS_MODULE,
222       attach:dt2811_attach,
223       detach:dt2811_detach,
224       board_name:&boardtypes[0].name,
225       num_names:sizeof(boardtypes) / sizeof(struct dt2811_board),
226       offset:sizeof(struct dt2811_board),
227 };
228
229 COMEDI_INITCLEANUP(driver_dt2811);
230
231 static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
232         struct comedi_insn *insn, unsigned int *data);
233 static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
234         struct comedi_insn *insn, unsigned int *data);
235 static int dt2811_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
236         struct comedi_insn *insn, unsigned int *data);
237 static int dt2811_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
238         struct comedi_insn *insn, unsigned int *data);
239 static int dt2811_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
240         struct comedi_insn *insn, unsigned int *data);
241
242 enum { card_2811_pgh, card_2811_pgl };
243
244 struct dt2811_private {
245         int ntrig;
246         int curadchan;
247         enum {
248                 adc_singleended, adc_diff, adc_pseudo_diff
249         } adc_mux;
250         enum {
251                 dac_bipolar_5, dac_bipolar_2_5, dac_unipolar_5
252         } dac_range[2];
253         const struct comedi_lrange *range_type_list[2];
254         unsigned int ao_readback[2];
255 };
256
257 #define devpriv ((struct dt2811_private *)dev->private)
258
259 static const struct comedi_lrange *dac_range_types[] = {
260         &range_bipolar5,
261         &range_bipolar2_5,
262         &range_unipolar5
263 };
264
265 #define DT2811_TIMEOUT 5
266
267 #if 0
268 static irqreturn_t dt2811_interrupt(int irq, void *d)
269 {
270         int lo, hi;
271         int data;
272         struct comedi_device *dev = d;
273
274         if (!dev->attached) {
275                 comedi_error(dev, "spurious interrupt");
276                 return IRQ_HANDLED;
277         }
278
279         lo = inb(dev->iobase + DT2811_ADDATLO);
280         hi = inb(dev->iobase + DT2811_ADDATHI);
281
282         data = lo + (hi << 8);
283
284         if (!(--devpriv->ntrig)) {
285                 /* how to turn off acquisition */
286                 s->async->events |= COMEDI_SB_EOA;
287         }
288         comedi_event(dev, s);
289         return IRQ_HANDLED;
290 }
291 #endif
292
293 /*
294   options[0]   Board base address
295   options[1]   IRQ
296   options[2]   Input configuration
297                  0 == single-ended
298                  1 == differential
299                  2 == pseudo-differential
300   options[3]   Analog input range configuration
301                  0 == bipolar 5  (-5V -- +5V)
302                  1 == bipolar 2.5V  (-2.5V -- +2.5V)
303                  2 == unipolar 5V  (0V -- +5V)
304   options[4]   Analog output 0 range configuration
305                  0 == bipolar 5  (-5V -- +5V)
306                  1 == bipolar 2.5V  (-2.5V -- +2.5V)
307                  2 == unipolar 5V  (0V -- +5V)
308   options[5]   Analog output 1 range configuration
309                  0 == bipolar 5  (-5V -- +5V)
310                  1 == bipolar 2.5V  (-2.5V -- +2.5V)
311                  2 == unipolar 5V  (0V -- +5V)
312 */
313
314 static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
315 {
316         /* int i, irq; */
317         /* unsigned long irqs; */
318         /* long flags; */
319
320         int ret;
321         struct comedi_subdevice *s;
322         unsigned long iobase;
323
324         iobase = it->options[0];
325
326         printk("comedi%d: dt2811: base=0x%04lx\n", dev->minor, iobase);
327
328         if (!request_region(iobase, DT2811_SIZE, driver_name)) {
329                 printk("I/O port conflict\n");
330                 return -EIO;
331         }
332
333         dev->iobase = iobase;
334         dev->board_name = this_board->name;
335
336 #if 0
337         outb(0, dev->iobase + DT2811_ADCSR);
338         comedi_udelay(100);
339         i = inb(dev->iobase + DT2811_ADDATLO);
340         i = inb(dev->iobase + DT2811_ADDATHI);
341 #endif
342
343 #if 0
344         irq = it->options[1];
345         if (irq < 0) {
346                 save_flags(flags);
347                 sti();
348                 irqs = probe_irq_on();
349
350                 outb(DT2811_CLRERROR | DT2811_INTENB,
351                         dev->iobase + DT2811_ADCSR);
352                 outb(0, dev->iobase + DT2811_ADGCR);
353
354                 comedi_udelay(100);
355
356                 irq = probe_irq_off(irqs);
357                 restore_flags(flags);
358
359                 /*outb(DT2811_CLRERROR|DT2811_INTENB,dev->iobase+DT2811_ADCSR); */
360
361                 if (inb(dev->iobase + DT2811_ADCSR) & DT2811_ADERROR) {
362                         printk("error probing irq (bad) \n");
363                 }
364                 dev->irq = 0;
365                 if (irq > 0) {
366                         i = inb(dev->iobase + DT2811_ADDATLO);
367                         i = inb(dev->iobase + DT2811_ADDATHI);
368                         printk("(irq = %d)\n", irq);
369                         ret = comedi_request_irq(irq, dt2811_interrupt, 0,
370                                 driver_name, dev);
371                         if (ret < 0)
372                                 return -EIO;
373                         dev->irq = irq;
374                 } else if (irq == 0) {
375                         printk("(no irq)\n");
376                 } else {
377                         printk("( multiple irq's -- this is bad! )\n");
378                 }
379         }
380 #endif
381
382         if ((ret = alloc_subdevices(dev, 4)) < 0)
383                 return ret;
384         if ((ret = alloc_private(dev, sizeof(struct dt2811_private))) < 0)
385                 return ret;
386         switch (it->options[2]) {
387         case 0:
388                 devpriv->adc_mux = adc_singleended;
389                 break;
390         case 1:
391                 devpriv->adc_mux = adc_diff;
392                 break;
393         case 2:
394                 devpriv->adc_mux = adc_pseudo_diff;
395                 break;
396         default:
397                 devpriv->adc_mux = adc_singleended;
398                 break;
399         }
400         switch (it->options[4]) {
401         case 0:
402                 devpriv->dac_range[0] = dac_bipolar_5;
403                 break;
404         case 1:
405                 devpriv->dac_range[0] = dac_bipolar_2_5;
406                 break;
407         case 2:
408                 devpriv->dac_range[0] = dac_unipolar_5;
409                 break;
410         default:
411                 devpriv->dac_range[0] = dac_bipolar_5;
412                 break;
413         }
414         switch (it->options[5]) {
415         case 0:
416                 devpriv->dac_range[1] = dac_bipolar_5;
417                 break;
418         case 1:
419                 devpriv->dac_range[1] = dac_bipolar_2_5;
420                 break;
421         case 2:
422                 devpriv->dac_range[1] = dac_unipolar_5;
423                 break;
424         default:
425                 devpriv->dac_range[1] = dac_bipolar_5;
426                 break;
427         }
428
429         s = dev->subdevices + 0;
430         /* initialize the ADC subdevice */
431         s->type = COMEDI_SUBD_AI;
432         s->subdev_flags = SDF_READABLE | SDF_GROUND;
433         s->n_chan = devpriv->adc_mux == adc_diff ? 8 : 16;
434         s->insn_read = dt2811_ai_insn;
435         s->maxdata = 0xfff;
436         switch (it->options[3]) {
437         case 0:
438         default:
439                 s->range_table = this_board->bip_5;
440                 break;
441         case 1:
442                 s->range_table = this_board->bip_2_5;
443                 break;
444         case 2:
445                 s->range_table = this_board->unip_5;
446                 break;
447         }
448
449         s = dev->subdevices + 1;
450         /* ao subdevice */
451         s->type = COMEDI_SUBD_AO;
452         s->subdev_flags = SDF_WRITABLE;
453         s->n_chan = 2;
454         s->insn_write = dt2811_ao_insn;
455         s->insn_read = dt2811_ao_insn_read;
456         s->maxdata = 0xfff;
457         s->range_table_list = devpriv->range_type_list;
458         devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]];
459         devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]];
460
461         s = dev->subdevices + 2;
462         /* di subdevice */
463         s->type = COMEDI_SUBD_DI;
464         s->subdev_flags = SDF_READABLE;
465         s->n_chan = 8;
466         s->insn_bits = dt2811_di_insn_bits;
467         s->maxdata = 1;
468         s->range_table = &range_digital;
469
470         s = dev->subdevices + 3;
471         /* do subdevice */
472         s->type = COMEDI_SUBD_DO;
473         s->subdev_flags = SDF_WRITABLE;
474         s->n_chan = 8;
475         s->insn_bits = dt2811_do_insn_bits;
476         s->maxdata = 1;
477         s->state = 0;
478         s->range_table = &range_digital;
479
480         return 0;
481 }
482
483 static int dt2811_detach(struct comedi_device *dev)
484 {
485         printk("comedi%d: dt2811: remove\n", dev->minor);
486
487         if (dev->irq) {
488                 comedi_free_irq(dev->irq, dev);
489         }
490         if (dev->iobase) {
491                 release_region(dev->iobase, DT2811_SIZE);
492         }
493
494         return 0;
495 }
496
497 static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
498         struct comedi_insn *insn, unsigned int *data)
499 {
500         int chan = CR_CHAN(insn->chanspec);
501         int timeout = DT2811_TIMEOUT;
502         int i;
503
504         for (i = 0; i < insn->n; i++) {
505                 outb(chan, dev->iobase + DT2811_ADGCR);
506
507                 while (timeout
508                         && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY)
509                         timeout--;
510                 if (!timeout)
511                         return -ETIME;
512
513                 data[i] = inb(dev->iobase + DT2811_ADDATLO);
514                 data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
515                 data[i] &= 0xfff;
516         }
517
518         return i;
519 }
520
521 #if 0
522 /* Wow.  This is code from the Comedi stone age.  But it hasn't been
523  * replaced, so I'll let it stay. */
524 int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig)
525 {
526         struct comedi_device *dev = comedi_devices + minor;
527
528         if (adtrig->n < 1)
529                 return 0;
530         dev->curadchan = adtrig->chan;
531         switch (dev->i_admode) {
532         case COMEDI_MDEMAND:
533                 dev->ntrig = adtrig->n - 1;
534                 /*printk("dt2811: AD soft trigger\n"); */
535                 /*outb(DT2811_CLRERROR|DT2811_INTENB,dev->iobase+DT2811_ADCSR); */ /* not neccessary */
536                 outb(dev->curadchan, dev->iobase + DT2811_ADGCR);
537                 do_gettimeofday(&trigtime);
538                 break;
539         case COMEDI_MCONTS:
540                 dev->ntrig = adtrig->n;
541                 break;
542         }
543
544         return 0;
545 }
546 #endif
547
548 static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
549         struct comedi_insn *insn, unsigned int *data)
550 {
551         int i;
552         int chan;
553
554         chan = CR_CHAN(insn->chanspec);
555
556         for (i = 0; i < insn->n; i++) {
557                 outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
558                 outb((data[i] >> 8) & 0xff,
559                         dev->iobase + DT2811_DADAT0HI + 2 * chan);
560                 devpriv->ao_readback[chan] = data[i];
561         }
562
563         return i;
564 }
565
566 static int dt2811_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
567         struct comedi_insn *insn, unsigned int *data)
568 {
569         int i;
570         int chan;
571
572         chan = CR_CHAN(insn->chanspec);
573
574         for (i = 0; i < insn->n; i++) {
575                 data[i] = devpriv->ao_readback[chan];
576         }
577
578         return i;
579 }
580
581 static int dt2811_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
582         struct comedi_insn *insn, unsigned int *data)
583 {
584         if (insn->n != 2)
585                 return -EINVAL;
586
587         data[1] = inb(dev->iobase + DT2811_DIO);
588
589         return 2;
590 }
591
592 static int dt2811_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
593         struct comedi_insn *insn, unsigned int *data)
594 {
595         if (insn->n != 2)
596                 return -EINVAL;
597
598         s->state &= ~data[0];
599         s->state |= data[0] & data[1];
600         outb(s->state, dev->iobase + DT2811_DIO);
601
602         data[1] = s->state;
603
604         return 2;
605 }