fixing end of scan events in some drivers
[comedi.git] / comedi / drivers / rti800.c
1 /*
2    module/rti800.c
3    hardware driver for Analog Devices RTI-800/815 board
4
5    COMEDI - Linux Control and Measurement Device Interface
6    Copyright (C) 1998 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: rti800.o
25 Description: Analog Devices RTI-800/815
26 Author: ds
27 Status: unknown
28 Devices: [Analog Devices] RTI-800 (rti800), RTI-815 (rti815)
29
30 Configuration options:
31   [0] - I/O port base address
32   [1] - IRQ
33   [2] - A/D reference
34           0 = differential
35           1 = pseudodifferential (common)
36           2 = single-ended
37   [3] - A/D range
38           0 = [-10,10]
39           1 = [-5,5]
40           2 = [0,10]
41   [4] - A/D encoding
42           0 = two's complement
43           1 = straight binary
44   [5] - DAC 0 range
45           0 = [-10,10]
46           1 = [0,10]
47   [5] - DAC 0 encoding
48           0 = two's complement
49           1 = straight binary
50   [6] - DAC 1 range (same as DAC 0)
51   [7] - DAC 1 encoding (same as DAC 0)
52 */
53
54 #include <linux/kernel.h>
55 #include <linux/module.h>
56 #include <linux/sched.h>
57 #include <linux/mm.h>
58 #include <linux/slab.h>
59 #include <linux/errno.h>
60 #include <linux/ioport.h>
61 #include <linux/delay.h>
62 #include <linux/interrupt.h>
63 #include <linux/timex.h>
64 #include <linux/timer.h>
65 #include <asm/io.h>
66 #include <linux/comedidev.h>
67
68
69 #define RTI800_SIZE 16
70
71 #define RTI800_CSR 0
72 #define RTI800_MUXGAIN 1
73 #define RTI800_CONVERT 2
74 #define RTI800_ADCLO 3
75 #define RTI800_ADCHI 4
76 #define RTI800_DAC0LO 5
77 #define RTI800_DAC0HI 6
78 #define RTI800_DAC1LO 7
79 #define RTI800_DAC1HI 8
80 #define RTI800_CLRFLAGS 9
81 #define RTI800_DI 10
82 #define RTI800_DO 11
83 #define RTI800_9513A_DATA 12
84 #define RTI800_9513A_CNTRL 13
85 #define RTI800_9513A_STATUS 13
86
87
88 /*
89  * flags for CSR register
90  */
91
92 #define RTI800_BUSY             0x80
93 #define RTI800_DONE             0x40
94 #define RTI800_OVERRUN          0x20
95 #define RTI800_TCR              0x10
96 #define RTI800_DMA_ENAB         0x08
97 #define RTI800_INTR_TC          0x04
98 #define RTI800_INTR_EC          0x02
99 #define RTI800_INTR_OVRN        0x01
100
101 #define Am9513_8BITBUS
102
103 #define Am9513_output_control(a)        outb(a,dev->iobase+RTI800_9513A_CNTRL)
104 #define Am9513_output_data(a)           outb(a,dev->iobase+RTI800_9513A_DATA)
105 #define Am9513_input_data()             inb(dev->iobase+RTI800_9513A_DATA)
106 #define Am9513_input_status()           inb(dev->iobase+RTI800_9513A_STATUS)
107
108 #include "am9513.h"
109
110 static comedi_lrange range_rti800_ai_10_bipolar = { 4, {
111         BIP_RANGE( 10 ),
112         BIP_RANGE( 1 ),
113         BIP_RANGE( 0.1 ),
114         BIP_RANGE( 0.02 )
115 }};
116 static comedi_lrange range_rti800_ai_5_bipolar = { 4, {
117         BIP_RANGE( 5 ),
118         BIP_RANGE( 0.5 ),
119         BIP_RANGE( 0.05 ),
120         BIP_RANGE( 0.01 )
121 }};
122 static comedi_lrange range_rti800_ai_unipolar = { 4, {
123         UNI_RANGE( 10 ),
124         UNI_RANGE( 1 ),
125         UNI_RANGE( 0.1 ),
126         UNI_RANGE( 0.02 )
127 }};
128
129 typedef struct{
130         char *name;
131         int has_ao;
132 }boardtype;
133 static boardtype boardtypes[]={
134         { "rti800", 0 },
135         { "rti815", 1 },
136 };
137 #define this_board ((boardtype *)dev->board_ptr)
138
139 static int rti800_attach(comedi_device *dev,comedi_devconfig *it);
140 static int rti800_detach(comedi_device *dev);
141 static comedi_driver driver_rti800={
142         driver_name:    "rti800",
143         module:         THIS_MODULE,
144         attach:         rti800_attach,
145         detach:         rti800_detach,
146         num_names:      sizeof(boardtypes)/sizeof(boardtype),
147         board_name:     boardtypes,
148         offset:         sizeof(boardtype),
149 };
150 COMEDI_INITCLEANUP(driver_rti800);
151
152 static void rti800_interrupt(int irq, void *dev, struct pt_regs *regs);
153
154 typedef struct {
155         enum {
156                 adc_diff, adc_pseudodiff, adc_singleended
157         } adc_mux;
158         enum {
159                 adc_bipolar10, adc_bipolar5, adc_unipolar10
160         } adc_range;
161         enum {
162                 adc_2comp, adc_straight
163         } adc_coding;
164         enum {
165                 dac_bipolar10, dac_unipolar10
166         } dac0_range, dac1_range;
167         enum {
168                 dac_2comp, dac_straight
169         } dac0_coding, dac1_coding;
170         comedi_lrange * ao_range_type_list[2];
171         lsampl_t ao_readback[2];
172 } rti800_private;
173
174 #define devpriv ((rti800_private *)dev->private)
175
176 #define RTI800_TIMEOUT 10
177
178 static void rti800_interrupt(int irq, void *dev, struct pt_regs *regs)
179 {
180
181
182 }
183
184 // settling delay times in usec for different gains
185 //static int gaindelay[]={10,20,40,80};
186
187 static int rti800_ai_insn_read(comedi_device *dev,comedi_subdevice *s,
188         comedi_insn *insn,lsampl_t *data)
189 {
190         int i,t;
191         int status;
192         int chan = CR_CHAN(insn->chanspec);
193         int gain = CR_RANGE(insn->chanspec);
194
195         inb(dev->iobase + RTI800_ADCHI);
196         outb(0,dev->iobase+RTI800_CLRFLAGS);
197
198         outb(chan | (gain << 5), dev->iobase + RTI800_MUXGAIN);
199
200         for(i=0;i<insn->n;i++){
201                 outb(0, dev->iobase + RTI800_CONVERT);
202                 for (t = RTI800_TIMEOUT; t; t--) {
203                         status=inb(dev->iobase+RTI800_CSR);
204                         if(status & RTI800_OVERRUN){
205                                 rt_printk("rti800: a/d overrun\n");
206                                 outb(0,dev->iobase+RTI800_CLRFLAGS);
207                                 return -EIO;
208                         }
209                         if (status & RTI800_DONE)break;
210                         //udelay(8);
211                 }
212                 if(t == 0){
213                         rt_printk("rti800: timeout\n");
214                         return -ETIME;
215                 }
216                 data[i] = inb(dev->iobase + RTI800_ADCLO);
217                 data[i] |= (0xf & inb(dev->iobase + RTI800_ADCHI))<<8;
218
219                 if (devpriv->adc_coding == adc_2comp) {
220                         data[i] ^= 0x800;
221                 }
222         }
223
224         return i;
225 }
226
227 static int rti800_ao_insn_read(comedi_device *dev,comedi_subdevice *s,
228         comedi_insn *insn,lsampl_t *data)
229 {
230         int i;
231         int chan=CR_CHAN(insn->chanspec);
232
233         for(i=0;i<insn->n;i++)
234                 data[i] = devpriv->ao_readback[chan];
235
236         return i;
237 }
238
239 static int rti800_ao_insn_write(comedi_device *dev,comedi_subdevice *s,
240         comedi_insn *insn,lsampl_t *data)
241 {
242         int chan=CR_CHAN(insn->chanspec);
243         int d;
244         int i;
245
246         for(i=0;i<insn->n;i++){
247                 devpriv->ao_readback[chan] = d = data[i];
248                 if (devpriv->dac0_coding == dac_2comp) {
249                         d ^= 0x800;
250                 }
251                 outb(d & 0xff, dev->iobase + (chan?RTI800_DAC1LO:RTI800_DAC0LO));
252                 outb(d >> 8, dev->iobase + (chan?RTI800_DAC1HI:RTI800_DAC0HI));
253         }
254         return i;
255 }
256
257 static int rti800_di_insn_bits(comedi_device *dev,comedi_subdevice *s,
258         comedi_insn *insn,lsampl_t *data)
259 {
260         if(insn->n!=2)return -EINVAL;
261         data[1] = inb(dev->iobase + RTI800_DI);
262         return 2;
263 }
264
265 static int rti800_do_insn_bits(comedi_device *dev,comedi_subdevice *s,
266         comedi_insn *insn,lsampl_t *data)
267 {
268         if(insn->n!=2)return -EINVAL;
269
270         if(data[0]){
271                 s->state &= ~data[0];
272                 s->state |= data[0]&data[1];
273                 /* Outputs are inverted... */
274                 outb(s->state ^ 0xff, dev->iobase + RTI800_DO);
275         }
276
277         data[1] = s->state;
278
279         return 2;
280 }
281
282
283 /*
284    options[0] - I/O port
285    options[1] - irq
286    options[2] - a/d mux
287         0=differential, 1=pseudodiff, 2=single
288    options[3] - a/d range
289         0=bipolar10, 1=bipolar5, 2=unipolar10
290    options[4] - a/d coding
291         0=2's comp, 1=straight binary
292    options[5] - dac0 range
293         0=bipolar10, 1=unipolar10
294    options[6] - dac0 coding
295         0=2's comp, 1=straight binary
296    options[7] - dac1 range
297    options[8] - dac1 coding
298  */
299
300 static int rti800_attach(comedi_device * dev, comedi_devconfig * it)
301 {
302         int irq;
303         int iobase;
304         int ret;
305         comedi_subdevice *s;
306
307         iobase = it->options[0];
308         printk("comedi%d: rti800: 0x%04x ", dev->minor, iobase);
309         if (check_region(iobase, RTI800_SIZE) < 0) {
310                 printk("I/O port conflict\n");
311                 return -EIO;
312         }
313         request_region(iobase, RTI800_SIZE, "rti800");
314         dev->iobase = iobase;
315
316 #ifdef DEBUG
317         printk("fingerprint=%x,%x,%x,%x,%x ",
318                 inb(dev->iobase + 0),
319                 inb(dev->iobase + 1),
320                 inb(dev->iobase + 2),
321                 inb(dev->iobase + 3),
322                 inb(dev->iobase + 4));
323 #endif
324
325         outb(0,dev->iobase+RTI800_CSR);
326         inb(dev->iobase+RTI800_ADCHI);
327         outb(0,dev->iobase+RTI800_CLRFLAGS);
328
329         irq=it->options[1];
330         if(irq>0){
331                 printk("( irq = %d )\n",irq);
332                 if((ret=comedi_request_irq(irq,rti800_interrupt, 0, "rti800", dev))<0)
333                         return ret;
334                 dev->irq=irq;
335         }else if(irq == 0){
336                 printk("( no irq )");
337         }
338
339         dev->board_name = this_board->name;
340
341         dev->n_subdevices=4;
342         if((ret=alloc_subdevices(dev))<0)
343                 return ret;
344         if((ret=alloc_private(dev,sizeof(rti800_private)))<0)
345                 return ret;
346         
347         devpriv->adc_mux = it->options[2];
348         devpriv->adc_range = it->options[3];
349         devpriv->adc_coding = it->options[4];
350         devpriv->dac0_range = it->options[5];
351         devpriv->dac0_coding = it->options[6];
352         devpriv->dac1_range = it->options[7];
353         devpriv->dac1_coding = it->options[8];
354
355         s=dev->subdevices+0;
356         /* ai subdevice */
357         s->type=COMEDI_SUBD_AI;
358         s->subdev_flags=SDF_READABLE;
359         s->n_chan=(devpriv->adc_mux? 16 : 8);
360         s->insn_read=rti800_ai_insn_read;
361         s->maxdata=0xfff;
362         switch (devpriv->adc_range) {
363         case adc_bipolar10:
364                 s->range_table = &range_rti800_ai_10_bipolar;
365                 break;
366         case adc_bipolar5:
367                 s->range_table = &range_rti800_ai_5_bipolar;
368                 break;
369         case adc_unipolar10:
370                 s->range_table = &range_rti800_ai_unipolar;
371                 break;
372         }
373
374         s++;
375         if (this_board->has_ao){
376                 /* ao subdevice (only on rti815) */
377                 s->type=COMEDI_SUBD_AO;
378                 s->subdev_flags=SDF_WRITABLE;
379                 s->n_chan=2;
380                 s->insn_read=rti800_ao_insn_read;
381                 s->insn_write=rti800_ao_insn_write;
382                 s->maxdata=0xfff;
383                 s->range_table_list=devpriv->ao_range_type_list;
384                 switch (devpriv->dac0_range) {
385                 case dac_bipolar10:
386                         devpriv->ao_range_type_list[0] = &range_bipolar10;
387                         break;
388                 case dac_unipolar10:
389                         devpriv->ao_range_type_list[0] = &range_unipolar10;
390                         break;
391                 }
392                 switch (devpriv->dac1_range) {
393                 case dac_bipolar10:
394                         devpriv->ao_range_type_list[1] = &range_bipolar10;
395                         break;
396                 case dac_unipolar10:
397                         devpriv->ao_range_type_list[1] = &range_unipolar10;
398                         break;
399                 }
400         }else{
401                 s->type=COMEDI_SUBD_UNUSED;
402         }
403
404         s++;
405         /* di */
406         s->type=COMEDI_SUBD_DI;
407         s->subdev_flags=SDF_READABLE;
408         s->n_chan=8;
409         s->insn_bits=rti800_di_insn_bits;
410         s->maxdata=1;
411         s->range_table=&range_digital;
412
413         s++;
414         /* do */
415         s->type=COMEDI_SUBD_DO;
416         s->subdev_flags=SDF_WRITABLE;
417         s->n_chan=8;
418         s->insn_bits=rti800_do_insn_bits;
419         s->maxdata=1;
420         s->range_table=&range_digital;
421
422
423 /* don't yet know how to deal with counter/timers */
424 #if 0
425         s++;
426         /* do */
427         s->type=COMEDI_SUBD_TIMER;
428 #endif
429
430         printk("\n");
431
432         return 0;
433 }
434
435
436 static int rti800_detach(comedi_device * dev)
437 {
438         printk("comedi%d: rti800: remove\n", dev->minor);
439
440         if(dev->iobase)
441                 release_region(dev->iobase, RTI800_SIZE);
442
443         if(dev->irq)
444                 comedi_free_irq(dev->irq,dev);
445
446         return 0;
447 }
448