Initial revision
[comedi.git] / comedi / drivers / das08.c
1 /*
2
3   DAS-08 adapter
4
5   hack by David Schleef <ds@stm.lbl.gov>
6
7   mostly borrowed from Warren J. Jasper <wjasper@tx.ncsu.edu>
8
9   should be compatible with boards from Keithley Metrabyte and
10   Computer Boards.
11
12  * Copyright (C) 1998  Warren Jasper, David Schleef
13  * All rights reserved.
14  *
15  * This software may be freely copied, modified, and redistributed
16  * provided that this copyright notice is preserved on all copies.
17  *
18  * You may not distribute this software, in whole or in part, as part of
19  * any commercial product without the express consent of the authors.
20  *
21  * There is no warranty or other guarantee of fitness of this software
22  * for any purpose.  It is provided solely "as is".
23
24
25 */
26
27
28 #include <linux/kernel.h>
29 #include <linux/module.h>
30 #include <comedi_module.h>
31 #include <linux/errno.h>
32 #include <linux/ioport.h>
33 #include <asm/io.h>
34 #include <linux/malloc.h>
35 #include <linux/delay.h>
36 #include <8255.h>
37
38 /* general debugging messages */
39 #define DEBUG
40
41 /* specific debugging messages */
42 #undef DAVE1
43 #undef DAVE2
44 #undef DAVE3
45
46 /*
47         on the non-AO board, the DA registers don't exist
48         and the 8255 registers move up by 4
49         it also doesn't use the GAIN_REG
50 */
51
52
53 #define DAS08_SIZE 0x10
54
55 #define LSB_AND_CHNLS   0       /* A/D Data & Channel Register      */
56 #define MSB_DATA_BYTE   1
57 #define STATUS_REG      2       /* Channel Mux Scan Limits Register */
58 #define GAIN_REG        3       /* Programmable Gain Register       */
59 #define COUNTER_0_DATA  4       /* Counter 0 Register               */
60 #define COUNTER_1_DATA  5       /* Counter 1 Register               */
61 #define COUNTER_2_DATA  6       /* Counter 2 Register               */
62 #define COUNTER_CONTROL 7       /* Conter Control  Register         */
63 #define DA_CHAN0_LSB    8       /* DAC 0 Low Byte                   */
64 #define DA_CHAN0_MSB    9       /* DAC 0 High Byte                  */
65 #define DA_CHAN1_LSB    10      /* DAC 1 Low Byte                   */
66 #define DA_CHAN1_MSB    11      /* DAC 1 High Byte                  */
67 #define DIO_PORTA       12      /* Port A 8 bit I/O of 8255         */
68 #define DIO_PORTB       13      /* Port B 8 bit I/O of 8255         */
69 #define DIO_PORTC       14      /* Port C 4+4 bit of 8255           */
70 #define DIO_CNTRL_REG   15      /* Mode and Direction Control Reg.  */
71
72 /*
73
74  info provided by Carsten Zerbst about das08:
75  agrees with pdf file from www.computerboards.com
76
77 port, read, write
78 0       A/D Bits 3-0(LSB)               Start 8 bit A/D conversion
79 1       A/D Bits 11-4(MSB)              Start 12 bit A/D conversion
80 2       EOC,IP1-IP3,IRQ,MUX Address     OP1-OP4, INTE & MUX address
81 3       not used                        not used
82 4       Read counter 0                  Load Counter 0
83 5       Read counter 1                  Load Counter 1
84 6       Read counter 2                  Load Counter 2
85 7       not used                        Counter control
86 8       Port A input 8255               Port A Output
87 9       Port B input                    Port A output
88 10      Port C Input                    Port A Output
89 11      None. No read Back on 8255      Configure 8255
90
91
92 pgh model: gains .5,1,5,10,50,100,500,1000, unipolar and bipolar
93 pgl model: gains .5,1.2,4,8, unipolar and bipolar
94
95 pgh bipolar ranges: +/- 10, +/-5, etc.
96 pgh unipolar ranges: 0 to { x,10,x,1,x,0.1,x,0.01 }
97   (what does x mean?)
98
99 pgl bipolar ranges: +/- { 10,5,2.5,1.25,0.625 }
100 pgl unipolar ranges: 0 to { N/A, 10, 5, 2.5, 1.25 }
101
102
103 das08jr info:
104
105 4       DAC0 lsb
106 5       DAC0 msb
107 6       DAC1 lsb
108 7       DAC1 msb
109
110
111
112 */
113
114
115
116 /*************************************************************************
117 * STATUS_REG         base_reg+2             Status Register              *
118 **************************************************************************/
119
120 /* Read */
121 #define MUX0  0x01      /* Current multiplexor channel */
122 #define MUX1  0x02      /* Current multiplexor channel */
123 #define MUX2  0x04      /* Current multiplexor channel */
124 #define IRQ   0x08      /* 1 = positive edge detected  */
125 #define IP1   0x10      /* digial input line IP1       */
126 #define IP2   0x20      /* digial input line IP2       */
127 #define IP3   0x40      /* digial input line IP3       */
128 #define EOC   0x80      /* 1=A/D busy, 0=not busy      */
129
130 /* Write */
131 #define INTE  0x08     /* 1=enable interrupts, 0=disable */
132 #define OP1   0x10     /* digital output line OP1        */
133 #define OP2   0x20     /* digital output line OP2        */
134 #define OP3   0x40     /* digital output line OP3        */
135 #define OP4   0x80     /* digital output line OP4        */
136
137 /*************************************************************************
138 * Constants for dealing with the 8254 counters                           *
139 **************************************************************************/
140
141 #define MODE0 0x0
142 #define MODE1 0x2
143 #define MODE2 0x4
144 #define MODE3 0x6
145 #define MODE4 0x8
146 #define MODE5 0xa
147
148 #define C0 0x00
149 #define C1 0x40
150 #define C2 0x80
151
152 #define _LATCH    0x00          /* LATCH gets caught up with timex.h */
153 #define LSBONLY  0x10
154 #define MSBONLY  0x20
155 #define LSBFIRST 0x30
156
157 #define S0       0x00
158 #define S1       0x02
159
160 static int das08_attach(comedi_device *dev,comedi_devconfig *it);
161 static int das08_detach(comedi_device *dev);
162 static int das08_recognize(char *name);
163 comedi_driver driver_das08={
164         driver_name:    "das08",
165         module:         &__this_module,
166         attach:         das08_attach,
167         detach:         das08_detach,
168         recognize:      das08_recognize,
169 };
170
171
172 typedef struct{
173         int boardtype;
174         int dio;
175         int aip[16];
176 }das08_private;
177 #define devpriv ((das08_private *)dev->private)
178
179 struct boardtype_struct{
180         char name[20];
181         int ai_chans;
182         int ao_chans;
183 };
184 static struct boardtype_struct boardtypes[]={
185   {"das08",8,0},
186   {"das08-aol",8,0},
187   {"das08-pgh",8,0},
188   {"das08-pgl",8,0}
189 };
190 #define this_board (boardtypes[devpriv->boardtype])
191 #define n_boardtypes (sizeof(boardtypes)/sizeof(boardtypes[0]))
192
193
194 static int das08_ai(comedi_device *dev,comedi_subdevice *s,comedi_trig *it)
195 {
196         int i,lsb,msb;
197         int chan;
198
199         chan=CR_CHAN(it->chanlist[0]);
200         
201 #ifndef DAVE1
202         /* possibly clears A/D queue */
203         inb(dev->iobase+LSB_AND_CHNLS);
204         inb(dev->iobase+MSB_DATA_BYTE);
205 #endif
206
207         /* set multiplexer */
208         outb_p(chan | devpriv->dio,dev->iobase+STATUS_REG);
209
210         /* XXX do we have to wait for MUX to settle?  how long? */
211         
212         /* how to set gain? */
213
214         /* trigger conversion */
215 #ifndef DAVE3
216         outb_p(0,dev->iobase+LSB_AND_CHNLS);
217 #else
218         outb_p(0,dev->iobase+MSB_DATA_BYTE);
219 #endif
220 #ifdef DAVE2
221         /* wait for conversion to take place */
222         udelay(25);
223         
224         msb=inb(dev->iobase+MSB_DATA_BYTE);
225         lsb=inb(dev->iobase+LSB_AND_CHNLS);
226         it->data[0]=(lsb >> 4) | (msb << 4);
227         return 1;
228 #else
229         for(i=0;i<200;i++){
230                 if(!(inb_p(dev->iobase+STATUS_REG) & EOC)){
231                         msb=inb(dev->iobase+MSB_DATA_BYTE);
232                         lsb=inb(dev->iobase+LSB_AND_CHNLS);
233                         it->data[0]=(lsb >> 4) | (msb << 4);
234                         return 1;
235                 }
236                 udelay(5);
237         }
238 #ifdef DEBUG
239         rt_printk("das08: ai timeout\n");
240 #endif
241         return -ETIME;
242 #endif
243 }
244
245
246 static int das08_ao(comedi_device *dev,comedi_subdevice *s,comedi_trig *it)
247 {
248         int lsb,msb;
249
250         lsb=it->data[0]&0xff;
251         msb=(it->data[0]>>8)&0xf;
252         if(CR_CHAN(it->chanlist[0])==0){
253                 outb(lsb,dev->iobase+DA_CHAN0_LSB);
254                 outb(msb,dev->iobase+DA_CHAN0_MSB);
255         }else{
256                 outb(lsb,dev->iobase+DA_CHAN1_LSB);
257                 outb(msb,dev->iobase+DA_CHAN1_MSB);
258         }
259         return 1;
260 }
261
262 static int das08_do(comedi_device *dev,comedi_subdevice *s,comedi_trig *it)
263 {
264         do_pack(&s->state,it);
265         
266         outb_p(s->state<<4,dev->iobase+STATUS_REG);
267
268         return it->n_chan;
269 }
270
271 static int das08_di(comedi_device *dev,comedi_subdevice *s,comedi_trig *it)
272 {
273         unsigned int bits;
274         
275         bits=(inb(dev->iobase+STATUS_REG)>>4)&0x7;
276         
277         return di_unpack(bits,it);
278 }
279
280 static int das08_recognize(char *name)
281 {
282         int i;
283
284         for(i=0;i<n_boardtypes;i++){
285                 if(!strcmp(boardtypes[i].name,name))return i;
286         }
287         return -1;
288 }
289
290 static int das08_attach(comedi_device *dev,comedi_devconfig *it)
291 {
292         int i;
293         comedi_subdevice *s;
294         int ret;
295         
296         dev->iobase=it->options[0];
297         printk("comedi%d: das08: 0x%04x",dev->minor,dev->iobase);
298         if(check_region(dev->iobase,DAS08_SIZE)<0){
299                 printk(" I/O port conflict\n");
300                 return -EIO;
301         }
302         dev->board_name="das08";
303         dev->iosize=DAS08_SIZE;
304         dev->irq=0;
305         
306 #ifdef DEBUG
307         printk("\nboard fingerprint:\n");
308         for(i=0;i<DAS08_SIZE;i++){
309                 printk("%02x ",inb_p(dev->iobase+i));
310         }
311 #endif
312         dev->n_subdevices=5;
313         if((ret=alloc_subdevices(dev))<0)
314                 return ret;
315         if((ret=alloc_private(dev,sizeof(das08_private)))<0)
316                 return ret;
317         
318         request_region(dev->iobase,DAS08_SIZE,"das08");
319         
320         devpriv->boardtype=0;
321         
322         s=dev->subdevices+0;
323         /* ai */
324         s->type=COMEDI_SUBD_AI;
325         s->subdev_flags=SDF_READABLE;
326         s->n_chan=8;
327         s->maxdata=0xfff;
328         s->range_type=RANGE_unknown;    /* XXX */
329         s->trig[0]=das08_ai;
330
331         s=dev->subdevices+1;
332         /* ao */
333         if(this_board.ao_chans>0){
334                 s->type=COMEDI_SUBD_AO;
335                 s->subdev_flags=SDF_WRITEABLE;
336                 s->n_chan=2;
337                 s->maxdata=0xfff;
338                 s->range_type=RANGE_unknown;    /* XXX */
339         }else{
340                 s->type=COMEDI_SUBD_UNUSED;
341         }
342         s->trig[0]=das08_ao;
343
344         s=dev->subdevices+2;
345         subdev_8255_init(dev,s,NULL,(void *)(dev->iobase+DIO_PORTA));
346
347         s=dev->subdevices+3;
348         /* ai */
349         s->type=COMEDI_SUBD_DI;
350         s->subdev_flags=SDF_READABLE;
351         s->n_chan=3;
352         s->maxdata=1;
353         s->range_type=RANGE_digital;
354         s->trig[0]=das08_di;
355
356         s=dev->subdevices+4;
357         /* ai */
358         s->type=COMEDI_SUBD_DO;
359         s->subdev_flags=SDF_WRITEABLE;
360         s->n_chan=4;
361         s->maxdata=1;
362         s->range_type=RANGE_digital;
363         s->trig[0]=das08_do;
364
365         devpriv->dio=0;
366         
367
368         if(this_board.ao_chans>0){
369                 /* zero AO */
370                 outb(0,dev->iobase+DA_CHAN0_LSB);
371                 outb(0,dev->iobase+DA_CHAN0_MSB);
372                 outb(0,dev->iobase+DA_CHAN1_LSB);
373                 outb(0,dev->iobase+DA_CHAN1_MSB);
374         }
375         
376         outb_p(0,dev->iobase+STATUS_REG);
377         
378 #if 0
379         outb_p(0,dev->iobase+DIO_PORTA);
380         outb_p(0,dev->iobase+DIO_PORTB);
381         outb_p(0,dev->iobase+DIO_PORTC);
382 #endif
383         
384         printk("\n");
385
386         return 0;
387 }
388
389 static int das08_detach(comedi_device *dev)
390 {
391         printk("comedi%d: das08: remove\n",dev->minor);
392         
393         release_region(dev->iobase,dev->iosize);
394         
395         return 0;
396 }
397
398 #ifdef MODULE
399 int init_module(void)
400 {
401         comedi_driver_register(&driver_das08);
402         
403         return 0;
404 }
405
406 void cleanup_module(void)
407 {
408         comedi_driver_unregister(&driver_das08);
409 }
410 #endif