5 hack by David Schleef <ds@stm.lbl.gov>
7 mostly borrowed from Warren J. Jasper <wjasper@tx.ncsu.edu>
9 should be compatible with boards from Keithley Metrabyte and
12 * Copyright (C) 1998 Warren Jasper, David Schleef
13 * All rights reserved.
15 * This software may be freely copied, modified, and redistributed
16 * provided that this copyright notice is preserved on all copies.
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.
21 * There is no warranty or other guarantee of fitness of this software
22 * for any purpose. It is provided solely "as is".
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>
34 #include <linux/malloc.h>
35 #include <linux/delay.h>
38 /* general debugging messages */
41 /* specific debugging messages */
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
53 #define DAS08_SIZE 0x10
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. */
74 info provided by Carsten Zerbst about das08:
75 agrees with pdf file from www.computerboards.com
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
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
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
95 pgh bipolar ranges: +/- 10, +/-5, etc.
96 pgh unipolar ranges: 0 to { x,10,x,1,x,0.1,x,0.01 }
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 }
116 /*************************************************************************
117 * STATUS_REG base_reg+2 Status Register *
118 **************************************************************************/
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 */
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 */
137 /*************************************************************************
138 * Constants for dealing with the 8254 counters *
139 **************************************************************************/
152 #define _LATCH 0x00 /* LATCH gets caught up with timex.h */
155 #define LSBFIRST 0x30
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,
177 #define devpriv ((das08_private *)dev->private)
179 struct boardtype_struct{
184 static struct boardtype_struct boardtypes[]={
190 #define this_board (boardtypes[devpriv->boardtype])
191 #define n_boardtypes (sizeof(boardtypes)/sizeof(boardtypes[0]))
194 static int das08_ai(comedi_device *dev,comedi_subdevice *s,comedi_trig *it)
199 chan=CR_CHAN(it->chanlist[0]);
202 /* possibly clears A/D queue */
203 inb(dev->iobase+LSB_AND_CHNLS);
204 inb(dev->iobase+MSB_DATA_BYTE);
207 /* set multiplexer */
208 outb_p(chan | devpriv->dio,dev->iobase+STATUS_REG);
210 /* XXX do we have to wait for MUX to settle? how long? */
212 /* how to set gain? */
214 /* trigger conversion */
216 outb_p(0,dev->iobase+LSB_AND_CHNLS);
218 outb_p(0,dev->iobase+MSB_DATA_BYTE);
221 /* wait for conversion to take place */
224 msb=inb(dev->iobase+MSB_DATA_BYTE);
225 lsb=inb(dev->iobase+LSB_AND_CHNLS);
226 it->data[0]=(lsb >> 4) | (msb << 4);
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);
239 rt_printk("das08: ai timeout\n");
246 static int das08_ao(comedi_device *dev,comedi_subdevice *s,comedi_trig *it)
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);
256 outb(lsb,dev->iobase+DA_CHAN1_LSB);
257 outb(msb,dev->iobase+DA_CHAN1_MSB);
262 static int das08_do(comedi_device *dev,comedi_subdevice *s,comedi_trig *it)
264 do_pack(&s->state,it);
266 outb_p(s->state<<4,dev->iobase+STATUS_REG);
271 static int das08_di(comedi_device *dev,comedi_subdevice *s,comedi_trig *it)
275 bits=(inb(dev->iobase+STATUS_REG)>>4)&0x7;
277 return di_unpack(bits,it);
280 static int das08_recognize(char *name)
284 for(i=0;i<n_boardtypes;i++){
285 if(!strcmp(boardtypes[i].name,name))return i;
290 static int das08_attach(comedi_device *dev,comedi_devconfig *it)
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");
302 dev->board_name="das08";
303 dev->iosize=DAS08_SIZE;
307 printk("\nboard fingerprint:\n");
308 for(i=0;i<DAS08_SIZE;i++){
309 printk("%02x ",inb_p(dev->iobase+i));
313 if((ret=alloc_subdevices(dev))<0)
315 if((ret=alloc_private(dev,sizeof(das08_private)))<0)
318 request_region(dev->iobase,DAS08_SIZE,"das08");
320 devpriv->boardtype=0;
324 s->type=COMEDI_SUBD_AI;
325 s->subdev_flags=SDF_READABLE;
328 s->range_type=RANGE_unknown; /* XXX */
333 if(this_board.ao_chans>0){
334 s->type=COMEDI_SUBD_AO;
335 s->subdev_flags=SDF_WRITEABLE;
338 s->range_type=RANGE_unknown; /* XXX */
340 s->type=COMEDI_SUBD_UNUSED;
345 subdev_8255_init(dev,s,NULL,(void *)(dev->iobase+DIO_PORTA));
349 s->type=COMEDI_SUBD_DI;
350 s->subdev_flags=SDF_READABLE;
353 s->range_type=RANGE_digital;
358 s->type=COMEDI_SUBD_DO;
359 s->subdev_flags=SDF_WRITEABLE;
362 s->range_type=RANGE_digital;
368 if(this_board.ao_chans>0){
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);
376 outb_p(0,dev->iobase+STATUS_REG);
379 outb_p(0,dev->iobase+DIO_PORTA);
380 outb_p(0,dev->iobase+DIO_PORTB);
381 outb_p(0,dev->iobase+DIO_PORTC);
389 static int das08_detach(comedi_device *dev)
391 printk("comedi%d: das08: remove\n",dev->minor);
393 release_region(dev->iobase,dev->iosize);
399 int init_module(void)
401 comedi_driver_register(&driver_das08);
406 void cleanup_module(void)
408 comedi_driver_unregister(&driver_das08);