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