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.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33 Description: Keithley Metrabyte DAS6402 (& compatibles)
34 Author: Oystein Svendsen <svendsen@pvv.org>
36 Devices: [Keithley Metrabyte] DAS6402 (das6402)
38 This driver has suffered bitrot.
41 #include <linux/interrupt.h>
42 #include "../comedidev.h"
44 #include <linux/ioport.h>
46 #define DAS6402_SIZE 16
48 #define N_WORDS (3000*64)
54 #define BYTE unsigned char
55 #define WORD unsigned short
57 /*----- register 8 ----*/
62 #define ARMED 0x20 /* enable conting of post sample conv */
64 #define MHZ 0x80 /* 10 MHz clock */
65 /*---------------------*/
67 /*----- register 9 ----*/
68 #define IRQ (0x04 << 4) /* these two are */
69 #define IRQV 10 /* dependent on each other */
71 #define CONVSRC 0x03 /* trig src is Intarnal pacer */
72 #define BURSTEN 0x04 /* enable burst */
73 #define XINTE 0x08 /* use external int. trig */
74 #define INTE 0x80 /* enable analog interrupts */
75 /*---------------------*/
77 /*----- register 10 ---*/
78 #define TGEN 0x01 /* Use pin DI1 for externl trigging? */
79 #define TGSEL 0x02 /* Use edge triggering */
80 #define TGPOL 0x04 /* active edge is falling */
81 #define PRETRIG 0x08 /* pretrig */
82 /*---------------------*/
84 /*----- register 11 ---*/
86 #define FIFOHFULL 0x08
88 #define FIFONEPTY 0x04
92 /*---------------------*/
102 static int das6402_attach(struct comedi_device
*dev
,
103 struct comedi_devconfig
*it
);
104 static int das6402_detach(struct comedi_device
*dev
);
105 static struct comedi_driver driver_das6402
= {
106 .driver_name
= "das6402",
107 .module
= THIS_MODULE
,
108 .attach
= das6402_attach
,
109 .detach
= das6402_detach
,
112 static int __init
driver_das6402_init_module(void)
114 return comedi_driver_register(&driver_das6402
);
117 static void __exit
driver_das6402_cleanup_module(void)
119 comedi_driver_unregister(&driver_das6402
);
122 module_init(driver_das6402_init_module
);
123 module_exit(driver_das6402_cleanup_module
);
125 struct das6402_private
{
126 int ai_bytes_to_read
;
128 int das6402_ignoreirq
;
130 #define devpriv ((struct das6402_private *)dev->private)
132 static void das6402_ai_fifo_dregs(struct comedi_device
*dev
,
133 struct comedi_subdevice
*s
);
135 static void das6402_setcounter(struct comedi_device
*dev
)
138 unsigned short ctrlwrd
;
140 /* set up counter0 first, mode 0 */
142 outb_p(p
, dev
->iobase
+ 15);
144 p
= (BYTE
) (0xff & ctrlwrd
);
145 outb_p(p
, dev
->iobase
+ 12);
146 p
= (BYTE
) (0xff & (ctrlwrd
>> 8));
147 outb_p(p
, dev
->iobase
+ 12);
149 /* set up counter1, mode 2 */
151 outb_p(p
, dev
->iobase
+ 15);
153 p
= (BYTE
) (0xff & ctrlwrd
);
154 outb_p(p
, dev
->iobase
+ 13);
155 p
= (BYTE
) (0xff & (ctrlwrd
>> 8));
156 outb_p(p
, dev
->iobase
+ 13);
158 /* set up counter1, mode 2 */
160 outb_p(p
, dev
->iobase
+ 15);
162 p
= (BYTE
) (0xff & ctrlwrd
);
163 outb_p(p
, dev
->iobase
+ 14);
164 p
= (BYTE
) (0xff & (ctrlwrd
>> 8));
165 outb_p(p
, dev
->iobase
+ 14);
168 static irqreturn_t
intr_handler(int irq
, void *d
)
170 struct comedi_device
*dev
= d
;
171 struct comedi_subdevice
*s
= dev
->subdevices
;
173 if (!dev
->attached
|| devpriv
->das6402_ignoreirq
) {
174 printk("das6402: BUG: spurious interrupt\n");
178 printk("das6402: interrupt! das6402_irqcount=%i\n",
179 devpriv
->das6402_irqcount
);
180 printk("das6402: iobase+2=%i\n", inw_p(dev
->iobase
+ 2));
183 das6402_ai_fifo_dregs(dev
, s
);
185 if (s
->async
->buf_write_count
>= devpriv
->ai_bytes_to_read
) {
186 outw_p(SCANL
, dev
->iobase
+ 2); /* clears the fifo */
187 outb(0x07, dev
->iobase
+ 8); /* clears all flip-flops */
189 printk("das6402: Got %i samples\n\n",
190 devpriv
->das6402_wordsread
- diff
);
192 s
->async
->events
|= COMEDI_CB_EOA
;
193 comedi_event(dev
, s
);
196 outb(0x01, dev
->iobase
+ 8); /* clear only the interrupt flip-flop */
198 comedi_event(dev
, s
);
203 static void das6402_ai_fifo_dregs(struct comedi_device
*dev
,
204 struct comedi_subdevice
*s
)
207 if (!(inb(dev
->iobase
+ 8) & 0x01))
209 comedi_buf_put(s
->async
, inw(dev
->iobase
));
213 static int das6402_ai_cancel(struct comedi_device
*dev
,
214 struct comedi_subdevice
*s
)
217 * This function should reset the board from whatever condition it
218 * is in (i.e., acquiring data), to a non-active state.
221 devpriv
->das6402_ignoreirq
= 1;
223 printk("das6402: Stopping acquisition\n");
225 devpriv
->das6402_ignoreirq
= 1;
226 outb_p(0x02, dev
->iobase
+ 10); /* disable external trigging */
227 outw_p(SCANL
, dev
->iobase
+ 2); /* resets the card fifo */
228 outb_p(0, dev
->iobase
+ 9); /* disables interrupts */
230 outw_p(SCANL
, dev
->iobase
+ 2);
236 static int das6402_ai_mode2(struct comedi_device
*dev
,
237 struct comedi_subdevice
*s
, comedi_trig
* it
)
239 devpriv
->das6402_ignoreirq
= 1;
242 printk("das6402: Starting acquisition\n");
244 outb_p(0x03, dev
->iobase
+ 10); /* enable external trigging */
245 outw_p(SCANL
, dev
->iobase
+ 2); /* resets the card fifo */
246 outb_p(IRQ
| CONVSRC
| BURSTEN
| INTE
, dev
->iobase
+ 9);
248 devpriv
->ai_bytes_to_read
= it
->n
* sizeof(short);
250 /* um... ignoreirq is a nasty race condition */
251 devpriv
->das6402_ignoreirq
= 0;
253 outw_p(SCANL
, dev
->iobase
+ 2);
259 static int board_init(struct comedi_device
*dev
)
263 devpriv
->das6402_ignoreirq
= 1;
265 outb(0x07, dev
->iobase
+ 8);
268 outb_p(MODE
, dev
->iobase
+ 11);
269 b
= BIP
| SEM
| MODE
| GAIN
| FIFOHFULL
;
270 outb_p(b
, dev
->iobase
+ 11);
273 outb_p(EXTEND
, dev
->iobase
+ 8);
275 outb_p(b
, dev
->iobase
+ 8);
276 b
= MHZ
| CLRINT
| CLRXTR
| CLRXIN
;
277 outb_p(b
, dev
->iobase
+ 8);
280 b
= IRQ
| CONVSRC
| BURSTEN
| INTE
;
281 outb_p(b
, dev
->iobase
+ 9);
285 outb_p(b
, dev
->iobase
+ 10);
288 outb_p(b
, dev
->iobase
+ 8);
290 das6402_setcounter(dev
);
292 outw_p(SCANL
, dev
->iobase
+ 2); /* reset card fifo */
294 devpriv
->das6402_ignoreirq
= 0;
299 static int das6402_detach(struct comedi_device
*dev
)
302 free_irq(dev
->irq
, dev
);
304 release_region(dev
->iobase
, DAS6402_SIZE
);
309 static int das6402_attach(struct comedi_device
*dev
,
310 struct comedi_devconfig
*it
)
313 unsigned long iobase
;
315 struct comedi_subdevice
*s
;
317 dev
->board_name
= "das6402";
319 iobase
= it
->options
[0];
323 printk("comedi%d: das6402: 0x%04lx", dev
->minor
, iobase
);
325 if (!request_region(iobase
, DAS6402_SIZE
, "das6402")) {
326 printk(" I/O port conflict\n");
329 dev
->iobase
= iobase
;
331 /* should do a probe here */
333 irq
= it
->options
[0];
334 printk(" ( irq = %u )", irq
);
335 ret
= request_irq(irq
, intr_handler
, 0, "das6402", dev
);
337 printk("irq conflict\n");
342 ret
= alloc_private(dev
, sizeof(struct das6402_private
));
346 ret
= alloc_subdevices(dev
, 1);
351 s
= dev
->subdevices
+ 0;
352 s
->type
= COMEDI_SUBD_AI
;
353 s
->subdev_flags
= SDF_READABLE
| SDF_GROUND
;
355 /* s->trig[2]=das6402_ai_mode2; */
356 s
->cancel
= das6402_ai_cancel
;
357 s
->maxdata
= (1 << 12) - 1;
358 s
->len_chanlist
= 16; /* ? */
359 s
->range_table
= &range_unknown
;
366 MODULE_AUTHOR("Comedi http://www.comedi.org");
367 MODULE_DESCRIPTION("Comedi low-level driver");
368 MODULE_LICENSE("GPL");