Linux-libre 3.0.60-gnu1
[librecmc/linux-libre.git] / 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 #define devpriv ((struct das800_private *)dev->private)
245
246 static int das800_attach(struct comedi_device *dev,
247                          struct comedi_devconfig *it);
248 static int 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                         printk(" Board model: DAS-800\n");
300                         return board;
301                 }
302                 if (board == ciodas800) {
303                         printk(" Board model: CIO-DAS800\n");
304                         return board;
305                 }
306                 printk(" Board model (probed): DAS-800\n");
307                 return das800;
308                 break;
309         case 0x2:
310                 if (board == das801) {
311                         printk(" Board model: DAS-801\n");
312                         return board;
313                 }
314                 if (board == ciodas801) {
315                         printk(" Board model: CIO-DAS801\n");
316                         return board;
317                 }
318                 printk(" Board model (probed): DAS-801\n");
319                 return das801;
320                 break;
321         case 0x3:
322                 if (board == das802) {
323                         printk(" Board model: DAS-802\n");
324                         return board;
325                 }
326                 if (board == ciodas802) {
327                         printk(" Board model: CIO-DAS802\n");
328                         return board;
329                 }
330                 if (board == ciodas80216) {
331                         printk(" Board model: CIO-DAS802/16\n");
332                         return board;
333                 }
334                 printk(" Board model (probed): DAS-802\n");
335                 return das802;
336                 break;
337         default:
338                 printk(" Board model: probe returned 0x%x (unknown)\n",
339                        id_bits);
340                 return board;
341                 break;
342         }
343         return -1;
344 }
345
346 /*
347  * A convenient macro that defines init_module() and cleanup_module(),
348  * as necessary.
349  */
350 static int __init driver_das800_init_module(void)
351 {
352         return comedi_driver_register(&driver_das800);
353 }
354
355 static void __exit driver_das800_cleanup_module(void)
356 {
357         comedi_driver_unregister(&driver_das800);
358 }
359
360 module_init(driver_das800_init_module);
361 module_exit(driver_das800_cleanup_module);
362
363 /* interrupt service routine */
364 static irqreturn_t das800_interrupt(int irq, void *d)
365 {
366         short i;                /* loop index */
367         short dataPoint = 0;
368         struct comedi_device *dev = d;
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, dev->subdevices + 0);
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);    /* diable 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 comedi_subdevice *s;
464         unsigned long iobase = it->options[0];
465         unsigned int irq = it->options[1];
466         unsigned long irq_flags;
467         int board;
468
469         printk("comedi%d: das800: io 0x%lx", dev->minor, iobase);
470         if (irq)
471                 printk(", irq %u", irq);
472         printk("\n");
473
474         /* allocate and initialize dev->private */
475         if (alloc_private(dev, sizeof(struct das800_private)) < 0)
476                 return -ENOMEM;
477
478         if (iobase == 0) {
479                 printk("io base address required for das800\n");
480                 return -EINVAL;
481         }
482
483         /* check if io addresses are available */
484         if (!request_region(iobase, DAS800_SIZE, "das800")) {
485                 printk("I/O port conflict\n");
486                 return -EIO;
487         }
488         dev->iobase = iobase;
489
490         board = das800_probe(dev);
491         if (board < 0) {
492                 printk("unable to determine board type\n");
493                 return -ENODEV;
494         }
495         dev->board_ptr = das800_boards + board;
496
497         /* grab our IRQ */
498         if (irq == 1 || irq > 7) {
499                 printk("irq out of range\n");
500                 return -EINVAL;
501         }
502         if (irq) {
503                 if (request_irq(irq, das800_interrupt, 0, "das800", dev)) {
504                         printk("unable to allocate irq %u\n", irq);
505                         return -EINVAL;
506                 }
507         }
508         dev->irq = irq;
509
510         dev->board_name = thisboard->name;
511
512         if (alloc_subdevices(dev, 3) < 0)
513                 return -ENOMEM;
514
515         /* analog input subdevice */
516         s = dev->subdevices + 0;
517         dev->read_subdev = s;
518         s->type = COMEDI_SUBD_AI;
519         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
520         s->n_chan = 8;
521         s->len_chanlist = 8;
522         s->maxdata = (1 << thisboard->resolution) - 1;
523         s->range_table = thisboard->ai_range;
524         s->do_cmd = das800_ai_do_cmd;
525         s->do_cmdtest = das800_ai_do_cmdtest;
526         s->insn_read = das800_ai_rinsn;
527         s->cancel = das800_cancel;
528
529         /* di */
530         s = dev->subdevices + 1;
531         s->type = COMEDI_SUBD_DI;
532         s->subdev_flags = SDF_READABLE;
533         s->n_chan = 3;
534         s->maxdata = 1;
535         s->range_table = &range_digital;
536         s->insn_bits = das800_di_rbits;
537
538         /* do */
539         s = dev->subdevices + 2;
540         s->type = COMEDI_SUBD_DO;
541         s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
542         s->n_chan = 4;
543         s->maxdata = 1;
544         s->range_table = &range_digital;
545         s->insn_bits = das800_do_wbits;
546
547         disable_das800(dev);
548
549         /* initialize digital out channels */
550         spin_lock_irqsave(&dev->spinlock, irq_flags);
551         outb(CONTROL1, dev->iobase + DAS800_GAIN);      /* select dev->iobase + 2 to be control register 1 */
552         outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);
553         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
554
555         return 0;
556 };
557
558 static int das800_detach(struct comedi_device *dev)
559 {
560         printk("comedi%d: das800: remove\n", dev->minor);
561
562         /* only free stuff if it has been allocated by _attach */
563         if (dev->iobase)
564                 release_region(dev->iobase, DAS800_SIZE);
565         if (dev->irq)
566                 free_irq(dev->irq, dev);
567         return 0;
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: make sure trigger sources are trivially valid */
613
614         tmp = cmd->start_src;
615         cmd->start_src &= TRIG_NOW | TRIG_EXT;
616         if (!cmd->start_src || tmp != cmd->start_src)
617                 err++;
618
619         tmp = cmd->scan_begin_src;
620         cmd->scan_begin_src &= TRIG_FOLLOW;
621         if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
622                 err++;
623
624         tmp = cmd->convert_src;
625         cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
626         if (!cmd->convert_src || tmp != cmd->convert_src)
627                 err++;
628
629         tmp = cmd->scan_end_src;
630         cmd->scan_end_src &= TRIG_COUNT;
631         if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
632                 err++;
633
634         tmp = cmd->stop_src;
635         cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
636         if (!cmd->stop_src || tmp != cmd->stop_src)
637                 err++;
638
639         if (err)
640                 return 1;
641
642         /* step 2: make sure trigger sources are unique and mutually compatible */
643
644         if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
645                 err++;
646         if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
647                 err++;
648         if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
649                 err++;
650
651         if (err)
652                 return 2;
653
654         /* step 3: make sure arguments are trivially compatible */
655
656         if (cmd->start_arg != 0) {
657                 cmd->start_arg = 0;
658                 err++;
659         }
660         if (cmd->convert_src == TRIG_TIMER) {
661                 if (cmd->convert_arg < thisboard->ai_speed) {
662                         cmd->convert_arg = thisboard->ai_speed;
663                         err++;
664                 }
665         }
666         if (!cmd->chanlist_len) {
667                 cmd->chanlist_len = 1;
668                 err++;
669         }
670         if (cmd->scan_end_arg != cmd->chanlist_len) {
671                 cmd->scan_end_arg = cmd->chanlist_len;
672                 err++;
673         }
674         if (cmd->stop_src == TRIG_COUNT) {
675                 if (!cmd->stop_arg) {
676                         cmd->stop_arg = 1;
677                         err++;
678                 }
679         } else {                /* TRIG_NONE */
680                 if (cmd->stop_arg != 0) {
681                         cmd->stop_arg = 0;
682                         err++;
683                 }
684         }
685
686         if (err)
687                 return 3;
688
689         /* step 4: fix up any arguments */
690
691         if (cmd->convert_src == TRIG_TIMER) {
692                 tmp = cmd->convert_arg;
693                 /* calculate counter values that give desired timing */
694                 i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
695                                                &(devpriv->divisor2),
696                                                &(cmd->convert_arg),
697                                                cmd->flags & TRIG_ROUND_MASK);
698                 if (tmp != cmd->convert_arg)
699                         err++;
700         }
701
702         if (err)
703                 return 4;
704
705         /*  check channel/gain list against card's limitations */
706         if (cmd->chanlist) {
707                 gain = CR_RANGE(cmd->chanlist[0]);
708                 startChan = CR_CHAN(cmd->chanlist[0]);
709                 for (i = 1; i < cmd->chanlist_len; i++) {
710                         if (CR_CHAN(cmd->chanlist[i]) !=
711                             (startChan + i) % N_CHAN_AI) {
712                                 comedi_error(dev,
713                                              "entries in chanlist must be consecutive channels, counting upwards\n");
714                                 err++;
715                         }
716                         if (CR_RANGE(cmd->chanlist[i]) != gain) {
717                                 comedi_error(dev,
718                                              "entries in chanlist must all have the same gain\n");
719                                 err++;
720                         }
721                 }
722         }
723
724         if (err)
725                 return 5;
726
727         return 0;
728 }
729
730 static int das800_ai_do_cmd(struct comedi_device *dev,
731                             struct comedi_subdevice *s)
732 {
733         int startChan, endChan, scan, gain;
734         int conv_bits;
735         unsigned long irq_flags;
736         struct comedi_async *async = s->async;
737
738         if (!dev->irq) {
739                 comedi_error(dev,
740                              "no irq assigned for das-800, cannot do hardware conversions");
741                 return -1;
742         }
743
744         disable_das800(dev);
745
746         /* set channel scan limits */
747         startChan = CR_CHAN(async->cmd.chanlist[0]);
748         endChan = (startChan + async->cmd.chanlist_len - 1) % 8;
749         scan = (endChan << 3) | startChan;
750
751         spin_lock_irqsave(&dev->spinlock, irq_flags);
752         outb(SCAN_LIMITS, dev->iobase + DAS800_GAIN);   /* select base address + 2 to be scan limits register */
753         outb(scan, dev->iobase + DAS800_SCAN_LIMITS);   /* set scan limits */
754         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
755
756         /* set gain */
757         gain = CR_RANGE(async->cmd.chanlist[0]);
758         if (thisboard->resolution == 12 && gain > 0)
759                 gain += 0x7;
760         gain &= 0xf;
761         outb(gain, dev->iobase + DAS800_GAIN);
762
763         switch (async->cmd.stop_src) {
764         case TRIG_COUNT:
765                 devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len;
766                 devpriv->forever = 0;
767                 break;
768         case TRIG_NONE:
769                 devpriv->forever = 1;
770                 devpriv->count = 0;
771                 break;
772         default:
773                 break;
774         }
775
776         /* enable auto channel scan, send interrupts on end of conversion
777          * and set clock source to internal or external
778          */
779         conv_bits = 0;
780         conv_bits |= EACS | IEOC;
781         if (async->cmd.start_src == TRIG_EXT)
782                 conv_bits |= DTEN;
783         switch (async->cmd.convert_src) {
784         case TRIG_TIMER:
785                 conv_bits |= CASC | ITE;
786                 /* set conversion frequency */
787                 i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
788                                                &(devpriv->divisor2),
789                                                &(async->cmd.convert_arg),
790                                                async->cmd.
791                                                flags & TRIG_ROUND_MASK);
792                 if (das800_set_frequency(dev) < 0) {
793                         comedi_error(dev, "Error setting up counters");
794                         return -1;
795                 }
796                 break;
797         case TRIG_EXT:
798                 break;
799         default:
800                 break;
801         }
802
803         spin_lock_irqsave(&dev->spinlock, irq_flags);
804         outb(CONV_CONTROL, dev->iobase + DAS800_GAIN);  /* select dev->iobase + 2 to be conversion control register */
805         outb(conv_bits, dev->iobase + DAS800_CONV_CONTROL);
806         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
807         async->events = 0;
808         enable_das800(dev);
809         return 0;
810 }
811
812 static int das800_ai_rinsn(struct comedi_device *dev,
813                            struct comedi_subdevice *s, struct comedi_insn *insn,
814                            unsigned int *data)
815 {
816         int i, n;
817         int chan;
818         int range;
819         int lsb, msb;
820         int timeout = 1000;
821         unsigned long irq_flags;
822
823         disable_das800(dev);    /* disable hardware conversions (enables software conversions) */
824
825         /* set multiplexer */
826         chan = CR_CHAN(insn->chanspec);
827
828         spin_lock_irqsave(&dev->spinlock, irq_flags);
829         outb(CONTROL1, dev->iobase + DAS800_GAIN);      /* select dev->iobase + 2 to be control register 1 */
830         outb(chan | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);
831         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
832
833         /* set gain / range */
834         range = CR_RANGE(insn->chanspec);
835         if (thisboard->resolution == 12 && range)
836                 range += 0x7;
837         range &= 0xf;
838         outb(range, dev->iobase + DAS800_GAIN);
839
840         udelay(5);
841
842         for (n = 0; n < insn->n; n++) {
843                 /* trigger conversion */
844                 outb_p(0, dev->iobase + DAS800_MSB);
845
846                 for (i = 0; i < timeout; i++) {
847                         if (!(inb(dev->iobase + DAS800_STATUS) & BUSY))
848                                 break;
849                 }
850                 if (i == timeout) {
851                         comedi_error(dev, "timeout");
852                         return -ETIME;
853                 }
854                 lsb = inb(dev->iobase + DAS800_LSB);
855                 msb = inb(dev->iobase + DAS800_MSB);
856                 if (thisboard->resolution == 12) {
857                         data[n] = (lsb >> 4) & 0xff;
858                         data[n] |= (msb << 4);
859                 } else {
860                         data[n] = (msb << 8) | lsb;
861                 }
862         }
863
864         return n;
865 }
866
867 static int das800_di_rbits(struct comedi_device *dev,
868                            struct comedi_subdevice *s, struct comedi_insn *insn,
869                            unsigned int *data)
870 {
871         unsigned int bits;
872
873         bits = inb(dev->iobase + DAS800_STATUS) >> 4;
874         bits &= 0x7;
875         data[1] = bits;
876         data[0] = 0;
877
878         return 2;
879 }
880
881 static int das800_do_wbits(struct comedi_device *dev,
882                            struct comedi_subdevice *s, struct comedi_insn *insn,
883                            unsigned int *data)
884 {
885         int wbits;
886         unsigned long irq_flags;
887
888         /*  only set bits that have been masked */
889         data[0] &= 0xf;
890         wbits = devpriv->do_bits >> 4;
891         wbits &= ~data[0];
892         wbits |= data[0] & data[1];
893         devpriv->do_bits = wbits << 4;
894
895         spin_lock_irqsave(&dev->spinlock, irq_flags);
896         outb(CONTROL1, dev->iobase + DAS800_GAIN);      /* select dev->iobase + 2 to be control register 1 */
897         outb(devpriv->do_bits | CONTROL1_INTE, dev->iobase + DAS800_CONTROL1);
898         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
899
900         data[1] = wbits;
901
902         return 2;
903 }
904
905 /* loads counters with divisor1, divisor2 from private structure */
906 static int das800_set_frequency(struct comedi_device *dev)
907 {
908         int err = 0;
909
910         if (i8254_load(dev->iobase + DAS800_8254, 0, 1, devpriv->divisor1, 2))
911                 err++;
912         if (i8254_load(dev->iobase + DAS800_8254, 0, 2, devpriv->divisor2, 2))
913                 err++;
914         if (err)
915                 return -1;
916
917         return 0;
918 }
919
920 MODULE_AUTHOR("Comedi http://www.comedi.org");
921 MODULE_DESCRIPTION("Comedi low-level driver");
922 MODULE_LICENSE("GPL");