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