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