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