2 Some comments on the code..
4 - it shouldn't be necessary to use outb_p().
6 - ignoreirq creates a race condition. It needs to be fixed.
11 comedi/drivers/das6402.c
12 An experimental driver for Computerboards' DAS6402 I/O card
14 Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org>
16 This program is free software; you can redistribute it and/or modify
17 it under the terms of the GNU General Public License as published by
18 the Free Software Foundation; either version 2 of the License, or
19 (at your option) any later version.
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
28 Description: Keithley Metrabyte DAS6402 (& compatibles)
29 Author: Oystein Svendsen <svendsen@pvv.org>
31 Devices: [Keithley Metrabyte] DAS6402 (das6402)
33 This driver has suffered bitrot.
36 #include <linux/interrupt.h>
37 #include "../comedidev.h"
39 #include <linux/ioport.h>
41 #define DAS6402_SIZE 16
43 #define N_WORDS (3000*64)
49 #define BYTE unsigned char
50 #define WORD unsigned short
52 /*----- register 8 ----*/
57 #define ARMED 0x20 /* enable conting of post sample conv */
59 #define MHZ 0x80 /* 10 MHz clock */
60 /*---------------------*/
62 /*----- register 9 ----*/
63 #define IRQ (0x04 << 4) /* these two are */
64 #define IRQV 10 /* dependent on each other */
66 #define CONVSRC 0x03 /* trig src is Intarnal pacer */
67 #define BURSTEN 0x04 /* enable burst */
68 #define XINTE 0x08 /* use external int. trig */
69 #define INTE 0x80 /* enable analog interrupts */
70 /*---------------------*/
72 /*----- register 10 ---*/
73 #define TGEN 0x01 /* Use pin DI1 for externl trigging? */
74 #define TGSEL 0x02 /* Use edge triggering */
75 #define TGPOL 0x04 /* active edge is falling */
76 #define PRETRIG 0x08 /* pretrig */
77 /*---------------------*/
79 /*----- register 11 ---*/
81 #define FIFOHFULL 0x08
83 #define FIFONEPTY 0x04
87 /*---------------------*/
97 struct das6402_private
{
100 int das6402_ignoreirq
;
103 static void das6402_ai_fifo_dregs(struct comedi_device
*dev
,
104 struct comedi_subdevice
*s
)
107 if (!(inb(dev
->iobase
+ 8) & 0x01))
109 comedi_buf_put(s
->async
, inw(dev
->iobase
));
113 static void das6402_setcounter(struct comedi_device
*dev
)
116 unsigned short ctrlwrd
;
118 /* set up counter0 first, mode 0 */
120 outb_p(p
, dev
->iobase
+ 15);
122 p
= (BYTE
) (0xff & ctrlwrd
);
123 outb_p(p
, dev
->iobase
+ 12);
124 p
= (BYTE
) (0xff & (ctrlwrd
>> 8));
125 outb_p(p
, dev
->iobase
+ 12);
127 /* set up counter1, mode 2 */
129 outb_p(p
, dev
->iobase
+ 15);
131 p
= (BYTE
) (0xff & ctrlwrd
);
132 outb_p(p
, dev
->iobase
+ 13);
133 p
= (BYTE
) (0xff & (ctrlwrd
>> 8));
134 outb_p(p
, dev
->iobase
+ 13);
136 /* set up counter1, mode 2 */
138 outb_p(p
, dev
->iobase
+ 15);
140 p
= (BYTE
) (0xff & ctrlwrd
);
141 outb_p(p
, dev
->iobase
+ 14);
142 p
= (BYTE
) (0xff & (ctrlwrd
>> 8));
143 outb_p(p
, dev
->iobase
+ 14);
146 static irqreturn_t
intr_handler(int irq
, void *d
)
148 struct comedi_device
*dev
= d
;
149 struct das6402_private
*devpriv
= dev
->private;
150 struct comedi_subdevice
*s
= &dev
->subdevices
[0];
152 if (!dev
->attached
|| devpriv
->das6402_ignoreirq
) {
153 dev_warn(dev
->class_dev
, "BUG: spurious interrupt\n");
157 printk("das6402: interrupt! das6402_irqcount=%i\n",
158 devpriv
->das6402_irqcount
);
159 printk("das6402: iobase+2=%i\n", inw_p(dev
->iobase
+ 2));
162 das6402_ai_fifo_dregs(dev
, s
);
164 if (s
->async
->buf_write_count
>= devpriv
->ai_bytes_to_read
) {
165 outw_p(SCANL
, dev
->iobase
+ 2); /* clears the fifo */
166 outb(0x07, dev
->iobase
+ 8); /* clears all flip-flops */
168 printk("das6402: Got %i samples\n\n",
169 devpriv
->das6402_wordsread
- diff
);
171 s
->async
->events
|= COMEDI_CB_EOA
;
172 comedi_event(dev
, s
);
175 outb(0x01, dev
->iobase
+ 8); /* clear only the interrupt flip-flop */
177 comedi_event(dev
, s
);
182 static void das6402_ai_fifo_read(struct comedi_device
*dev
, short *data
, int n
)
186 for (i
= 0; i
< n
; i
++)
187 data
[i
] = inw(dev
->iobase
);
191 static int das6402_ai_cancel(struct comedi_device
*dev
,
192 struct comedi_subdevice
*s
)
194 struct das6402_private
*devpriv
= dev
->private;
197 * This function should reset the board from whatever condition it
198 * is in (i.e., acquiring data), to a non-active state.
201 devpriv
->das6402_ignoreirq
= 1;
202 dev_dbg(dev
->class_dev
, "Stopping acquisition\n");
203 devpriv
->das6402_ignoreirq
= 1;
204 outb_p(0x02, dev
->iobase
+ 10); /* disable external trigging */
205 outw_p(SCANL
, dev
->iobase
+ 2); /* resets the card fifo */
206 outb_p(0, dev
->iobase
+ 9); /* disables interrupts */
208 outw_p(SCANL
, dev
->iobase
+ 2);
214 static int das6402_ai_mode2(struct comedi_device
*dev
,
215 struct comedi_subdevice
*s
, comedi_trig
* it
)
217 struct das6402_private
*devpriv
= dev
->private;
219 devpriv
->das6402_ignoreirq
= 1;
220 dev_dbg(dev
->class_dev
, "Starting acquisition\n");
221 outb_p(0x03, dev
->iobase
+ 10); /* enable external trigging */
222 outw_p(SCANL
, dev
->iobase
+ 2); /* resets the card fifo */
223 outb_p(IRQ
| CONVSRC
| BURSTEN
| INTE
, dev
->iobase
+ 9);
225 devpriv
->ai_bytes_to_read
= it
->n
* sizeof(short);
227 /* um... ignoreirq is a nasty race condition */
228 devpriv
->das6402_ignoreirq
= 0;
230 outw_p(SCANL
, dev
->iobase
+ 2);
236 static int board_init(struct comedi_device
*dev
)
238 struct das6402_private
*devpriv
= dev
->private;
241 devpriv
->das6402_ignoreirq
= 1;
243 outb(0x07, dev
->iobase
+ 8);
246 outb_p(MODE
, dev
->iobase
+ 11);
247 b
= BIP
| SEM
| MODE
| GAIN
| FIFOHFULL
;
248 outb_p(b
, dev
->iobase
+ 11);
251 outb_p(EXTEND
, dev
->iobase
+ 8);
253 outb_p(b
, dev
->iobase
+ 8);
254 b
= MHZ
| CLRINT
| CLRXTR
| CLRXIN
;
255 outb_p(b
, dev
->iobase
+ 8);
258 b
= IRQ
| CONVSRC
| BURSTEN
| INTE
;
259 outb_p(b
, dev
->iobase
+ 9);
263 outb_p(b
, dev
->iobase
+ 10);
266 outb_p(b
, dev
->iobase
+ 8);
268 das6402_setcounter(dev
);
270 outw_p(SCANL
, dev
->iobase
+ 2); /* reset card fifo */
272 devpriv
->das6402_ignoreirq
= 0;
277 static int das6402_attach(struct comedi_device
*dev
,
278 struct comedi_devconfig
*it
)
280 struct das6402_private
*devpriv
;
283 struct comedi_subdevice
*s
;
285 ret
= comedi_request_region(dev
, it
->options
[0], DAS6402_SIZE
);
289 irq
= it
->options
[0];
290 dev_dbg(dev
->class_dev
, "( irq = %u )\n", irq
);
291 ret
= request_irq(irq
, intr_handler
, 0, "das6402", dev
);
297 devpriv
= kzalloc(sizeof(*devpriv
), GFP_KERNEL
);
300 dev
->private = devpriv
;
302 ret
= comedi_alloc_subdevices(dev
, 1);
307 s
= &dev
->subdevices
[0];
308 s
->type
= COMEDI_SUBD_AI
;
309 s
->subdev_flags
= SDF_READABLE
| SDF_GROUND
;
311 /* s->trig[2]=das6402_ai_mode2; */
312 s
->cancel
= das6402_ai_cancel
;
313 s
->maxdata
= (1 << 12) - 1;
314 s
->len_chanlist
= 16; /* ? */
315 s
->range_table
= &range_unknown
;
322 static struct comedi_driver das6402_driver
= {
323 .driver_name
= "das6402",
324 .module
= THIS_MODULE
,
325 .attach
= das6402_attach
,
326 .detach
= comedi_legacy_detach
,
328 module_comedi_driver(das6402_driver
)
330 MODULE_AUTHOR("Comedi http://www.comedi.org");
331 MODULE_DESCRIPTION("Comedi low-level driver");
332 MODULE_LICENSE("GPL");