]> Pileus Git - ~andy/linux/blob - drivers/staging/comedi/drivers/das800.c
2a6df6b6ae3989848c19c451c5c6bbbb4fceb1f6
[~andy/linux] / drivers / staging / comedi / drivers / das800.c
1 /*
2     comedi/drivers/das800.c
3     Driver for Keitley das800 series boards and compatibles
4     Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net>
5
6     COMEDI - Linux Control and Measurement Device Interface
7     Copyright (C) 2000 David A. Schleef <ds@schleef.org>
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 <fmhess@users.sourceforge.net>
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;
114         int resolution;
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
184 enum { das800, ciodas800, das801, ciodas801, das802, ciodas802, ciodas80216 };
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
236 struct das800_private {
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 static int das800_attach(struct comedi_device *dev,
245                          struct comedi_devconfig *it);
246 static void das800_detach(struct comedi_device *dev);
247 static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
248
249 static struct comedi_driver driver_das800 = {
250         .driver_name = "das800",
251         .module = THIS_MODULE,
252         .attach = das800_attach,
253         .detach = das800_detach,
254         .num_names = ARRAY_SIZE(das800_boards),
255         .board_name = &das800_boards[0].name,
256         .offset = sizeof(struct das800_board),
257 };
258
259 static irqreturn_t das800_interrupt(int irq, void *d);
260 static void enable_das800(struct comedi_device *dev);
261 static void disable_das800(struct comedi_device *dev);
262 static int das800_ai_do_cmdtest(struct comedi_device *dev,
263                                 struct comedi_subdevice *s,
264                                 struct comedi_cmd *cmd);
265 static int das800_ai_do_cmd(struct comedi_device *dev,
266                             struct comedi_subdevice *s);
267 static int das800_ai_rinsn(struct comedi_device *dev,
268                            struct comedi_subdevice *s, struct comedi_insn *insn,
269                            unsigned int *data);
270 static int das800_di_rbits(struct comedi_device *dev,
271                            struct comedi_subdevice *s, struct comedi_insn *insn,
272                            unsigned int *data);
273 static int das800_do_wbits(struct comedi_device *dev,
274                            struct comedi_subdevice *s, struct comedi_insn *insn,
275                            unsigned int *data);
276 static int das800_probe(struct comedi_device *dev);
277 static int das800_set_frequency(struct comedi_device *dev);
278
279 /* checks and probes das-800 series board type */
280 static int das800_probe(struct comedi_device *dev)
281 {
282         int id_bits;
283         unsigned long irq_flags;
284         int board;
285
286         /*  'comedi spin lock irqsave' disables even rt interrupts, we use them to protect indirect addressing */
287         spin_lock_irqsave(&dev->spinlock, irq_flags);
288         outb(ID, dev->iobase + DAS800_GAIN);    /* select base address + 7 to be ID register */
289         id_bits = inb(dev->iobase + DAS800_ID) & 0x3;   /* get id bits */
290         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
291
292         board = thisboard - das800_boards;
293
294         switch (id_bits) {
295         case 0x0:
296                 if (board == das800) {
297                         dev_dbg(dev->class_dev, "Board model: DAS-800\n");
298                         return board;
299                 }
300                 if (board == ciodas800) {
301                         dev_dbg(dev->class_dev, "Board model: CIO-DAS800\n");
302                         return board;
303                 }
304                 dev_dbg(dev->class_dev, "Board model (probed): DAS-800\n");
305                 return das800;
306                 break;
307         case 0x2:
308                 if (board == das801) {
309                         dev_dbg(dev->class_dev, "Board model: DAS-801\n");
310                         return board;
311                 }
312                 if (board == ciodas801) {
313                         dev_dbg(dev->class_dev, "Board model: CIO-DAS801\n");
314                         return board;
315                 }
316                 dev_dbg(dev->class_dev, "Board model (probed): DAS-801\n");
317                 return das801;
318                 break;
319         case 0x3:
320                 if (board == das802) {
321                         dev_dbg(dev->class_dev, "Board model: DAS-802\n");
322                         return board;
323                 }
324                 if (board == ciodas802) {
325                         dev_dbg(dev->class_dev, "Board model: CIO-DAS802\n");
326                         return board;
327                 }
328                 if (board == ciodas80216) {
329                         dev_dbg(dev->class_dev, "Board model: CIO-DAS802/16\n");
330                         return board;
331                 }
332                 dev_dbg(dev->class_dev, "Board model (probed): DAS-802\n");
333                 return das802;
334                 break;
335         default:
336                 dev_dbg(dev->class_dev,
337                         "Board model: probe returned 0x%x (unknown)\n",
338                         id_bits);
339                 return board;
340                 break;
341         }
342         return -1;
343 }
344
345 /*
346  * A convenient macro that defines init_module() and cleanup_module(),
347  * as necessary.
348  */
349 static int __init driver_das800_init_module(void)
350 {
351         return comedi_driver_register(&driver_das800);
352 }
353
354 static void __exit driver_das800_cleanup_module(void)
355 {
356         comedi_driver_unregister(&driver_das800);
357 }
358
359 module_init(driver_das800_init_module);
360 module_exit(driver_das800_cleanup_module);
361
362 /* interrupt service routine */
363 static irqreturn_t das800_interrupt(int irq, void *d)
364 {
365         short i;                /* loop index */
366         short dataPoint = 0;
367         struct comedi_device *dev = d;
368         struct das800_private *devpriv = dev->private;
369         struct comedi_subdevice *s = dev->read_subdev;  /* analog input subdevice */
370         struct comedi_async *async;
371         int status;
372         unsigned long irq_flags;
373         static const int max_loops = 128;       /*  half-fifo size for cio-das802/16 */
374         /*  flags */
375         int fifo_empty = 0;
376         int fifo_overflow = 0;
377
378         status = inb(dev->iobase + DAS800_STATUS);
379         /* if interrupt was not generated by board or driver not attached, quit */
380         if (!(status & IRQ))
381                 return IRQ_NONE;
382         if (!(dev->attached))
383                 return IRQ_HANDLED;
384
385         /* wait until here to initialize async, since we will get null dereference
386          * if interrupt occurs before driver is fully attached!
387          */
388         async = s->async;
389
390         /*  if hardware conversions are not enabled, then quit */
391         spin_lock_irqsave(&dev->spinlock, irq_flags);
392         outb(CONTROL1, dev->iobase + DAS800_GAIN);      /* select base address + 7 to be STATUS2 register */
393         status = inb(dev->iobase + DAS800_STATUS2) & STATUS2_HCEN;
394         /* don't release spinlock yet since we want to make sure no one else disables hardware conversions */
395         if (status == 0) {
396                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
397                 return IRQ_HANDLED;
398         }
399
400         /* loop while card's fifo is not empty (and limit to half fifo for cio-das802/16) */
401         for (i = 0; i < max_loops; i++) {
402                 /* read 16 bits from dev->iobase and dev->iobase + 1 */
403                 dataPoint = inb(dev->iobase + DAS800_LSB);
404                 dataPoint += inb(dev->iobase + DAS800_MSB) << 8;
405                 if (thisboard->resolution == 12) {
406                         fifo_empty = dataPoint & FIFO_EMPTY;
407                         fifo_overflow = dataPoint & FIFO_OVF;
408                         if (fifo_overflow)
409                                 break;
410                 } else {
411                         fifo_empty = 0; /*  cio-das802/16 has no fifo empty status bit */
412                 }
413                 if (fifo_empty)
414                         break;
415                 /* strip off extraneous bits for 12 bit cards */
416                 if (thisboard->resolution == 12)
417                         dataPoint = (dataPoint >> 4) & 0xfff;
418                 /* if there are more data points to collect */
419                 if (devpriv->count > 0 || devpriv->forever == 1) {
420                         /* write data point to buffer */
421                         cfc_write_to_buffer(s, dataPoint);
422                         if (devpriv->count > 0)
423                                 devpriv->count--;
424                 }
425         }
426         async->events |= COMEDI_CB_BLOCK;
427         /* check for fifo overflow */
428         if (thisboard->resolution == 12) {
429                 fifo_overflow = dataPoint & FIFO_OVF;
430                 /*  else cio-das802/16 */
431         } else {
432                 fifo_overflow = inb(dev->iobase + DAS800_GAIN) & CIO_FFOV;
433         }
434         if (fifo_overflow) {
435                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
436                 comedi_error(dev, "DAS800 FIFO overflow");
437                 das800_cancel(dev, s);
438                 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
439                 comedi_event(dev, s);
440                 async->events = 0;
441                 return IRQ_HANDLED;
442         }
443         if (devpriv->count > 0 || devpriv->forever == 1) {
444                 /* Re-enable card's interrupt.
445                  * We already have spinlock, so indirect addressing is safe */
446                 outb(CONTROL1, dev->iobase + DAS800_GAIN);      /* select dev->iobase + 2 to be control register 1 */
447                 outb(CONTROL1_INTE | devpriv->do_bits,
448                      dev->iobase + DAS800_CONTROL1);
449                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
450                 /* otherwise, stop taking data */
451         } else {
452                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
453                 disable_das800(dev);    /* disable hardware triggered conversions */
454                 async->events |= COMEDI_CB_EOA;
455         }
456         comedi_event(dev, s);
457         async->events = 0;
458         return IRQ_HANDLED;
459 }
460
461 static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
462 {
463         struct das800_private *devpriv;
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         ret = alloc_private(dev, sizeof(*devpriv));
476         if (ret)
477                 return ret;
478         devpriv = dev->private;
479
480         if (iobase == 0) {
481                 dev_err(dev->class_dev,
482                         "io base address required for das800\n");
483                 return -EINVAL;
484         }
485
486         /* check if io addresses are available */
487         if (!request_region(iobase, DAS800_SIZE, "das800")) {
488                 dev_err(dev->class_dev, "I/O port conflict\n");
489                 return -EIO;
490         }
491         dev->iobase = iobase;
492
493         board = das800_probe(dev);
494         if (board < 0) {
495                 dev_dbg(dev->class_dev, "unable to determine board type\n");
496                 return -ENODEV;
497         }
498         dev->board_ptr = das800_boards + board;
499
500         /* grab our IRQ */
501         if (irq == 1 || irq > 7) {
502                 dev_err(dev->class_dev, "irq out of range\n");
503                 return -EINVAL;
504         }
505         if (irq) {
506                 if (request_irq(irq, das800_interrupt, 0, "das800", dev)) {
507                         dev_err(dev->class_dev, "unable to allocate irq %u\n",
508                                 irq);
509                         return -EINVAL;
510                 }
511         }
512         dev->irq = irq;
513
514         dev->board_name = thisboard->name;
515
516         ret = comedi_alloc_subdevices(dev, 3);
517         if (ret)
518                 return ret;
519
520         /* analog input subdevice */
521         s = &dev->subdevices[0];
522         dev->read_subdev = s;
523         s->type = COMEDI_SUBD_AI;
524         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
525         s->n_chan = 8;
526         s->len_chanlist = 8;
527         s->maxdata = (1 << thisboard->resolution) - 1;
528         s->range_table = thisboard->ai_range;
529         s->do_cmd = das800_ai_do_cmd;
530         s->do_cmdtest = das800_ai_do_cmdtest;
531         s->insn_read = das800_ai_rinsn;
532         s->cancel = das800_cancel;
533
534         /* di */
535         s = &dev->subdevices[1];
536         s->type = COMEDI_SUBD_DI;
537         s->subdev_flags = SDF_READABLE;
538         s->n_chan = 3;
539         s->maxdata = 1;
540         s->range_table = &range_digital;
541         s->insn_bits = das800_di_rbits;
542
543         /* do */
544         s = &dev->subdevices[2];
545         s->type = COMEDI_SUBD_DO;
546         s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
547         s->n_chan = 4;
548         s->maxdata = 1;
549         s->range_table = &range_digital;
550         s->insn_bits = das800_do_wbits;
551
552         disable_das800(dev);
553
554         /* initialize digital out channels */
555         spin_lock_irqsave(&dev->spinlock, irq_flags);
556         outb(CONTROL1, dev->iobase + DAS800_GAIN);      /* select dev->iobase + 2 to be control register 1 */
557         outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);
558         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
559
560         return 0;
561 };
562
563 static void das800_detach(struct comedi_device *dev)
564 {
565         if (dev->iobase)
566                 release_region(dev->iobase, DAS800_SIZE);
567         if (dev->irq)
568                 free_irq(dev->irq, dev);
569 };
570
571 static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
572 {
573         struct das800_private *devpriv = dev->private;
574
575         devpriv->forever = 0;
576         devpriv->count = 0;
577         disable_das800(dev);
578         return 0;
579 }
580
581 /* enable_das800 makes the card start taking hardware triggered conversions */
582 static void enable_das800(struct comedi_device *dev)
583 {
584         struct das800_private *devpriv = dev->private;
585         unsigned long irq_flags;
586
587         spin_lock_irqsave(&dev->spinlock, irq_flags);
588         /*  enable fifo-half full interrupts for cio-das802/16 */
589         if (thisboard->resolution == 16)
590                 outb(CIO_ENHF, dev->iobase + DAS800_GAIN);
591         outb(CONV_CONTROL, dev->iobase + DAS800_GAIN);  /* select dev->iobase + 2 to be conversion control register */
592         outb(CONV_HCEN, dev->iobase + DAS800_CONV_CONTROL);     /* enable hardware triggering */
593         outb(CONTROL1, dev->iobase + DAS800_GAIN);      /* select dev->iobase + 2 to be control register 1 */
594         outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);  /* enable card's interrupt */
595         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
596 }
597
598 /* disable_das800 stops hardware triggered conversions */
599 static void disable_das800(struct comedi_device *dev)
600 {
601         unsigned long irq_flags;
602         spin_lock_irqsave(&dev->spinlock, irq_flags);
603         outb(CONV_CONTROL, dev->iobase + DAS800_GAIN);  /* select dev->iobase + 2 to be conversion control register */
604         outb(0x0, dev->iobase + DAS800_CONV_CONTROL);   /* disable hardware triggering of conversions */
605         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
606 }
607
608 static int das800_ai_do_cmdtest(struct comedi_device *dev,
609                                 struct comedi_subdevice *s,
610                                 struct comedi_cmd *cmd)
611 {
612         struct das800_private *devpriv = dev->private;
613         int err = 0;
614         int tmp;
615         int gain, startChan;
616         int i;
617
618         /* Step 1 : check if triggers are trivially valid */
619
620         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
621         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
622         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
623         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
624         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
625
626         if (err)
627                 return 1;
628
629         /* Step 2a : make sure trigger sources are unique */
630
631         err |= cfc_check_trigger_is_unique(cmd->start_src);
632         err |= cfc_check_trigger_is_unique(cmd->convert_src);
633         err |= cfc_check_trigger_is_unique(cmd->stop_src);
634
635         /* Step 2b : and mutually compatible */
636
637         if (err)
638                 return 2;
639
640         /* step 3: make sure arguments are trivially compatible */
641
642         if (cmd->start_arg != 0) {
643                 cmd->start_arg = 0;
644                 err++;
645         }
646         if (cmd->convert_src == TRIG_TIMER) {
647                 if (cmd->convert_arg < thisboard->ai_speed) {
648                         cmd->convert_arg = thisboard->ai_speed;
649                         err++;
650                 }
651         }
652         if (!cmd->chanlist_len) {
653                 cmd->chanlist_len = 1;
654                 err++;
655         }
656         if (cmd->scan_end_arg != cmd->chanlist_len) {
657                 cmd->scan_end_arg = cmd->chanlist_len;
658                 err++;
659         }
660         if (cmd->stop_src == TRIG_COUNT) {
661                 if (!cmd->stop_arg) {
662                         cmd->stop_arg = 1;
663                         err++;
664                 }
665         } else {                /* TRIG_NONE */
666                 if (cmd->stop_arg != 0) {
667                         cmd->stop_arg = 0;
668                         err++;
669                 }
670         }
671
672         if (err)
673                 return 3;
674
675         /* step 4: fix up any arguments */
676
677         if (cmd->convert_src == TRIG_TIMER) {
678                 tmp = cmd->convert_arg;
679                 /* calculate counter values that give desired timing */
680                 i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
681                                                &(devpriv->divisor2),
682                                                &(cmd->convert_arg),
683                                                cmd->flags & TRIG_ROUND_MASK);
684                 if (tmp != cmd->convert_arg)
685                         err++;
686         }
687
688         if (err)
689                 return 4;
690
691         /*  check channel/gain list against card's limitations */
692         if (cmd->chanlist) {
693                 gain = CR_RANGE(cmd->chanlist[0]);
694                 startChan = CR_CHAN(cmd->chanlist[0]);
695                 for (i = 1; i < cmd->chanlist_len; i++) {
696                         if (CR_CHAN(cmd->chanlist[i]) !=
697                             (startChan + i) % N_CHAN_AI) {
698                                 comedi_error(dev,
699                                              "entries in chanlist must be consecutive channels, counting upwards\n");
700                                 err++;
701                         }
702                         if (CR_RANGE(cmd->chanlist[i]) != gain) {
703                                 comedi_error(dev,
704                                              "entries in chanlist must all have the same gain\n");
705                                 err++;
706                         }
707                 }
708         }
709
710         if (err)
711                 return 5;
712
713         return 0;
714 }
715
716 static int das800_ai_do_cmd(struct comedi_device *dev,
717                             struct comedi_subdevice *s)
718 {
719         struct das800_private *devpriv = dev->private;
720         int startChan, endChan, scan, gain;
721         int conv_bits;
722         unsigned long irq_flags;
723         struct comedi_async *async = s->async;
724
725         if (!dev->irq) {
726                 comedi_error(dev,
727                              "no irq assigned for das-800, cannot do hardware conversions");
728                 return -1;
729         }
730
731         disable_das800(dev);
732
733         /* set channel scan limits */
734         startChan = CR_CHAN(async->cmd.chanlist[0]);
735         endChan = (startChan + async->cmd.chanlist_len - 1) % 8;
736         scan = (endChan << 3) | startChan;
737
738         spin_lock_irqsave(&dev->spinlock, irq_flags);
739         outb(SCAN_LIMITS, dev->iobase + DAS800_GAIN);   /* select base address + 2 to be scan limits register */
740         outb(scan, dev->iobase + DAS800_SCAN_LIMITS);   /* set scan limits */
741         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
742
743         /* set gain */
744         gain = CR_RANGE(async->cmd.chanlist[0]);
745         if (thisboard->resolution == 12 && gain > 0)
746                 gain += 0x7;
747         gain &= 0xf;
748         outb(gain, dev->iobase + DAS800_GAIN);
749
750         switch (async->cmd.stop_src) {
751         case TRIG_COUNT:
752                 devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len;
753                 devpriv->forever = 0;
754                 break;
755         case TRIG_NONE:
756                 devpriv->forever = 1;
757                 devpriv->count = 0;
758                 break;
759         default:
760                 break;
761         }
762
763         /* enable auto channel scan, send interrupts on end of conversion
764          * and set clock source to internal or external
765          */
766         conv_bits = 0;
767         conv_bits |= EACS | IEOC;
768         if (async->cmd.start_src == TRIG_EXT)
769                 conv_bits |= DTEN;
770         switch (async->cmd.convert_src) {
771         case TRIG_TIMER:
772                 conv_bits |= CASC | ITE;
773                 /* set conversion frequency */
774                 i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
775                                                &(devpriv->divisor2),
776                                                &(async->cmd.convert_arg),
777                                                async->cmd.
778                                                flags & TRIG_ROUND_MASK);
779                 if (das800_set_frequency(dev) < 0) {
780                         comedi_error(dev, "Error setting up counters");
781                         return -1;
782                 }
783                 break;
784         case TRIG_EXT:
785                 break;
786         default:
787                 break;
788         }
789
790         spin_lock_irqsave(&dev->spinlock, irq_flags);
791         outb(CONV_CONTROL, dev->iobase + DAS800_GAIN);  /* select dev->iobase + 2 to be conversion control register */
792         outb(conv_bits, dev->iobase + DAS800_CONV_CONTROL);
793         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
794         async->events = 0;
795         enable_das800(dev);
796         return 0;
797 }
798
799 static int das800_ai_rinsn(struct comedi_device *dev,
800                            struct comedi_subdevice *s, struct comedi_insn *insn,
801                            unsigned int *data)
802 {
803         struct das800_private *devpriv = dev->private;
804         int i, n;
805         int chan;
806         int range;
807         int lsb, msb;
808         int timeout = 1000;
809         unsigned long irq_flags;
810
811         disable_das800(dev);    /* disable hardware conversions (enables software conversions) */
812
813         /* set multiplexer */
814         chan = CR_CHAN(insn->chanspec);
815
816         spin_lock_irqsave(&dev->spinlock, irq_flags);
817         outb(CONTROL1, dev->iobase + DAS800_GAIN);      /* select dev->iobase + 2 to be control register 1 */
818         outb(chan | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);
819         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
820
821         /* set gain / range */
822         range = CR_RANGE(insn->chanspec);
823         if (thisboard->resolution == 12 && range)
824                 range += 0x7;
825         range &= 0xf;
826         outb(range, dev->iobase + DAS800_GAIN);
827
828         udelay(5);
829
830         for (n = 0; n < insn->n; n++) {
831                 /* trigger conversion */
832                 outb_p(0, dev->iobase + DAS800_MSB);
833
834                 for (i = 0; i < timeout; i++) {
835                         if (!(inb(dev->iobase + DAS800_STATUS) & BUSY))
836                                 break;
837                 }
838                 if (i == timeout) {
839                         comedi_error(dev, "timeout");
840                         return -ETIME;
841                 }
842                 lsb = inb(dev->iobase + DAS800_LSB);
843                 msb = inb(dev->iobase + DAS800_MSB);
844                 if (thisboard->resolution == 12) {
845                         data[n] = (lsb >> 4) & 0xff;
846                         data[n] |= (msb << 4);
847                 } else {
848                         data[n] = (msb << 8) | lsb;
849                 }
850         }
851
852         return n;
853 }
854
855 static int das800_di_rbits(struct comedi_device *dev,
856                            struct comedi_subdevice *s, struct comedi_insn *insn,
857                            unsigned int *data)
858 {
859         unsigned int bits;
860
861         bits = inb(dev->iobase + DAS800_STATUS) >> 4;
862         bits &= 0x7;
863         data[1] = bits;
864         data[0] = 0;
865
866         return insn->n;
867 }
868
869 static int das800_do_wbits(struct comedi_device *dev,
870                            struct comedi_subdevice *s, struct comedi_insn *insn,
871                            unsigned int *data)
872 {
873         struct das800_private *devpriv = dev->private;
874         int wbits;
875         unsigned long irq_flags;
876
877         /*  only set bits that have been masked */
878         data[0] &= 0xf;
879         wbits = devpriv->do_bits >> 4;
880         wbits &= ~data[0];
881         wbits |= data[0] & data[1];
882         devpriv->do_bits = wbits << 4;
883
884         spin_lock_irqsave(&dev->spinlock, irq_flags);
885         outb(CONTROL1, dev->iobase + DAS800_GAIN);      /* select dev->iobase + 2 to be control register 1 */
886         outb(devpriv->do_bits | CONTROL1_INTE, dev->iobase + DAS800_CONTROL1);
887         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
888
889         data[1] = wbits;
890
891         return insn->n;
892 }
893
894 /* loads counters with divisor1, divisor2 from private structure */
895 static int das800_set_frequency(struct comedi_device *dev)
896 {
897         struct das800_private *devpriv = dev->private;
898         int err = 0;
899
900         if (i8254_load(dev->iobase + DAS800_8254, 0, 1, devpriv->divisor1, 2))
901                 err++;
902         if (i8254_load(dev->iobase + DAS800_8254, 0, 2, devpriv->divisor2, 2))
903                 err++;
904         if (err)
905                 return -1;
906
907         return 0;
908 }
909
910 MODULE_AUTHOR("Comedi http://www.comedi.org");
911 MODULE_DESCRIPTION("Comedi low-level driver");
912 MODULE_LICENSE("GPL");