Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
das800.c
Go to the documentation of this file.
1 /*
2  comedi/drivers/das800.c
3  Driver for Keitley das800 series boards and compatibles
4  Copyright (C) 2000 Frank Mori Hess <[email protected]>
5 
6  COMEDI - Linux Control and Measurement Device Interface
7  Copyright (C) 2000 David A. Schleef <[email protected]>
8 
9  This program is free software; you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 2 of the License, or
12  (at your option) any later version.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program; if not, write to the Free Software
21  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 
23 ************************************************************************
24 */
25 /*
26 Driver: das800
27 Description: Keithley Metrabyte DAS800 (& compatibles)
28 Author: Frank Mori Hess <[email protected]>
29 Devices: [Keithley Metrabyte] DAS-800 (das-800), DAS-801 (das-801),
30  DAS-802 (das-802),
31  [Measurement Computing] CIO-DAS800 (cio-das800),
32  CIO-DAS801 (cio-das801), CIO-DAS802 (cio-das802),
33  CIO-DAS802/16 (cio-das802/16)
34 Status: works, cio-das802/16 untested - email me if you have tested it
35 
36 Configuration options:
37  [0] - I/O port base address
38  [1] - IRQ (optional, required for timed or externally triggered conversions)
39 
40 Notes:
41  IRQ can be omitted, although the cmd interface will not work without it.
42 
43  All entries in the channel/gain list must use the same gain and be
44  consecutive channels counting upwards in channel number (these are
45  hardware limitations.)
46 
47  I've never tested the gain setting stuff since I only have a
48  DAS-800 board with fixed gain.
49 
50  The cio-das802/16 does not have a fifo-empty status bit! Therefore
51  only fifo-half-full transfers are possible with this card.
52 */
53 /*
54 
55 cmd triggers supported:
56  start_src: TRIG_NOW | TRIG_EXT
57  scan_begin_src: TRIG_FOLLOW
58  scan_end_src: TRIG_COUNT
59  convert_src: TRIG_TIMER | TRIG_EXT
60  stop_src: TRIG_NONE | TRIG_COUNT
61 
62 
63 */
64 
65 #include <linux/interrupt.h>
66 #include "../comedidev.h"
67 
68 #include <linux/ioport.h>
69 #include <linux/delay.h>
70 
71 #include "8253.h"
72 #include "comedi_fc.h"
73 
74 #define DAS800_SIZE 8
75 #define TIMER_BASE 1000
76 #define N_CHAN_AI 8 /* number of analog input channels */
77 
78 /* Registers for the das800 */
79 
80 #define DAS800_LSB 0
81 #define FIFO_EMPTY 0x1
82 #define FIFO_OVF 0x2
83 #define DAS800_MSB 1
84 #define DAS800_CONTROL1 2
85 #define CONTROL1_INTE 0x8
86 #define DAS800_CONV_CONTROL 2
87 #define ITE 0x1
88 #define CASC 0x2
89 #define DTEN 0x4
90 #define IEOC 0x8
91 #define EACS 0x10
92 #define CONV_HCEN 0x80
93 #define DAS800_SCAN_LIMITS 2
94 #define DAS800_STATUS 2
95 #define IRQ 0x8
96 #define BUSY 0x80
97 #define DAS800_GAIN 3
98 #define CIO_FFOV 0x8 /* fifo overflow for cio-das802/16 */
99 #define CIO_ENHF 0x90 /* interrupt fifo half full for cio-das802/16 */
100 #define CONTROL1 0x80
101 #define CONV_CONTROL 0xa0
102 #define SCAN_LIMITS 0xc0
103 #define ID 0xe0
104 #define DAS800_8254 4
105 #define DAS800_STATUS2 7
106 #define STATUS2_HCEN 0x80
107 #define STATUS2_INTE 0X20
108 #define DAS800_ID 7
109 
110 struct das800_board {
111  const char *name;
112  int ai_speed;
113  const struct comedi_lrange *ai_range;
115 };
116 
117 /* analog input ranges */
118 static const struct comedi_lrange range_das800_ai = {
119  1,
120  {
121  RANGE(-5, 5),
122  }
123 };
124 
125 static const struct comedi_lrange range_das801_ai = {
126  9,
127  {
128  RANGE(-5, 5),
129  RANGE(-10, 10),
130  RANGE(0, 10),
131  RANGE(-0.5, 0.5),
132  RANGE(0, 1),
133  RANGE(-0.05, 0.05),
134  RANGE(0, 0.1),
135  RANGE(-0.01, 0.01),
136  RANGE(0, 0.02),
137  }
138 };
139 
140 static const struct comedi_lrange range_cio_das801_ai = {
141  9,
142  {
143  RANGE(-5, 5),
144  RANGE(-10, 10),
145  RANGE(0, 10),
146  RANGE(-0.5, 0.5),
147  RANGE(0, 1),
148  RANGE(-0.05, 0.05),
149  RANGE(0, 0.1),
150  RANGE(-0.005, 0.005),
151  RANGE(0, 0.01),
152  }
153 };
154 
155 static const struct comedi_lrange range_das802_ai = {
156  9,
157  {
158  RANGE(-5, 5),
159  RANGE(-10, 10),
160  RANGE(0, 10),
161  RANGE(-2.5, 2.5),
162  RANGE(0, 5),
163  RANGE(-1.25, 1.25),
164  RANGE(0, 2.5),
165  RANGE(-0.625, 0.625),
166  RANGE(0, 1.25),
167  }
168 };
169 
170 static const struct comedi_lrange range_das80216_ai = {
171  8,
172  {
173  RANGE(-10, 10),
174  RANGE(0, 10),
175  RANGE(-5, 5),
176  RANGE(0, 5),
177  RANGE(-2.5, 2.5),
178  RANGE(0, 2.5),
179  RANGE(-1.25, 1.25),
180  RANGE(0, 1.25),
181  }
182 };
183 
185 
186 static const struct das800_board das800_boards[] = {
187  {
188  .name = "das-800",
189  .ai_speed = 25000,
190  .ai_range = &range_das800_ai,
191  .resolution = 12,
192  },
193  {
194  .name = "cio-das800",
195  .ai_speed = 20000,
196  .ai_range = &range_das800_ai,
197  .resolution = 12,
198  },
199  {
200  .name = "das-801",
201  .ai_speed = 25000,
202  .ai_range = &range_das801_ai,
203  .resolution = 12,
204  },
205  {
206  .name = "cio-das801",
207  .ai_speed = 20000,
208  .ai_range = &range_cio_das801_ai,
209  .resolution = 12,
210  },
211  {
212  .name = "das-802",
213  .ai_speed = 25000,
214  .ai_range = &range_das802_ai,
215  .resolution = 12,
216  },
217  {
218  .name = "cio-das802",
219  .ai_speed = 20000,
220  .ai_range = &range_das802_ai,
221  .resolution = 12,
222  },
223  {
224  .name = "cio-das802/16",
225  .ai_speed = 10000,
226  .ai_range = &range_das80216_ai,
227  .resolution = 16,
228  },
229 };
230 
231 /*
232  * Useful for shorthand access to the particular board structure
233  */
234 #define thisboard ((const struct das800_board *)dev->board_ptr)
235 
237  volatile unsigned int count; /* number of data points left to be taken */
238  volatile int forever; /* flag indicating whether we should take data forever */
239  unsigned int divisor1; /* value to load into board's counter 1 for timed conversions */
240  unsigned int divisor2; /* value to load into board's counter 2 for timed conversions */
241  volatile int do_bits; /* digital output bits */
242 };
243 
244 #define devpriv ((struct das800_private *)dev->private)
245 
246 static int das800_attach(struct comedi_device *dev,
247  struct comedi_devconfig *it);
248 static void das800_detach(struct comedi_device *dev);
249 static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
250 
251 static struct comedi_driver driver_das800 = {
252  .driver_name = "das800",
253  .module = THIS_MODULE,
254  .attach = das800_attach,
255  .detach = das800_detach,
256  .num_names = ARRAY_SIZE(das800_boards),
257  .board_name = &das800_boards[0].name,
258  .offset = sizeof(struct das800_board),
259 };
260 
261 static irqreturn_t das800_interrupt(int irq, void *d);
262 static void enable_das800(struct comedi_device *dev);
263 static void disable_das800(struct comedi_device *dev);
264 static int das800_ai_do_cmdtest(struct comedi_device *dev,
265  struct comedi_subdevice *s,
266  struct comedi_cmd *cmd);
267 static int das800_ai_do_cmd(struct comedi_device *dev,
268  struct comedi_subdevice *s);
269 static int das800_ai_rinsn(struct comedi_device *dev,
270  struct comedi_subdevice *s, struct comedi_insn *insn,
271  unsigned int *data);
272 static int das800_di_rbits(struct comedi_device *dev,
273  struct comedi_subdevice *s, struct comedi_insn *insn,
274  unsigned int *data);
275 static int das800_do_wbits(struct comedi_device *dev,
276  struct comedi_subdevice *s, struct comedi_insn *insn,
277  unsigned int *data);
278 static int das800_probe(struct comedi_device *dev);
279 static int das800_set_frequency(struct comedi_device *dev);
280 
281 /* checks and probes das-800 series board type */
282 static int das800_probe(struct comedi_device *dev)
283 {
284  int id_bits;
285  unsigned long irq_flags;
286  int board;
287 
288  /* 'comedi spin lock irqsave' disables even rt interrupts, we use them to protect indirect addressing */
289  spin_lock_irqsave(&dev->spinlock, irq_flags);
290  outb(ID, dev->iobase + DAS800_GAIN); /* select base address + 7 to be ID register */
291  id_bits = inb(dev->iobase + DAS800_ID) & 0x3; /* get id bits */
292  spin_unlock_irqrestore(&dev->spinlock, irq_flags);
293 
294  board = thisboard - das800_boards;
295 
296  switch (id_bits) {
297  case 0x0:
298  if (board == das800) {
299  dev_dbg(dev->class_dev, "Board model: DAS-800\n");
300  return board;
301  }
302  if (board == ciodas800) {
303  dev_dbg(dev->class_dev, "Board model: CIO-DAS800\n");
304  return board;
305  }
306  dev_dbg(dev->class_dev, "Board model (probed): DAS-800\n");
307  return das800;
308  break;
309  case 0x2:
310  if (board == das801) {
311  dev_dbg(dev->class_dev, "Board model: DAS-801\n");
312  return board;
313  }
314  if (board == ciodas801) {
315  dev_dbg(dev->class_dev, "Board model: CIO-DAS801\n");
316  return board;
317  }
318  dev_dbg(dev->class_dev, "Board model (probed): DAS-801\n");
319  return das801;
320  break;
321  case 0x3:
322  if (board == das802) {
323  dev_dbg(dev->class_dev, "Board model: DAS-802\n");
324  return board;
325  }
326  if (board == ciodas802) {
327  dev_dbg(dev->class_dev, "Board model: CIO-DAS802\n");
328  return board;
329  }
330  if (board == ciodas80216) {
331  dev_dbg(dev->class_dev, "Board model: CIO-DAS802/16\n");
332  return board;
333  }
334  dev_dbg(dev->class_dev, "Board model (probed): DAS-802\n");
335  return das802;
336  break;
337  default:
338  dev_dbg(dev->class_dev,
339  "Board model: probe returned 0x%x (unknown)\n",
340  id_bits);
341  return board;
342  break;
343  }
344  return -1;
345 }
346 
347 /*
348  * A convenient macro that defines init_module() and cleanup_module(),
349  * as necessary.
350  */
351 static int __init driver_das800_init_module(void)
352 {
353  return comedi_driver_register(&driver_das800);
354 }
355 
356 static void __exit driver_das800_cleanup_module(void)
357 {
358  comedi_driver_unregister(&driver_das800);
359 }
360 
361 module_init(driver_das800_init_module);
362 module_exit(driver_das800_cleanup_module);
363 
364 /* interrupt service routine */
365 static irqreturn_t das800_interrupt(int irq, void *d)
366 {
367  short i; /* loop index */
368  short dataPoint = 0;
369  struct comedi_device *dev = d;
370  struct comedi_subdevice *s = dev->read_subdev; /* analog input subdevice */
371  struct comedi_async *async;
372  int status;
373  unsigned long irq_flags;
374  static const int max_loops = 128; /* half-fifo size for cio-das802/16 */
375  /* flags */
376  int fifo_empty = 0;
377  int fifo_overflow = 0;
378 
379  status = inb(dev->iobase + DAS800_STATUS);
380  /* if interrupt was not generated by board or driver not attached, quit */
381  if (!(status & IRQ))
382  return IRQ_NONE;
383  if (!(dev->attached))
384  return IRQ_HANDLED;
385 
386  /* wait until here to initialize async, since we will get null dereference
387  * if interrupt occurs before driver is fully attached!
388  */
389  async = s->async;
390 
391  /* if hardware conversions are not enabled, then quit */
392  spin_lock_irqsave(&dev->spinlock, irq_flags);
393  outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select base address + 7 to be STATUS2 register */
394  status = inb(dev->iobase + DAS800_STATUS2) & STATUS2_HCEN;
395  /* don't release spinlock yet since we want to make sure no one else disables hardware conversions */
396  if (status == 0) {
397  spin_unlock_irqrestore(&dev->spinlock, irq_flags);
398  return IRQ_HANDLED;
399  }
400 
401  /* loop while card's fifo is not empty (and limit to half fifo for cio-das802/16) */
402  for (i = 0; i < max_loops; i++) {
403  /* read 16 bits from dev->iobase and dev->iobase + 1 */
404  dataPoint = inb(dev->iobase + DAS800_LSB);
405  dataPoint += inb(dev->iobase + DAS800_MSB) << 8;
406  if (thisboard->resolution == 12) {
407  fifo_empty = dataPoint & FIFO_EMPTY;
408  fifo_overflow = dataPoint & FIFO_OVF;
409  if (fifo_overflow)
410  break;
411  } else {
412  fifo_empty = 0; /* cio-das802/16 has no fifo empty status bit */
413  }
414  if (fifo_empty)
415  break;
416  /* strip off extraneous bits for 12 bit cards */
417  if (thisboard->resolution == 12)
418  dataPoint = (dataPoint >> 4) & 0xfff;
419  /* if there are more data points to collect */
420  if (devpriv->count > 0 || devpriv->forever == 1) {
421  /* write data point to buffer */
422  cfc_write_to_buffer(s, dataPoint);
423  if (devpriv->count > 0)
424  devpriv->count--;
425  }
426  }
427  async->events |= COMEDI_CB_BLOCK;
428  /* check for fifo overflow */
429  if (thisboard->resolution == 12) {
430  fifo_overflow = dataPoint & FIFO_OVF;
431  /* else cio-das802/16 */
432  } else {
433  fifo_overflow = inb(dev->iobase + DAS800_GAIN) & CIO_FFOV;
434  }
435  if (fifo_overflow) {
436  spin_unlock_irqrestore(&dev->spinlock, irq_flags);
437  comedi_error(dev, "DAS800 FIFO overflow");
438  das800_cancel(dev, s);
440  comedi_event(dev, s);
441  async->events = 0;
442  return IRQ_HANDLED;
443  }
444  if (devpriv->count > 0 || devpriv->forever == 1) {
445  /* Re-enable card's interrupt.
446  * We already have spinlock, so indirect addressing is safe */
447  outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */
448  outb(CONTROL1_INTE | devpriv->do_bits,
449  dev->iobase + DAS800_CONTROL1);
450  spin_unlock_irqrestore(&dev->spinlock, irq_flags);
451  /* otherwise, stop taking data */
452  } else {
453  spin_unlock_irqrestore(&dev->spinlock, irq_flags);
454  disable_das800(dev); /* disable hardware triggered conversions */
455  async->events |= COMEDI_CB_EOA;
456  }
457  comedi_event(dev, s);
458  async->events = 0;
459  return IRQ_HANDLED;
460 }
461 
462 static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
463 {
464  struct comedi_subdevice *s;
465  unsigned long iobase = it->options[0];
466  unsigned int irq = it->options[1];
467  unsigned long irq_flags;
468  int board;
469  int ret;
470 
471  dev_info(dev->class_dev, "das800: io 0x%lx\n", iobase);
472  if (irq)
473  dev_dbg(dev->class_dev, "irq %u\n", irq);
474 
475  /* allocate and initialize dev->private */
476  if (alloc_private(dev, sizeof(struct das800_private)) < 0)
477  return -ENOMEM;
478 
479  if (iobase == 0) {
480  dev_err(dev->class_dev,
481  "io base address required for das800\n");
482  return -EINVAL;
483  }
484 
485  /* check if io addresses are available */
486  if (!request_region(iobase, DAS800_SIZE, "das800")) {
487  dev_err(dev->class_dev, "I/O port conflict\n");
488  return -EIO;
489  }
490  dev->iobase = iobase;
491 
492  board = das800_probe(dev);
493  if (board < 0) {
494  dev_dbg(dev->class_dev, "unable to determine board type\n");
495  return -ENODEV;
496  }
497  dev->board_ptr = das800_boards + board;
498 
499  /* grab our IRQ */
500  if (irq == 1 || irq > 7) {
501  dev_err(dev->class_dev, "irq out of range\n");
502  return -EINVAL;
503  }
504  if (irq) {
505  if (request_irq(irq, das800_interrupt, 0, "das800", dev)) {
506  dev_err(dev->class_dev, "unable to allocate irq %u\n",
507  irq);
508  return -EINVAL;
509  }
510  }
511  dev->irq = irq;
512 
513  dev->board_name = thisboard->name;
514 
515  ret = comedi_alloc_subdevices(dev, 3);
516  if (ret)
517  return ret;
518 
519  /* analog input subdevice */
520  s = &dev->subdevices[0];
521  dev->read_subdev = s;
522  s->type = COMEDI_SUBD_AI;
524  s->n_chan = 8;
525  s->len_chanlist = 8;
526  s->maxdata = (1 << thisboard->resolution) - 1;
527  s->range_table = thisboard->ai_range;
528  s->do_cmd = das800_ai_do_cmd;
529  s->do_cmdtest = das800_ai_do_cmdtest;
530  s->insn_read = das800_ai_rinsn;
531  s->cancel = das800_cancel;
532 
533  /* di */
534  s = &dev->subdevices[1];
535  s->type = COMEDI_SUBD_DI;
537  s->n_chan = 3;
538  s->maxdata = 1;
540  s->insn_bits = das800_di_rbits;
541 
542  /* do */
543  s = &dev->subdevices[2];
544  s->type = COMEDI_SUBD_DO;
546  s->n_chan = 4;
547  s->maxdata = 1;
549  s->insn_bits = das800_do_wbits;
550 
551  disable_das800(dev);
552 
553  /* initialize digital out channels */
554  spin_lock_irqsave(&dev->spinlock, irq_flags);
555  outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */
556  outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);
557  spin_unlock_irqrestore(&dev->spinlock, irq_flags);
558 
559  return 0;
560 };
561 
562 static void das800_detach(struct comedi_device *dev)
563 {
564  if (dev->iobase)
566  if (dev->irq)
567  free_irq(dev->irq, dev);
568 };
569 
570 static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
571 {
572  devpriv->forever = 0;
573  devpriv->count = 0;
574  disable_das800(dev);
575  return 0;
576 }
577 
578 /* enable_das800 makes the card start taking hardware triggered conversions */
579 static void enable_das800(struct comedi_device *dev)
580 {
581  unsigned long irq_flags;
582  spin_lock_irqsave(&dev->spinlock, irq_flags);
583  /* enable fifo-half full interrupts for cio-das802/16 */
584  if (thisboard->resolution == 16)
585  outb(CIO_ENHF, dev->iobase + DAS800_GAIN);
586  outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */
587  outb(CONV_HCEN, dev->iobase + DAS800_CONV_CONTROL); /* enable hardware triggering */
588  outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */
589  outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); /* enable card's interrupt */
590  spin_unlock_irqrestore(&dev->spinlock, irq_flags);
591 }
592 
593 /* disable_das800 stops hardware triggered conversions */
594 static void disable_das800(struct comedi_device *dev)
595 {
596  unsigned long irq_flags;
597  spin_lock_irqsave(&dev->spinlock, irq_flags);
598  outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */
599  outb(0x0, dev->iobase + DAS800_CONV_CONTROL); /* disable hardware triggering of conversions */
600  spin_unlock_irqrestore(&dev->spinlock, irq_flags);
601 }
602 
603 static int das800_ai_do_cmdtest(struct comedi_device *dev,
604  struct comedi_subdevice *s,
605  struct comedi_cmd *cmd)
606 {
607  int err = 0;
608  int tmp;
609  int gain, startChan;
610  int i;
611 
612  /* Step 1 : check if triggers are trivially valid */
613 
614  err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
615  err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
616  err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
617  err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
618  err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
619 
620  if (err)
621  return 1;
622 
623  /* Step 2a : make sure trigger sources are unique */
624 
625  err |= cfc_check_trigger_is_unique(cmd->start_src);
626  err |= cfc_check_trigger_is_unique(cmd->convert_src);
627  err |= cfc_check_trigger_is_unique(cmd->stop_src);
628 
629  /* Step 2b : and mutually compatible */
630 
631  if (err)
632  return 2;
633 
634  /* step 3: make sure arguments are trivially compatible */
635 
636  if (cmd->start_arg != 0) {
637  cmd->start_arg = 0;
638  err++;
639  }
640  if (cmd->convert_src == TRIG_TIMER) {
641  if (cmd->convert_arg < thisboard->ai_speed) {
642  cmd->convert_arg = thisboard->ai_speed;
643  err++;
644  }
645  }
646  if (!cmd->chanlist_len) {
647  cmd->chanlist_len = 1;
648  err++;
649  }
650  if (cmd->scan_end_arg != cmd->chanlist_len) {
651  cmd->scan_end_arg = cmd->chanlist_len;
652  err++;
653  }
654  if (cmd->stop_src == TRIG_COUNT) {
655  if (!cmd->stop_arg) {
656  cmd->stop_arg = 1;
657  err++;
658  }
659  } else { /* TRIG_NONE */
660  if (cmd->stop_arg != 0) {
661  cmd->stop_arg = 0;
662  err++;
663  }
664  }
665 
666  if (err)
667  return 3;
668 
669  /* step 4: fix up any arguments */
670 
671  if (cmd->convert_src == TRIG_TIMER) {
672  tmp = cmd->convert_arg;
673  /* calculate counter values that give desired timing */
674  i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
675  &(devpriv->divisor2),
676  &(cmd->convert_arg),
677  cmd->flags & TRIG_ROUND_MASK);
678  if (tmp != cmd->convert_arg)
679  err++;
680  }
681 
682  if (err)
683  return 4;
684 
685  /* check channel/gain list against card's limitations */
686  if (cmd->chanlist) {
687  gain = CR_RANGE(cmd->chanlist[0]);
688  startChan = CR_CHAN(cmd->chanlist[0]);
689  for (i = 1; i < cmd->chanlist_len; i++) {
690  if (CR_CHAN(cmd->chanlist[i]) !=
691  (startChan + i) % N_CHAN_AI) {
692  comedi_error(dev,
693  "entries in chanlist must be consecutive channels, counting upwards\n");
694  err++;
695  }
696  if (CR_RANGE(cmd->chanlist[i]) != gain) {
697  comedi_error(dev,
698  "entries in chanlist must all have the same gain\n");
699  err++;
700  }
701  }
702  }
703 
704  if (err)
705  return 5;
706 
707  return 0;
708 }
709 
710 static int das800_ai_do_cmd(struct comedi_device *dev,
711  struct comedi_subdevice *s)
712 {
713  int startChan, endChan, scan, gain;
714  int conv_bits;
715  unsigned long irq_flags;
716  struct comedi_async *async = s->async;
717 
718  if (!dev->irq) {
719  comedi_error(dev,
720  "no irq assigned for das-800, cannot do hardware conversions");
721  return -1;
722  }
723 
724  disable_das800(dev);
725 
726  /* set channel scan limits */
727  startChan = CR_CHAN(async->cmd.chanlist[0]);
728  endChan = (startChan + async->cmd.chanlist_len - 1) % 8;
729  scan = (endChan << 3) | startChan;
730 
731  spin_lock_irqsave(&dev->spinlock, irq_flags);
732  outb(SCAN_LIMITS, dev->iobase + DAS800_GAIN); /* select base address + 2 to be scan limits register */
733  outb(scan, dev->iobase + DAS800_SCAN_LIMITS); /* set scan limits */
734  spin_unlock_irqrestore(&dev->spinlock, irq_flags);
735 
736  /* set gain */
737  gain = CR_RANGE(async->cmd.chanlist[0]);
738  if (thisboard->resolution == 12 && gain > 0)
739  gain += 0x7;
740  gain &= 0xf;
741  outb(gain, dev->iobase + DAS800_GAIN);
742 
743  switch (async->cmd.stop_src) {
744  case TRIG_COUNT:
745  devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len;
746  devpriv->forever = 0;
747  break;
748  case TRIG_NONE:
749  devpriv->forever = 1;
750  devpriv->count = 0;
751  break;
752  default:
753  break;
754  }
755 
756  /* enable auto channel scan, send interrupts on end of conversion
757  * and set clock source to internal or external
758  */
759  conv_bits = 0;
760  conv_bits |= EACS | IEOC;
761  if (async->cmd.start_src == TRIG_EXT)
762  conv_bits |= DTEN;
763  switch (async->cmd.convert_src) {
764  case TRIG_TIMER:
765  conv_bits |= CASC | ITE;
766  /* set conversion frequency */
767  i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
768  &(devpriv->divisor2),
769  &(async->cmd.convert_arg),
770  async->cmd.
772  if (das800_set_frequency(dev) < 0) {
773  comedi_error(dev, "Error setting up counters");
774  return -1;
775  }
776  break;
777  case TRIG_EXT:
778  break;
779  default:
780  break;
781  }
782 
783  spin_lock_irqsave(&dev->spinlock, irq_flags);
784  outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */
785  outb(conv_bits, dev->iobase + DAS800_CONV_CONTROL);
786  spin_unlock_irqrestore(&dev->spinlock, irq_flags);
787  async->events = 0;
788  enable_das800(dev);
789  return 0;
790 }
791 
792 static int das800_ai_rinsn(struct comedi_device *dev,
793  struct comedi_subdevice *s, struct comedi_insn *insn,
794  unsigned int *data)
795 {
796  int i, n;
797  int chan;
798  int range;
799  int lsb, msb;
800  int timeout = 1000;
801  unsigned long irq_flags;
802 
803  disable_das800(dev); /* disable hardware conversions (enables software conversions) */
804 
805  /* set multiplexer */
806  chan = CR_CHAN(insn->chanspec);
807 
808  spin_lock_irqsave(&dev->spinlock, irq_flags);
809  outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */
810  outb(chan | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);
811  spin_unlock_irqrestore(&dev->spinlock, irq_flags);
812 
813  /* set gain / range */
814  range = CR_RANGE(insn->chanspec);
815  if (thisboard->resolution == 12 && range)
816  range += 0x7;
817  range &= 0xf;
818  outb(range, dev->iobase + DAS800_GAIN);
819 
820  udelay(5);
821 
822  for (n = 0; n < insn->n; n++) {
823  /* trigger conversion */
824  outb_p(0, dev->iobase + DAS800_MSB);
825 
826  for (i = 0; i < timeout; i++) {
827  if (!(inb(dev->iobase + DAS800_STATUS) & BUSY))
828  break;
829  }
830  if (i == timeout) {
831  comedi_error(dev, "timeout");
832  return -ETIME;
833  }
834  lsb = inb(dev->iobase + DAS800_LSB);
835  msb = inb(dev->iobase + DAS800_MSB);
836  if (thisboard->resolution == 12) {
837  data[n] = (lsb >> 4) & 0xff;
838  data[n] |= (msb << 4);
839  } else {
840  data[n] = (msb << 8) | lsb;
841  }
842  }
843 
844  return n;
845 }
846 
847 static int das800_di_rbits(struct comedi_device *dev,
848  struct comedi_subdevice *s, struct comedi_insn *insn,
849  unsigned int *data)
850 {
851  unsigned int bits;
852 
853  bits = inb(dev->iobase + DAS800_STATUS) >> 4;
854  bits &= 0x7;
855  data[1] = bits;
856  data[0] = 0;
857 
858  return insn->n;
859 }
860 
861 static int das800_do_wbits(struct comedi_device *dev,
862  struct comedi_subdevice *s, struct comedi_insn *insn,
863  unsigned int *data)
864 {
865  int wbits;
866  unsigned long irq_flags;
867 
868  /* only set bits that have been masked */
869  data[0] &= 0xf;
870  wbits = devpriv->do_bits >> 4;
871  wbits &= ~data[0];
872  wbits |= data[0] & data[1];
873  devpriv->do_bits = wbits << 4;
874 
875  spin_lock_irqsave(&dev->spinlock, irq_flags);
876  outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */
877  outb(devpriv->do_bits | CONTROL1_INTE, dev->iobase + DAS800_CONTROL1);
878  spin_unlock_irqrestore(&dev->spinlock, irq_flags);
879 
880  data[1] = wbits;
881 
882  return insn->n;
883 }
884 
885 /* loads counters with divisor1, divisor2 from private structure */
886 static int das800_set_frequency(struct comedi_device *dev)
887 {
888  int err = 0;
889 
890  if (i8254_load(dev->iobase + DAS800_8254, 0, 1, devpriv->divisor1, 2))
891  err++;
892  if (i8254_load(dev->iobase + DAS800_8254, 0, 2, devpriv->divisor2, 2))
893  err++;
894  if (err)
895  return -1;
896 
897  return 0;
898 }
899 
900 MODULE_AUTHOR("Comedi http://www.comedi.org");
901 MODULE_DESCRIPTION("Comedi low-level driver");
902 MODULE_LICENSE("GPL");