Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
das6402.c
Go to the documentation of this file.
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 <[email protected]>
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 /*
32 Driver: das6402
33 Description: Keithley Metrabyte DAS6402 (& compatibles)
34 Author: Oystein Svendsen <[email protected]>
35 Status: bitrotten
36 Devices: [Keithley Metrabyte] DAS6402 (das6402)
37 
38 This 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 
104 
106 };
107 #define devpriv ((struct das6402_private *)dev->private)
108 
109 static void das6402_ai_fifo_dregs(struct comedi_device *dev,
110  struct comedi_subdevice *s)
111 {
112  while (1) {
113  if (!(inb(dev->iobase + 8) & 0x01))
114  return;
115  comedi_buf_put(s->async, inw(dev->iobase));
116  }
117 }
118 
119 static void das6402_setcounter(struct comedi_device *dev)
120 {
121  BYTE p;
122  unsigned short ctrlwrd;
123 
124  /* set up counter0 first, mode 0 */
125  p = M0 | C0 | RWLH;
126  outb_p(p, dev->iobase + 15);
127  ctrlwrd = 2000;
128  p = (BYTE) (0xff & ctrlwrd);
129  outb_p(p, dev->iobase + 12);
130  p = (BYTE) (0xff & (ctrlwrd >> 8));
131  outb_p(p, dev->iobase + 12);
132 
133  /* set up counter1, mode 2 */
134  p = M2 | C1 | RWLH;
135  outb_p(p, dev->iobase + 15);
136  ctrlwrd = 10;
137  p = (BYTE) (0xff & ctrlwrd);
138  outb_p(p, dev->iobase + 13);
139  p = (BYTE) (0xff & (ctrlwrd >> 8));
140  outb_p(p, dev->iobase + 13);
141 
142  /* set up counter1, mode 2 */
143  p = M2 | C2 | RWLH;
144  outb_p(p, dev->iobase + 15);
145  ctrlwrd = 1000;
146  p = (BYTE) (0xff & ctrlwrd);
147  outb_p(p, dev->iobase + 14);
148  p = (BYTE) (0xff & (ctrlwrd >> 8));
149  outb_p(p, dev->iobase + 14);
150 }
151 
152 static irqreturn_t intr_handler(int irq, void *d)
153 {
154  struct comedi_device *dev = d;
155  struct comedi_subdevice *s = &dev->subdevices[0];
156 
157  if (!dev->attached || devpriv->das6402_ignoreirq) {
158  dev_warn(dev->class_dev, "BUG: spurious interrupt\n");
159  return IRQ_HANDLED;
160  }
161 #ifdef DEBUG
162  printk("das6402: interrupt! das6402_irqcount=%i\n",
163  devpriv->das6402_irqcount);
164  printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2));
165 #endif
166 
167  das6402_ai_fifo_dregs(dev, s);
168 
169  if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) {
170  outw_p(SCANL, dev->iobase + 2); /* clears the fifo */
171  outb(0x07, dev->iobase + 8); /* clears all flip-flops */
172 #ifdef DEBUG
173  printk("das6402: Got %i samples\n\n",
174  devpriv->das6402_wordsread - diff);
175 #endif
176  s->async->events |= COMEDI_CB_EOA;
177  comedi_event(dev, s);
178  }
179 
180  outb(0x01, dev->iobase + 8); /* clear only the interrupt flip-flop */
181 
182  comedi_event(dev, s);
183  return IRQ_HANDLED;
184 }
185 
186 #if 0
187 static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n)
188 {
189  int i;
190 
191  for (i = 0; i < n; i++)
192  data[i] = inw(dev->iobase);
193 }
194 #endif
195 
196 static int das6402_ai_cancel(struct comedi_device *dev,
197  struct comedi_subdevice *s)
198 {
199  /*
200  * This function should reset the board from whatever condition it
201  * is in (i.e., acquiring data), to a non-active state.
202  */
203 
204  devpriv->das6402_ignoreirq = 1;
205  dev_dbg(dev->class_dev, "Stopping acquisition\n");
206  devpriv->das6402_ignoreirq = 1;
207  outb_p(0x02, dev->iobase + 10); /* disable external trigging */
208  outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
209  outb_p(0, dev->iobase + 9); /* disables interrupts */
210 
211  outw_p(SCANL, dev->iobase + 2);
212 
213  return 0;
214 }
215 
216 #ifdef unused
217 static int das6402_ai_mode2(struct comedi_device *dev,
218  struct comedi_subdevice *s, comedi_trig * it)
219 {
220  devpriv->das6402_ignoreirq = 1;
221  dev_dbg(dev->class_dev, "Starting acquisition\n");
222  outb_p(0x03, dev->iobase + 10); /* enable external trigging */
223  outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
224  outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9);
225 
226  devpriv->ai_bytes_to_read = it->n * sizeof(short);
227 
228  /* um... ignoreirq is a nasty race condition */
229  devpriv->das6402_ignoreirq = 0;
230 
231  outw_p(SCANL, dev->iobase + 2);
232 
233  return 0;
234 }
235 #endif
236 
237 static int board_init(struct comedi_device *dev)
238 {
239  BYTE b;
240 
241  devpriv->das6402_ignoreirq = 1;
242 
243  outb(0x07, dev->iobase + 8);
244 
245  /* register 11 */
246  outb_p(MODE, dev->iobase + 11);
247  b = BIP | SEM | MODE | GAIN | FIFOHFULL;
248  outb_p(b, dev->iobase + 11);
249 
250  /* register 8 */
251  outb_p(EXTEND, dev->iobase + 8);
252  b = EXTEND | MHZ;
253  outb_p(b, dev->iobase + 8);
254  b = MHZ | CLRINT | CLRXTR | CLRXIN;
255  outb_p(b, dev->iobase + 8);
256 
257  /* register 9 */
258  b = IRQ | CONVSRC | BURSTEN | INTE;
259  outb_p(b, dev->iobase + 9);
260 
261  /* register 10 */
262  b = TGSEL | TGEN;
263  outb_p(b, dev->iobase + 10);
264 
265  b = 0x07;
266  outb_p(b, dev->iobase + 8);
267 
268  das6402_setcounter(dev);
269 
270  outw_p(SCANL, dev->iobase + 2); /* reset card fifo */
271 
272  devpriv->das6402_ignoreirq = 0;
273 
274  return 0;
275 }
276 
277 static int das6402_attach(struct comedi_device *dev,
278  struct comedi_devconfig *it)
279 {
280  unsigned int irq;
281  unsigned long iobase;
282  int ret;
283  struct comedi_subdevice *s;
284 
285  dev->board_name = "das6402";
286 
287  iobase = it->options[0];
288  if (iobase == 0)
289  iobase = 0x300;
290 
291  if (!request_region(iobase, DAS6402_SIZE, "das6402")) {
292  dev_err(dev->class_dev, "I/O port conflict\n");
293  return -EIO;
294  }
295  dev->iobase = iobase;
296 
297  /* should do a probe here */
298 
299  irq = it->options[0];
300  dev_dbg(dev->class_dev, "( irq = %u )\n", irq);
301  ret = request_irq(irq, intr_handler, 0, "das6402", dev);
302  if (ret < 0)
303  return ret;
304 
305  dev->irq = irq;
306  ret = alloc_private(dev, sizeof(struct das6402_private));
307  if (ret < 0)
308  return ret;
309 
310  ret = comedi_alloc_subdevices(dev, 1);
311  if (ret)
312  return ret;
313 
314  /* ai subdevice */
315  s = &dev->subdevices[0];
316  s->type = COMEDI_SUBD_AI;
318  s->n_chan = 8;
319  /* s->trig[2]=das6402_ai_mode2; */
320  s->cancel = das6402_ai_cancel;
321  s->maxdata = (1 << 12) - 1;
322  s->len_chanlist = 16; /* ? */
324 
325  board_init(dev);
326 
327  return 0;
328 }
329 
330 static void das6402_detach(struct comedi_device *dev)
331 {
332  if (dev->irq)
333  free_irq(dev->irq, dev);
334  if (dev->iobase)
336 }
337 
338 static struct comedi_driver das6402_driver = {
339  .driver_name = "das6402",
340  .module = THIS_MODULE,
341  .attach = das6402_attach,
342  .detach = das6402_detach,
343 };
344 module_comedi_driver(das6402_driver)
345 
346 MODULE_AUTHOR("Comedi http://www.comedi.org");
348 MODULE_LICENSE("GPL");