Fix bug in ao code related to warning about return value !=
[comedi.git] / comedi / drivers / das08.c
1 /*
2     comedi/drivers/das.c
3     DAS08 driver
4
5     COMEDI - Linux Control and Measurement Device Interface
6     Copyright (C) 2000 David A. Schleef <ds@stm.lbl.gov>
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
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/comedidev.h>
28 #include <linux/errno.h>
29 #include <linux/ioport.h>
30 #include <asm/io.h>
31 #include <linux/malloc.h>
32 #include <linux/delay.h>
33 #include <8255.h>
34
35
36 #define DAS08_SIZE 16
37
38 /*
39     cio-das08.pdf
40
41   "das08"
42
43   0     a/d bits 0-3            start 8 bit
44   1     a/d bits 4-11           start 12 bit
45   2     eoc, ip1-3, irq, mux    op1-4, inte, mux
46   3     unused                  unused
47   4567  8254
48   89ab  8255
49
50   requires hard-wiring for async ai
51
52 */
53
54 #define DAS08_LSB               0
55 #define DAS08_MSB               1
56 #define DAS08_TRIG_12BIT        1
57 #define DAS08_STATUS            2
58 #define   DAS08_EOC                     (1<<7)
59 #define   DAS08_IRQ                     (1<<3)
60 #define   DAS08_IP(x)                   (((x)>>4)&0x7)
61 #define DAS08_CONTROL           2
62 #define   DAS08_MUX(x)                  ((x)<<0)
63 #define   DAS08_INTE                    (1<<3)
64 #define   DAS08_OP(x)                   ((x)<<4)
65
66 /*
67     cio-das08jr.pdf
68
69   "das08/jr-ao"
70
71   0     a/d bits 0-3            unused
72   1     a/d bits 4-11           start 12 bit
73   2     eoc, mux                mux
74   3     di                      do
75   4     unused                  ao0_lsb
76   5     unused                  ao0_msb
77   6     unused                  ao1_lsb
78   7     unused                  ao1_msb
79
80 */
81
82 #define DAS08JR_DIO             3
83 #define DAS08JR_AO_LSB(x)       ((x)?6:4)
84 #define DAS08JR_AO_MSB(x)       ((x)?7:5)
85
86 /*
87     cio-das08_aox.pdf
88
89   "das08-aoh"
90   "das08-aol"
91   "das08-aom"
92
93   0     a/d bits 0-3            start 8 bit
94   1     a/d bits 4-11           start 12 bit
95   2     eoc, ip1-3, irq, mux    op1-4, inte, mux
96   3     mux, gain status        gain control
97   4567  8254
98   8     unused                  ao0_lsb
99   9     unused                  ao0_msb
100   a     unused                  ao1_lsb
101   b     unused                  ao1_msb
102   89ab  
103   cdef  8255
104 */
105
106 #define DAS08AO_GAIN_CONTROL    3
107 #define DAS08AO_GAIN_STATUS     3
108
109 #define DAS08AO_AO_LSB(x)       ((x)?0xa:8)
110 #define DAS08AO_AO_MSB(x)       ((x)?0xb:9)
111 #define DAS08AO_AO_UPDATE       8
112
113 /* gainlist same as _pgx_ below */
114
115 /*
116     cio-das08pgx.pdf
117
118     "das08pgx"
119
120   0     a/d bits 0-3            start 8 bit
121   1     a/d bits 4-11           start 12 bit
122   2     eoc, ip1-3, irq, mux    op1-4, inte, mux
123   3     mux, gain status        gain control
124   4567  8254
125
126 */
127
128 static int das08_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
129 static int das08_di_rbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
130 static int das08_do_wbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
131 static int das08jr_di_rbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
132 static int das08jr_do_wbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
133 static int das08jr_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
134 static int das08ao_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
135
136 static comedi_lrange range_das08_pgl = { 9, {
137         BIP_RANGE(10),
138         BIP_RANGE(5),
139         BIP_RANGE(2.5),
140         BIP_RANGE(1.25),
141         BIP_RANGE(0.625),
142         UNI_RANGE(10),
143         UNI_RANGE(5),
144         UNI_RANGE(2.5),
145         UNI_RANGE(1.25)
146 }};
147 static comedi_lrange range_das08_pgh = { 12, {
148         BIP_RANGE(10),
149         BIP_RANGE(5),
150         BIP_RANGE(1),
151         BIP_RANGE(0.5),
152         BIP_RANGE(0.1),
153         BIP_RANGE(0.05),
154         BIP_RANGE(0.01),
155         BIP_RANGE(0.005),
156         UNI_RANGE(10),
157         UNI_RANGE(1),
158         UNI_RANGE(0.1),
159         UNI_RANGE(0.01),
160 }};
161 static comedi_lrange range_das08_pgm = { 9, {
162         BIP_RANGE(10),
163         BIP_RANGE(5),
164         BIP_RANGE(0.5),
165         BIP_RANGE(0.05),
166         BIP_RANGE(0.01),
167         UNI_RANGE(10),
168         UNI_RANGE(1),
169         UNI_RANGE(0.1),
170         UNI_RANGE(0.01)
171 }};
172
173 enum { das08_pg_none, das08_pgh, das08_pgl, das08_pgm };
174
175 static comedi_lrange *das08_ai_lranges[]={
176         &range_bipolar10, /* XXX guess */
177         &range_das08_pgh,
178         &range_das08_pgl,
179         &range_das08_pgm,
180 };
181
182 static int das08_pgh_gainlist[] = { 8, 0, 10, 2, 12, 4, 14, 6, 1, 3, 5, 7 };
183 static int das08_pgl_gainlist[] = { 8, 0, 2, 4, 6, 1, 3, 5, 7 };
184 static int das08_pgm_gainlist[] = { 8, 0, 10, 12, 14, 9, 11, 13, 15 };
185
186 static int *das08_gainlists[] = {
187         NULL,
188         das08_pgh_gainlist,
189         das08_pgl_gainlist,
190         das08_pgm_gainlist,
191 };
192
193 typedef struct das08_board_struct{
194         char            *name;
195         void            *ai;
196         unsigned int    ai_nbits;
197         unsigned int    ai_pg;
198         void            *ao;
199         unsigned int    ao_nbits;
200         void            *di;
201         void            *do_;
202         unsigned int    i8255_offset;
203         unsigned int    i8254_offset;
204 } das08_board;
205 static struct das08_board_struct das08_boards[]={
206         {
207         name:           "das08",                // cio-das08.pdf
208         ai:             das08_ai_rinsn,
209         ai_nbits:       12,
210         ai_pg:          das08_pg_none,
211         ao:             NULL,
212         ao_nbits:       12,
213         di:             das08_di_rbits,
214         do_:            das08_do_wbits,
215         i8255_offset:   8,
216         i8254_offset:   4,
217         },
218         {
219         name:           "das08-pgm",            // cio-das08pgx.pdf
220         ai:             das08_ai_rinsn,
221         ai_nbits:       12,
222         ai_pg:          das08_pgm,
223         ao:             NULL,
224         di:             das08_di_rbits,
225         do_:            das08_do_wbits,
226         i8255_offset:   0,
227         i8254_offset:   0x04,
228         },
229         {
230         name:           "das08-pgh",            // cio-das08pgx.pdf
231         ai:             das08_ai_rinsn,
232         ai_nbits:       12,
233         ai_pg:          das08_pgh,
234         ao:             NULL,
235         di:             das08_di_rbits,
236         do_:            das08_do_wbits,
237         i8255_offset:   0,
238         i8254_offset:   0x04,
239         },
240         {
241         name:           "das08-pgl",            // cio-das08pgx.pdf
242         ai:             das08_ai_rinsn,
243         ai_nbits:       12,
244         ai_pg:          das08_pgl,
245         ao:             NULL,
246         di:             das08_di_rbits,
247         do_:            das08_do_wbits,
248         i8255_offset:   0,
249         i8254_offset:   0x04,
250         },
251         {
252         name:           "das08-aoh",            // cio-das08_aox.pdf
253         ai:             das08_ai_rinsn,
254         ai_nbits:       12,
255         ai_pg:          das08_pgh,
256         ao:             das08ao_ao_winsn,       // 8
257         ao_nbits:       12,
258         di:             das08_di_rbits,
259         do_:            das08_do_wbits,
260         i8255_offset:   0x0c,
261         i8254_offset:   0x04,
262         },
263         {
264         name:           "das08-aol",            // cio-das08_aox.pdf
265         ai:             das08_ai_rinsn,
266         ai_nbits:       12,
267         ai_pg:          das08_pgl,
268         ao:             das08ao_ao_winsn,       // 8
269         ao_nbits:       12,
270         di:             das08_di_rbits,
271         do_:            das08_do_wbits,
272         i8255_offset:   0x0c,
273         i8254_offset:   0x04,
274         },
275         {
276         name:           "das08-aom",            // cio-das08_aox.pdf
277         ai:             das08_ai_rinsn,
278         ai_nbits:       12,
279         ai_pg:          das08_pgm,
280         ao:             das08ao_ao_winsn,       // 8
281         ao_nbits:       12,
282         di:             das08_di_rbits,
283         do_:            das08_do_wbits,
284         i8255_offset:   0x0c,
285         i8254_offset:   0x04,
286         },
287         {
288         name:           "das08/jr-ao",          // cio-das08-jr-ao.pdf
289         ai:             das08_ai_rinsn,
290         ai_nbits:       12,
291         ai_pg:          das08_pg_none,
292         ao:             das08jr_ao_winsn,
293         ao_nbits:       12,
294         di:             das08jr_di_rbits,
295         do_:            das08jr_do_wbits,
296         i8255_offset:   0,
297         i8254_offset:   0,
298         },
299         {
300         name:           "das08jr-16-ao",        // cio-das08jr-16-ao.pdf
301         ai:             das08_ai_rinsn,
302         ai_nbits:       16,
303         ai_pg:          das08_pg_none,
304         ao:             das08jr_ao_winsn,
305         ao_nbits:       16,
306         di:             das08jr_di_rbits,
307         do_:            das08jr_do_wbits,
308         i8255_offset:   0,
309         i8254_offset:   0x04,
310         },
311 #if 0
312         {
313         name:           "das08/f",
314         },
315         {
316         name:           "das08jr",
317         },
318         {
319         name:           "das08jr/16",
320         },
321         {
322         name:           "das48-pga",            // cio-das48-pga.pdf
323         },
324         {
325         name:           "das08-pga-g2",         // a KM board
326         },
327 #endif
328 };
329 #define n_boardtypes sizeof(das08_boards)/sizeof(das08_boards[0])
330
331
332 struct das08_private_struct{
333         unsigned int    do_bits;
334         unsigned int    *pg_gainlist;
335 };
336
337 #define devpriv ((struct das08_private_struct *)dev->private)
338 #define thisboard ((struct das08_board_struct *)dev->board_ptr)
339
340 #define TIMEOUT 1000
341
342 static int das08_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
343 {
344         int i,n;
345         int chan;
346         int range;
347         int lsb,msb;
348
349         chan = CR_CHAN(insn->chanspec);
350         range = CR_RANGE(insn->chanspec);
351
352         /* clear crap */
353         inb(dev->iobase+DAS08_LSB);
354         inb(dev->iobase+DAS08_MSB);
355
356         /* set multiplexer */
357         outb_p(DAS08_MUX(chan) | devpriv->do_bits,dev->iobase+DAS08_CONTROL);
358         
359         if(thisboard->ai_pg!=das08_pg_none){
360                 /* set gain/range */
361                 range = CR_RANGE(insn->chanspec);
362                 outb_p(devpriv->pg_gainlist[range],dev->iobase+DAS08AO_GAIN_CONTROL);
363         }
364
365         /* How long should we wait for MUX to settle? */
366         //udelay(5);
367
368         for(n=0;n<insn->n;n++){
369                 /* trigger conversion */
370                 outb_p(0,dev->iobase+DAS08_TRIG_12BIT);
371
372                 for(i=0;i<TIMEOUT;i++){
373                         if(!(inb(dev->iobase+DAS08_STATUS)&DAS08_EOC))
374                                 break;
375                 }
376                 if(i==TIMEOUT){
377                         rt_printk("das08: timeout\n");
378                         return -ETIME;
379                 }
380                 msb = inb(dev->iobase + DAS08_MSB);
381                 lsb = inb(dev->iobase + DAS08_LSB);
382                 if(thisboard->ai_nbits==12){
383                         data[n] = (lsb>>4) | (msb << 4);
384                 }else{
385                         data[n] = lsb | (msb << 8);
386                 }
387         }
388
389         return n;
390 }
391
392 static int das08_di_rbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
393 {
394         insn->data[0]=DAS08_IP(inb(dev->iobase+DAS08_STATUS));
395
396         return 1;
397 }
398
399 static int das08_do_wbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
400 {
401         /* XXX race with ai */
402
403         devpriv->do_bits = DAS08_OP(insn->data[0]);
404
405         outb(devpriv->do_bits,dev->iobase+DAS08_CONTROL);
406
407         return 1;
408 }
409
410 static int das08jr_di_rbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
411 {
412         insn->data[0]=inb(dev->iobase+DAS08JR_DIO);
413
414         return 1;
415 }
416
417 static int das08jr_do_wbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
418 {
419         outb(insn->data[0],dev->iobase+DAS08JR_DIO);
420
421         return 1;
422 }
423
424 static int das08jr_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
425 {
426         int n;
427         int lsb,msb;
428         int chan;
429
430         lsb=insn->data[0]&0xff;
431         msb=(insn->data[0]>>8)&0xf;
432
433         chan=CR_CHAN(insn->chanspec);
434
435         for(n=0;n<insn->n;n++){
436 #if 0
437                 outb(lsb,dev->iobase+devpriv->ao_offset_lsb[chan]);
438                 outb(msb,dev->iobase+devpriv->ao_offset_msb[chan]);
439 #else
440                 outb(lsb,dev->iobase+DAS08JR_AO_LSB(chan));
441                 outb(msb,dev->iobase+DAS08JR_AO_MSB(chan));
442 #endif
443
444                 /* load DACs */
445                 inb(dev->iobase+DAS08JR_DIO);
446         }
447
448         return n;
449 }
450
451 /*
452  *
453  * The -aox boards have the DACs at a different offset and use
454  * a different method to force an update.
455  *
456  */
457 static int das08ao_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
458 {
459         int n;
460         int lsb,msb;
461         int chan;
462
463         lsb=insn->data[0]&0xff;
464         msb=(insn->data[0]>>8)&0xf;
465
466         chan=CR_CHAN(insn->chanspec);
467
468         for(n=0;n<insn->n;n++){
469 #if 0
470                 outb(lsb,dev->iobase+devpriv->ao_offset_lsb[chan]);
471                 outb(msb,dev->iobase+devpriv->ao_offset_msb[chan]);
472 #else
473                 outb(lsb,dev->iobase+DAS08AO_AO_LSB(chan));
474                 outb(msb,dev->iobase+DAS08AO_AO_MSB(chan));
475 #endif
476
477                 /* load DACs */
478                 inb(dev->iobase+DAS08AO_AO_UPDATE);
479         }
480
481         return n;
482 }
483
484 static int das08_attach(comedi_device *dev,comedi_devconfig *it);
485 static int das08_detach(comedi_device *dev);
486
487 comedi_driver driver_das08={
488         driver_name:    "das08",
489         module:         THIS_MODULE,
490         attach:         das08_attach,
491         detach:         das08_detach,
492         board_name:     das08_boards,
493         num_names:      sizeof(das08_boards)/sizeof(struct das08_board_struct),
494         offset:         sizeof(struct das08_board_struct),
495 };
496
497 static int das08_attach(comedi_device *dev,comedi_devconfig *it)
498 {
499         comedi_subdevice *s;
500         int ret;
501
502         dev->iobase=it->options[0];
503         printk("comedi%d: das08: 0x%04x",dev->minor,dev->iobase);
504         if(check_region(dev->iobase,DAS08_SIZE)<0){
505                 printk(" I/O port conflict\n");
506                 return -EIO;
507         }
508
509         dev->board_name = thisboard->name;
510
511         dev->n_subdevices=5;
512         if((ret=alloc_subdevices(dev))<0)
513                 return ret;
514         if((ret=alloc_private(dev,sizeof(struct das08_private_struct)))<0)
515                 return ret;
516
517         request_region(dev->iobase,DAS08_SIZE,"das08");
518
519         s=dev->subdevices+0;
520         /* ai */
521         if(thisboard->ai){
522                 s->type=COMEDI_SUBD_AI;
523                 s->subdev_flags = SDF_READABLE;
524                 s->n_chan = 8;
525                 s->maxdata = (1<<thisboard->ai_nbits)-1;
526                 s->range_table = das08_ai_lranges[thisboard->ai_pg];
527                 s->insn_read = thisboard->ai;
528                 devpriv->pg_gainlist = das08_gainlists[thisboard->ai_pg];
529         }else{
530                 s->type=COMEDI_SUBD_UNUSED;
531         }
532
533         s=dev->subdevices+1;
534         /* ao */
535         if(thisboard->ao){
536                 s->type=COMEDI_SUBD_AO;
537                 s->subdev_flags = SDF_WRITEABLE;
538                 s->n_chan = 2;
539                 s->maxdata = (1<<thisboard->ao_nbits)-1;
540                 s->range_table = &range_bipolar5;
541                 s->insn_write = thisboard->ao;
542         }else{
543                 s->type=COMEDI_SUBD_UNUSED;
544         }
545
546         s=dev->subdevices+2;
547         /* di */
548         if(thisboard->di){
549                 s->type=COMEDI_SUBD_DI;
550                 s->subdev_flags = SDF_READABLE;
551                 s->n_chan = (thisboard->di==das08_di_rbits)?3:8;
552                 s->maxdata = 1;
553                 s->range_table = &range_digital;
554                 s->insn_read = thisboard->di; /* XXX */
555         }else{
556                 s->type=COMEDI_SUBD_UNUSED;
557         }
558
559         s=dev->subdevices+3;
560         /* do */
561         if(thisboard->do_){
562                 s->type=COMEDI_SUBD_DO;
563                 s->subdev_flags = SDF_WRITEABLE;
564                 s->n_chan = (thisboard->do_==das08_do_wbits)?4:8;
565                 s->maxdata = 1;
566                 s->range_table = &range_digital;
567                 s->insn_write = thisboard->do_; /* XXX */
568         }else{
569                 s->type=COMEDI_SUBD_UNUSED;
570         }
571
572         s=dev->subdevices+4;
573         /* 8255 */
574         if(thisboard->i8255_offset!=0){
575                 subdev_8255_init(dev,s,NULL,(void *)(dev->iobase+
576                         thisboard->i8255_offset));
577         }else{
578                 s->type=COMEDI_SUBD_UNUSED;
579         }
580
581         return 0;
582 }
583
584 static int das08_detach(comedi_device *dev)
585 {
586         printk(KERN_INFO "comedi%d: das08: remove\n",dev->minor);
587
588         release_region(dev->iobase,DAS08_SIZE);
589
590         return 0;
591 }
592
593 COMEDI_INITCLEANUP(driver_das08);
594