staging: comedi: comedi_test: simplify time since last AI scan
[deliverable/linux.git] / drivers / staging / comedi / drivers / das16m1.c
1 /*
2 comedi/drivers/das16m1.c
3 CIO-DAS16/M1 driver
4 Author: Frank Mori Hess, based on code from the das16
5 driver.
6 Copyright (C) 2001 Frank Mori Hess <fmhess@users.sourceforge.net>
7
8 COMEDI - Linux Control and Measurement Device Interface
9 Copyright (C) 2000 David A. Schleef <ds@schleef.org>
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20 */
21 /*
22 Driver: das16m1
23 Description: CIO-DAS16/M1
24 Author: Frank Mori Hess <fmhess@users.sourceforge.net>
25 Devices: [Measurement Computing] CIO-DAS16/M1 (das16m1)
26 Status: works
27
28 This driver supports a single board - the CIO-DAS16/M1.
29 As far as I know, there are no other boards that have
30 the same register layout. Even the CIO-DAS16/M1/16 is
31 significantly different.
32
33 I was _barely_ able to reach the full 1 MHz capability
34 of this board, using a hard real-time interrupt
35 (set the TRIG_RT flag in your struct comedi_cmd and use
36 rtlinux or RTAI). The board can't do dma, so the bottleneck is
37 pulling the data across the ISA bus. I timed the interrupt
38 handler, and it took my computer ~470 microseconds to pull 512
39 samples from the board. So at 1 Mhz sampling rate,
40 expect your CPU to be spending almost all of its
41 time in the interrupt handler.
42
43 This board has some unusual restrictions for its channel/gain list. If the
44 list has 2 or more channels in it, then two conditions must be satisfied:
45 (1) - even/odd channels must appear at even/odd indices in the list
46 (2) - the list must have an even number of entries.
47
48 Options:
49 [0] - base io address
50 [1] - irq (optional, but you probably want it)
51
52 irq can be omitted, although the cmd interface will not work without it.
53 */
54
55 #include <linux/module.h>
56 #include <linux/slab.h>
57 #include <linux/interrupt.h>
58 #include "../comedidev.h"
59
60 #include "8255.h"
61 #include "comedi_8254.h"
62
63 #define DAS16M1_SIZE2 8
64
65 #define FIFO_SIZE 1024 /* 1024 sample fifo */
66
67 /*
68 CIO-DAS16_M1.pdf
69
70 "cio-das16/m1"
71
72 0 a/d bits 0-3, mux start 12 bit
73 1 a/d bits 4-11 unused
74 2 status control
75 3 di 4 bit do 4 bit
76 4 unused clear interrupt
77 5 interrupt, pacer
78 6 channel/gain queue address
79 7 channel/gain queue data
80 89ab 8254
81 cdef 8254
82 400 8255
83 404-407 8254
84
85 */
86
87 #define DAS16M1_AI 0 /* 16-bit wide register */
88 #define AI_CHAN(x) ((x) & 0xf)
89 #define DAS16M1_CS 2
90 #define EXT_TRIG_BIT 0x1
91 #define OVRUN 0x20
92 #define IRQDATA 0x80
93 #define DAS16M1_DIO 3
94 #define DAS16M1_CLEAR_INTR 4
95 #define DAS16M1_INTR_CONTROL 5
96 #define EXT_PACER 0x2
97 #define INT_PACER 0x3
98 #define PACER_MASK 0x3
99 #define INTE 0x80
100 #define DAS16M1_QUEUE_ADDR 6
101 #define DAS16M1_QUEUE_DATA 7
102 #define Q_CHAN(x) ((x) & 0x7)
103 #define Q_RANGE(x) (((x) & 0xf) << 4)
104 #define UNIPOLAR 0x40
105 #define DAS16M1_8254_FIRST 0x8
106 #define DAS16M1_8254_SECOND 0xc
107 #define DAS16M1_82C55 0x400
108 #define DAS16M1_8254_THIRD 0x404
109
110 static const struct comedi_lrange range_das16m1 = {
111 9, {
112 BIP_RANGE(5),
113 BIP_RANGE(2.5),
114 BIP_RANGE(1.25),
115 BIP_RANGE(0.625),
116 UNI_RANGE(10),
117 UNI_RANGE(5),
118 UNI_RANGE(2.5),
119 UNI_RANGE(1.25),
120 BIP_RANGE(10)
121 }
122 };
123
124 struct das16m1_private_struct {
125 struct comedi_8254 *counter;
126 unsigned int control_state;
127 unsigned int adc_count; /* number of samples completed */
128 /* initial value in lower half of hardware conversion counter,
129 * needed to keep track of whether new count has been loaded into
130 * counter yet (loaded by first sample conversion) */
131 u16 initial_hw_count;
132 unsigned short ai_buffer[FIFO_SIZE];
133 unsigned long extra_iobase;
134 };
135
136 static inline unsigned short munge_sample(unsigned short data)
137 {
138 return (data >> 4) & 0xfff;
139 }
140
141 static void munge_sample_array(unsigned short *array, unsigned int num_elements)
142 {
143 unsigned int i;
144
145 for (i = 0; i < num_elements; i++)
146 array[i] = munge_sample(array[i]);
147 }
148
149 static int das16m1_ai_check_chanlist(struct comedi_device *dev,
150 struct comedi_subdevice *s,
151 struct comedi_cmd *cmd)
152 {
153 int i;
154
155 if (cmd->chanlist_len == 1)
156 return 0;
157
158 if ((cmd->chanlist_len % 2) != 0) {
159 dev_dbg(dev->class_dev,
160 "chanlist must be of even length or length 1\n");
161 return -EINVAL;
162 }
163
164 for (i = 0; i < cmd->chanlist_len; i++) {
165 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
166
167 if ((i % 2) != (chan % 2)) {
168 dev_dbg(dev->class_dev,
169 "even/odd channels must go have even/odd chanlist indices\n");
170 return -EINVAL;
171 }
172 }
173
174 return 0;
175 }
176
177 static int das16m1_cmd_test(struct comedi_device *dev,
178 struct comedi_subdevice *s, struct comedi_cmd *cmd)
179 {
180 int err = 0;
181
182 /* Step 1 : check if triggers are trivially valid */
183
184 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
185 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
186 err |= comedi_check_trigger_src(&cmd->convert_src,
187 TRIG_TIMER | TRIG_EXT);
188 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
189 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
190
191 if (err)
192 return 1;
193
194 /* Step 2a : make sure trigger sources are unique */
195
196 err |= comedi_check_trigger_is_unique(cmd->start_src);
197 err |= comedi_check_trigger_is_unique(cmd->convert_src);
198 err |= comedi_check_trigger_is_unique(cmd->stop_src);
199
200 /* Step 2b : and mutually compatible */
201
202 if (err)
203 return 2;
204
205 /* Step 3: check if arguments are trivially valid */
206
207 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
208
209 if (cmd->scan_begin_src == TRIG_FOLLOW) /* internal trigger */
210 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
211
212 if (cmd->convert_src == TRIG_TIMER)
213 err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 1000);
214
215 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
216 cmd->chanlist_len);
217
218 if (cmd->stop_src == TRIG_COUNT)
219 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
220 else /* TRIG_NONE */
221 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
222
223 if (err)
224 return 3;
225
226 /* step 4: fix up arguments */
227
228 if (cmd->convert_src == TRIG_TIMER) {
229 unsigned int arg = cmd->convert_arg;
230
231 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
232 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
233 }
234
235 if (err)
236 return 4;
237
238 /* Step 5: check channel list if it exists */
239 if (cmd->chanlist && cmd->chanlist_len > 0)
240 err |= das16m1_ai_check_chanlist(dev, s, cmd);
241
242 if (err)
243 return 5;
244
245 return 0;
246 }
247
248 static int das16m1_cmd_exec(struct comedi_device *dev,
249 struct comedi_subdevice *s)
250 {
251 struct das16m1_private_struct *devpriv = dev->private;
252 struct comedi_async *async = s->async;
253 struct comedi_cmd *cmd = &async->cmd;
254 unsigned int byte, i;
255
256 /* disable interrupts and internal pacer */
257 devpriv->control_state &= ~INTE & ~PACER_MASK;
258 outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);
259
260 /* set software count */
261 devpriv->adc_count = 0;
262
263 /*
264 * Initialize lower half of hardware counter, used to determine how
265 * many samples are in fifo. Value doesn't actually load into counter
266 * until counter's next clock (the next a/d conversion).
267 */
268 comedi_8254_set_mode(devpriv->counter, 1, I8254_MODE2 | I8254_BINARY);
269 comedi_8254_write(devpriv->counter, 1, 0);
270
271 /*
272 * Remember current reading of counter so we know when counter has
273 * actually been loaded.
274 */
275 devpriv->initial_hw_count = comedi_8254_read(devpriv->counter, 1);
276
277 /* setup channel/gain queue */
278 for (i = 0; i < cmd->chanlist_len; i++) {
279 outb(i, dev->iobase + DAS16M1_QUEUE_ADDR);
280 byte =
281 Q_CHAN(CR_CHAN(cmd->chanlist[i])) |
282 Q_RANGE(CR_RANGE(cmd->chanlist[i]));
283 outb(byte, dev->iobase + DAS16M1_QUEUE_DATA);
284 }
285
286 /* enable interrupts and set internal pacer counter mode and counts */
287 devpriv->control_state &= ~PACER_MASK;
288 if (cmd->convert_src == TRIG_TIMER) {
289 comedi_8254_update_divisors(dev->pacer);
290 comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
291 devpriv->control_state |= INT_PACER;
292 } else { /* TRIG_EXT */
293 devpriv->control_state |= EXT_PACER;
294 }
295
296 /* set control & status register */
297 byte = 0;
298 /* if we are using external start trigger (also board dislikes having
299 * both start and conversion triggers external simultaneously) */
300 if (cmd->start_src == TRIG_EXT && cmd->convert_src != TRIG_EXT)
301 byte |= EXT_TRIG_BIT;
302
303 outb(byte, dev->iobase + DAS16M1_CS);
304 /* clear interrupt bit */
305 outb(0, dev->iobase + DAS16M1_CLEAR_INTR);
306
307 devpriv->control_state |= INTE;
308 outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);
309
310 return 0;
311 }
312
313 static int das16m1_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
314 {
315 struct das16m1_private_struct *devpriv = dev->private;
316
317 devpriv->control_state &= ~INTE & ~PACER_MASK;
318 outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);
319
320 return 0;
321 }
322
323 static int das16m1_ai_eoc(struct comedi_device *dev,
324 struct comedi_subdevice *s,
325 struct comedi_insn *insn,
326 unsigned long context)
327 {
328 unsigned int status;
329
330 status = inb(dev->iobase + DAS16M1_CS);
331 if (status & IRQDATA)
332 return 0;
333 return -EBUSY;
334 }
335
336 static int das16m1_ai_rinsn(struct comedi_device *dev,
337 struct comedi_subdevice *s,
338 struct comedi_insn *insn, unsigned int *data)
339 {
340 struct das16m1_private_struct *devpriv = dev->private;
341 int ret;
342 int n;
343 int byte;
344
345 /* disable interrupts and internal pacer */
346 devpriv->control_state &= ~INTE & ~PACER_MASK;
347 outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);
348
349 /* setup channel/gain queue */
350 outb(0, dev->iobase + DAS16M1_QUEUE_ADDR);
351 byte =
352 Q_CHAN(CR_CHAN(insn->chanspec)) | Q_RANGE(CR_RANGE(insn->chanspec));
353 outb(byte, dev->iobase + DAS16M1_QUEUE_DATA);
354
355 for (n = 0; n < insn->n; n++) {
356 /* clear IRQDATA bit */
357 outb(0, dev->iobase + DAS16M1_CLEAR_INTR);
358 /* trigger conversion */
359 outb(0, dev->iobase);
360
361 ret = comedi_timeout(dev, s, insn, das16m1_ai_eoc, 0);
362 if (ret)
363 return ret;
364
365 data[n] = munge_sample(inw(dev->iobase));
366 }
367
368 return n;
369 }
370
371 static int das16m1_di_rbits(struct comedi_device *dev,
372 struct comedi_subdevice *s,
373 struct comedi_insn *insn, unsigned int *data)
374 {
375 unsigned int bits;
376
377 bits = inb(dev->iobase + DAS16M1_DIO) & 0xf;
378 data[1] = bits;
379 data[0] = 0;
380
381 return insn->n;
382 }
383
384 static int das16m1_do_wbits(struct comedi_device *dev,
385 struct comedi_subdevice *s,
386 struct comedi_insn *insn,
387 unsigned int *data)
388 {
389 if (comedi_dio_update_state(s, data))
390 outb(s->state, dev->iobase + DAS16M1_DIO);
391
392 data[1] = s->state;
393
394 return insn->n;
395 }
396
397 static void das16m1_handler(struct comedi_device *dev, unsigned int status)
398 {
399 struct das16m1_private_struct *devpriv = dev->private;
400 struct comedi_subdevice *s;
401 struct comedi_async *async;
402 struct comedi_cmd *cmd;
403 u16 num_samples;
404 u16 hw_counter;
405
406 s = dev->read_subdev;
407 async = s->async;
408 cmd = &async->cmd;
409
410 /* figure out how many samples are in fifo */
411 hw_counter = comedi_8254_read(devpriv->counter, 1);
412 /* make sure hardware counter reading is not bogus due to initial value
413 * not having been loaded yet */
414 if (devpriv->adc_count == 0 &&
415 hw_counter == devpriv->initial_hw_count) {
416 num_samples = 0;
417 } else {
418 /* The calculation of num_samples looks odd, but it uses the
419 * following facts. 16 bit hardware counter is initialized with
420 * value of zero (which really means 0x1000). The counter
421 * decrements by one on each conversion (when the counter
422 * decrements from zero it goes to 0xffff). num_samples is a
423 * 16 bit variable, so it will roll over in a similar fashion
424 * to the hardware counter. Work it out, and this is what you
425 * get. */
426 num_samples = -hw_counter - devpriv->adc_count;
427 }
428 /* check if we only need some of the points */
429 if (cmd->stop_src == TRIG_COUNT) {
430 if (num_samples > cmd->stop_arg * cmd->chanlist_len)
431 num_samples = cmd->stop_arg * cmd->chanlist_len;
432 }
433 /* make sure we dont try to get too many points if fifo has overrun */
434 if (num_samples > FIFO_SIZE)
435 num_samples = FIFO_SIZE;
436 insw(dev->iobase, devpriv->ai_buffer, num_samples);
437 munge_sample_array(devpriv->ai_buffer, num_samples);
438 comedi_buf_write_samples(s, devpriv->ai_buffer, num_samples);
439 devpriv->adc_count += num_samples;
440
441 if (cmd->stop_src == TRIG_COUNT) {
442 if (devpriv->adc_count >= cmd->stop_arg * cmd->chanlist_len) {
443 /* end of acquisition */
444 async->events |= COMEDI_CB_EOA;
445 }
446 }
447
448 /* this probably won't catch overruns since the card doesn't generate
449 * overrun interrupts, but we might as well try */
450 if (status & OVRUN) {
451 async->events |= COMEDI_CB_ERROR;
452 dev_err(dev->class_dev, "fifo overflow\n");
453 }
454
455 comedi_handle_events(dev, s);
456 }
457
458 static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s)
459 {
460 unsigned long flags;
461 unsigned int status;
462
463 /* prevent race with interrupt handler */
464 spin_lock_irqsave(&dev->spinlock, flags);
465 status = inb(dev->iobase + DAS16M1_CS);
466 das16m1_handler(dev, status);
467 spin_unlock_irqrestore(&dev->spinlock, flags);
468
469 return comedi_buf_n_bytes_ready(s);
470 }
471
472 static irqreturn_t das16m1_interrupt(int irq, void *d)
473 {
474 int status;
475 struct comedi_device *dev = d;
476
477 if (!dev->attached) {
478 dev_err(dev->class_dev, "premature interrupt\n");
479 return IRQ_HANDLED;
480 }
481 /* prevent race with comedi_poll() */
482 spin_lock(&dev->spinlock);
483
484 status = inb(dev->iobase + DAS16M1_CS);
485
486 if ((status & (IRQDATA | OVRUN)) == 0) {
487 dev_err(dev->class_dev, "spurious interrupt\n");
488 spin_unlock(&dev->spinlock);
489 return IRQ_NONE;
490 }
491
492 das16m1_handler(dev, status);
493
494 /* clear interrupt */
495 outb(0, dev->iobase + DAS16M1_CLEAR_INTR);
496
497 spin_unlock(&dev->spinlock);
498 return IRQ_HANDLED;
499 }
500
501 static int das16m1_irq_bits(unsigned int irq)
502 {
503 switch (irq) {
504 case 10:
505 return 0x0;
506 case 11:
507 return 0x1;
508 case 12:
509 return 0x2;
510 case 15:
511 return 0x3;
512 case 2:
513 return 0x4;
514 case 3:
515 return 0x5;
516 case 5:
517 return 0x6;
518 case 7:
519 return 0x7;
520 default:
521 return 0x0;
522 }
523 }
524
525 /*
526 * Options list:
527 * 0 I/O base
528 * 1 IRQ
529 */
530 static int das16m1_attach(struct comedi_device *dev,
531 struct comedi_devconfig *it)
532 {
533 struct das16m1_private_struct *devpriv;
534 struct comedi_subdevice *s;
535 int ret;
536
537 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
538 if (!devpriv)
539 return -ENOMEM;
540
541 ret = comedi_request_region(dev, it->options[0], 0x10);
542 if (ret)
543 return ret;
544 /* Request an additional region for the 8255 */
545 ret = __comedi_request_region(dev, dev->iobase + DAS16M1_82C55,
546 DAS16M1_SIZE2);
547 if (ret)
548 return ret;
549 devpriv->extra_iobase = dev->iobase + DAS16M1_82C55;
550
551 /* only irqs 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, and 15 are valid */
552 if ((1 << it->options[1]) & 0xdcfc) {
553 ret = request_irq(it->options[1], das16m1_interrupt, 0,
554 dev->board_name, dev);
555 if (ret == 0)
556 dev->irq = it->options[1];
557 }
558
559 dev->pacer = comedi_8254_init(dev->iobase + DAS16M1_8254_SECOND,
560 I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
561 if (!dev->pacer)
562 return -ENOMEM;
563
564 devpriv->counter = comedi_8254_init(dev->iobase + DAS16M1_8254_FIRST,
565 0, I8254_IO8, 0);
566 if (!devpriv->counter)
567 return -ENOMEM;
568
569 ret = comedi_alloc_subdevices(dev, 4);
570 if (ret)
571 return ret;
572
573 s = &dev->subdevices[0];
574 /* ai */
575 s->type = COMEDI_SUBD_AI;
576 s->subdev_flags = SDF_READABLE | SDF_DIFF;
577 s->n_chan = 8;
578 s->maxdata = (1 << 12) - 1;
579 s->range_table = &range_das16m1;
580 s->insn_read = das16m1_ai_rinsn;
581 if (dev->irq) {
582 dev->read_subdev = s;
583 s->subdev_flags |= SDF_CMD_READ;
584 s->len_chanlist = 256;
585 s->do_cmdtest = das16m1_cmd_test;
586 s->do_cmd = das16m1_cmd_exec;
587 s->cancel = das16m1_cancel;
588 s->poll = das16m1_poll;
589 }
590
591 s = &dev->subdevices[1];
592 /* di */
593 s->type = COMEDI_SUBD_DI;
594 s->subdev_flags = SDF_READABLE;
595 s->n_chan = 4;
596 s->maxdata = 1;
597 s->range_table = &range_digital;
598 s->insn_bits = das16m1_di_rbits;
599
600 s = &dev->subdevices[2];
601 /* do */
602 s->type = COMEDI_SUBD_DO;
603 s->subdev_flags = SDF_WRITABLE;
604 s->n_chan = 4;
605 s->maxdata = 1;
606 s->range_table = &range_digital;
607 s->insn_bits = das16m1_do_wbits;
608
609 s = &dev->subdevices[3];
610 /* 8255 */
611 ret = subdev_8255_init(dev, s, NULL, DAS16M1_82C55);
612 if (ret)
613 return ret;
614
615 /* initialize digital output lines */
616 outb(0, dev->iobase + DAS16M1_DIO);
617
618 /* set the interrupt level */
619 devpriv->control_state = das16m1_irq_bits(dev->irq) << 4;
620 outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);
621
622 return 0;
623 }
624
625 static void das16m1_detach(struct comedi_device *dev)
626 {
627 struct das16m1_private_struct *devpriv = dev->private;
628
629 if (devpriv) {
630 if (devpriv->extra_iobase)
631 release_region(devpriv->extra_iobase, DAS16M1_SIZE2);
632 kfree(devpriv->counter);
633 }
634 comedi_legacy_detach(dev);
635 }
636
637 static struct comedi_driver das16m1_driver = {
638 .driver_name = "das16m1",
639 .module = THIS_MODULE,
640 .attach = das16m1_attach,
641 .detach = das16m1_detach,
642 };
643 module_comedi_driver(das16m1_driver);
644
645 MODULE_AUTHOR("Comedi http://www.comedi.org");
646 MODULE_DESCRIPTION("Comedi low-level driver");
647 MODULE_LICENSE("GPL");
This page took 0.046772 seconds and 5 git commands to generate.