• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/staging/comedi/drivers/
1/*
2   Some comments on the code..
3
4   - it shouldn't be necessary to use outb_p().
5
6   - ignoreirq creates a race condition.  It needs to be fixed.
7
8 */
9
10/*
11   comedi/drivers/das6402.c
12   An experimental driver for Computerboards' DAS6402 I/O card
13
14   Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org>
15
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.
20
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.
25
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.
29
30 */
31/*
32Driver: das6402
33Description: Keithley Metrabyte DAS6402 (& compatibles)
34Author: Oystein Svendsen <svendsen@pvv.org>
35Status: bitrotten
36Devices: [Keithley Metrabyte] DAS6402 (das6402)
37
38This driver has suffered bitrot.
39*/
40
41#include <linux/interrupt.h>
42#include "../comedidev.h"
43
44#include <linux/ioport.h>
45
46#define DAS6402_SIZE 16
47
48#define N_WORDS (3000*64)
49
50#define STOP    0
51#define START   1
52
53#define SCANL 0x3f00
54#define BYTE unsigned char
55#define WORD unsigned short
56
57/*----- register 8 ----*/
58#define CLRINT 0x01
59#define CLRXTR 0x02
60#define CLRXIN 0x04
61#define EXTEND 0x10
62#define ARMED 0x20		/* enable conting of post sample conv */
63#define POSTMODE 0x40
64#define MHZ 0x80		/* 10 MHz clock */
65/*---------------------*/
66
67/*----- register 9 ----*/
68#define IRQ (0x04 << 4)		/* these two are                         */
69#define IRQV 10			/*               dependent on each other */
70
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/*---------------------*/
76
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/*---------------------*/
83
84/*----- register 11 ---*/
85#define EOB 0x0c
86#define FIFOHFULL 0x08
87#define GAIN 0x01
88#define FIFONEPTY 0x04
89#define MODE 0x10
90#define SEM 0x20
91#define BIP 0x40
92/*---------------------*/
93
94#define M0 0x00
95#define M2 0x04
96
97#define	C0 0x00
98#define	C1 0x40
99#define	C2 0x80
100#define	RWLH 0x30
101
102static int das6402_attach(struct comedi_device *dev,
103			  struct comedi_devconfig *it);
104static int das6402_detach(struct comedi_device *dev);
105static struct comedi_driver driver_das6402 = {
106	.driver_name = "das6402",
107	.module = THIS_MODULE,
108	.attach = das6402_attach,
109	.detach = das6402_detach,
110};
111
112static int __init driver_das6402_init_module(void)
113{
114	return comedi_driver_register(&driver_das6402);
115}
116
117static void __exit driver_das6402_cleanup_module(void)
118{
119	comedi_driver_unregister(&driver_das6402);
120}
121
122module_init(driver_das6402_init_module);
123module_exit(driver_das6402_cleanup_module);
124
125struct das6402_private {
126	int ai_bytes_to_read;
127
128	int das6402_ignoreirq;
129};
130#define devpriv ((struct das6402_private *)dev->private)
131
132static void das6402_ai_fifo_dregs(struct comedi_device *dev,
133				  struct comedi_subdevice *s);
134
135static void das6402_setcounter(struct comedi_device *dev)
136{
137	BYTE p;
138	unsigned short ctrlwrd;
139
140	/* set up counter0 first, mode 0 */
141	p = M0 | C0 | RWLH;
142	outb_p(p, dev->iobase + 15);
143	ctrlwrd = 2000;
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);
148
149	/* set up counter1, mode 2 */
150	p = M2 | C1 | RWLH;
151	outb_p(p, dev->iobase + 15);
152	ctrlwrd = 10;
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);
157
158	/* set up counter1, mode 2 */
159	p = M2 | C2 | RWLH;
160	outb_p(p, dev->iobase + 15);
161	ctrlwrd = 1000;
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);
166}
167
168static irqreturn_t intr_handler(int irq, void *d)
169{
170	struct comedi_device *dev = d;
171	struct comedi_subdevice *s = dev->subdevices;
172
173	if (!dev->attached || devpriv->das6402_ignoreirq) {
174		printk("das6402: BUG: spurious interrupt\n");
175		return IRQ_HANDLED;
176	}
177#ifdef DEBUG
178	printk("das6402: interrupt! das6402_irqcount=%i\n",
179	       devpriv->das6402_irqcount);
180	printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2));
181#endif
182
183	das6402_ai_fifo_dregs(dev, s);
184
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 */
188#ifdef DEBUG
189		printk("das6402: Got %i samples\n\n",
190		       devpriv->das6402_wordsread - diff);
191#endif
192		s->async->events |= COMEDI_CB_EOA;
193		comedi_event(dev, s);
194	}
195
196	outb(0x01, dev->iobase + 8);	/* clear only the interrupt flip-flop */
197
198	comedi_event(dev, s);
199	return IRQ_HANDLED;
200}
201
202
203static void das6402_ai_fifo_dregs(struct comedi_device *dev,
204				  struct comedi_subdevice *s)
205{
206	while (1) {
207		if (!(inb(dev->iobase + 8) & 0x01))
208			return;
209		comedi_buf_put(s->async, inw(dev->iobase));
210	}
211}
212
213static int das6402_ai_cancel(struct comedi_device *dev,
214			     struct comedi_subdevice *s)
215{
216	/*
217	 *  This function should reset the board from whatever condition it
218	 *  is in (i.e., acquiring data), to a non-active state.
219	 */
220
221	devpriv->das6402_ignoreirq = 1;
222#ifdef DEBUG
223	printk("das6402: Stopping acquisition\n");
224#endif
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 */
229
230	outw_p(SCANL, dev->iobase + 2);
231
232	return 0;
233}
234
235#ifdef unused
236static int das6402_ai_mode2(struct comedi_device *dev,
237			    struct comedi_subdevice *s, comedi_trig * it)
238{
239	devpriv->das6402_ignoreirq = 1;
240
241#ifdef DEBUG
242	printk("das6402: Starting acquisition\n");
243#endif
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);
247
248	devpriv->ai_bytes_to_read = it->n * sizeof(short);
249
250	/* um... ignoreirq is a nasty race condition */
251	devpriv->das6402_ignoreirq = 0;
252
253	outw_p(SCANL, dev->iobase + 2);
254
255	return 0;
256}
257#endif
258
259static int board_init(struct comedi_device *dev)
260{
261	BYTE b;
262
263	devpriv->das6402_ignoreirq = 1;
264
265	outb(0x07, dev->iobase + 8);
266
267	/* register 11  */
268	outb_p(MODE, dev->iobase + 11);
269	b = BIP | SEM | MODE | GAIN | FIFOHFULL;
270	outb_p(b, dev->iobase + 11);
271
272	/* register 8   */
273	outb_p(EXTEND, dev->iobase + 8);
274	b = EXTEND | MHZ;
275	outb_p(b, dev->iobase + 8);
276	b = MHZ | CLRINT | CLRXTR | CLRXIN;
277	outb_p(b, dev->iobase + 8);
278
279	/* register 9    */
280	b = IRQ | CONVSRC | BURSTEN | INTE;
281	outb_p(b, dev->iobase + 9);
282
283	/* register 10   */
284	b = TGSEL | TGEN;
285	outb_p(b, dev->iobase + 10);
286
287	b = 0x07;
288	outb_p(b, dev->iobase + 8);
289
290	das6402_setcounter(dev);
291
292	outw_p(SCANL, dev->iobase + 2);	/* reset card fifo */
293
294	devpriv->das6402_ignoreirq = 0;
295
296	return 0;
297}
298
299static int das6402_detach(struct comedi_device *dev)
300{
301	if (dev->irq)
302		free_irq(dev->irq, dev);
303	if (dev->iobase)
304		release_region(dev->iobase, DAS6402_SIZE);
305
306	return 0;
307}
308
309static int das6402_attach(struct comedi_device *dev,
310			  struct comedi_devconfig *it)
311{
312	unsigned int irq;
313	unsigned long iobase;
314	int ret;
315	struct comedi_subdevice *s;
316
317	dev->board_name = "das6402";
318
319	iobase = it->options[0];
320	if (iobase == 0)
321		iobase = 0x300;
322
323	printk("comedi%d: das6402: 0x%04lx", dev->minor, iobase);
324
325	if (!request_region(iobase, DAS6402_SIZE, "das6402")) {
326		printk(" I/O port conflict\n");
327		return -EIO;
328	}
329	dev->iobase = iobase;
330
331	/* should do a probe here */
332
333	irq = it->options[0];
334	printk(" ( irq = %u )", irq);
335	ret = request_irq(irq, intr_handler, 0, "das6402", dev);
336	if (ret < 0) {
337		printk("irq conflict\n");
338		return ret;
339	}
340	dev->irq = irq;
341
342	ret = alloc_private(dev, sizeof(struct das6402_private));
343	if (ret < 0)
344		return ret;
345
346	ret = alloc_subdevices(dev, 1);
347	if (ret < 0)
348		return ret;
349
350	/* ai subdevice */
351	s = dev->subdevices + 0;
352	s->type = COMEDI_SUBD_AI;
353	s->subdev_flags = SDF_READABLE | SDF_GROUND;
354	s->n_chan = 8;
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;
360
361	board_init(dev);
362
363	return 0;
364}
365
366MODULE_AUTHOR("Comedi http://www.comedi.org");
367MODULE_DESCRIPTION("Comedi low-level driver");
368MODULE_LICENSE("GPL");
369