Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / 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 /*
20 Driver: das800
21 Description: Keithley Metrabyte DAS800 (& compatibles)
22 Author: Frank Mori Hess <fmhess@users.sourceforge.net>
23 Devices: [Keithley Metrabyte] DAS-800 (das-800), DAS-801 (das-801),
24   DAS-802 (das-802),
25   [Measurement Computing] CIO-DAS800 (cio-das800),
26   CIO-DAS801 (cio-das801), CIO-DAS802 (cio-das802),
27   CIO-DAS802/16 (cio-das802/16)
28 Status: works, cio-das802/16 untested - email me if you have tested it
29
30 Configuration options:
31   [0] - I/O port base address
32   [1] - IRQ (optional, required for timed or externally triggered conversions)
33
34 Notes:
35         IRQ can be omitted, although the cmd interface will not work without it.
36
37         All entries in the channel/gain list must use the same gain and be
38         consecutive channels counting upwards in channel number (these are
39         hardware limitations.)
40
41         I've never tested the gain setting stuff since I only have a
42         DAS-800 board with fixed gain.
43
44         The cio-das802/16 does not have a fifo-empty status bit!  Therefore
45         only fifo-half-full transfers are possible with this card.
46
47 cmd triggers supported:
48         start_src:      TRIG_NOW | TRIG_EXT
49         scan_begin_src: TRIG_FOLLOW
50         scan_end_src:   TRIG_COUNT
51         convert_src:    TRIG_TIMER | TRIG_EXT
52         stop_src:       TRIG_NONE | TRIG_COUNT
53 */
54
55 #include <linux/module.h>
56 #include <linux/interrupt.h>
57 #include <linux/delay.h>
58
59 #include "../comedidev.h"
60
61 #include "comedi_8254.h"
62
63 #define N_CHAN_AI             8 /*  number of analog input channels */
64
65 /* Registers for the das800 */
66
67 #define DAS800_LSB            0
68 #define   FIFO_EMPTY            0x1
69 #define   FIFO_OVF              0x2
70 #define DAS800_MSB            1
71 #define DAS800_CONTROL1       2
72 #define   CONTROL1_INTE         0x8
73 #define DAS800_CONV_CONTROL   2
74 #define   ITE                   0x1
75 #define   CASC                  0x2
76 #define   DTEN                  0x4
77 #define   IEOC                  0x8
78 #define   EACS                  0x10
79 #define   CONV_HCEN             0x80
80 #define DAS800_SCAN_LIMITS    2
81 #define DAS800_STATUS         2
82 #define   IRQ                   0x8
83 #define   BUSY                  0x80
84 #define DAS800_GAIN           3
85 #define   CIO_FFOV              0x8   /* cio-das802/16 fifo overflow */
86 #define   CIO_ENHF              0x90  /* cio-das802/16 fifo half full int ena */
87 #define   CONTROL1              0x80
88 #define   CONV_CONTROL          0xa0
89 #define   SCAN_LIMITS           0xc0
90 #define   ID                    0xe0
91 #define DAS800_8254           4
92 #define DAS800_STATUS2        7
93 #define   STATUS2_HCEN          0x80
94 #define   STATUS2_INTE          0X20
95 #define DAS800_ID             7
96
97 #define DAS802_16_HALF_FIFO_SZ  128
98
99 struct das800_board {
100         const char *name;
101         int ai_speed;
102         const struct comedi_lrange *ai_range;
103         int resolution;
104 };
105
106 static const struct comedi_lrange range_das801_ai = {
107         9, {
108                 BIP_RANGE(5),
109                 BIP_RANGE(10),
110                 UNI_RANGE(10),
111                 BIP_RANGE(0.5),
112                 UNI_RANGE(1),
113                 BIP_RANGE(0.05),
114                 UNI_RANGE(0.1),
115                 BIP_RANGE(0.01),
116                 UNI_RANGE(0.02)
117         }
118 };
119
120 static const struct comedi_lrange range_cio_das801_ai = {
121         9, {
122                 BIP_RANGE(5),
123                 BIP_RANGE(10),
124                 UNI_RANGE(10),
125                 BIP_RANGE(0.5),
126                 UNI_RANGE(1),
127                 BIP_RANGE(0.05),
128                 UNI_RANGE(0.1),
129                 BIP_RANGE(0.005),
130                 UNI_RANGE(0.01)
131         }
132 };
133
134 static const struct comedi_lrange range_das802_ai = {
135         9, {
136                 BIP_RANGE(5),
137                 BIP_RANGE(10),
138                 UNI_RANGE(10),
139                 BIP_RANGE(2.5),
140                 UNI_RANGE(5),
141                 BIP_RANGE(1.25),
142                 UNI_RANGE(2.5),
143                 BIP_RANGE(0.625),
144                 UNI_RANGE(1.25)
145         }
146 };
147
148 static const struct comedi_lrange range_das80216_ai = {
149         8, {
150                 BIP_RANGE(10),
151                 UNI_RANGE(10),
152                 BIP_RANGE(5),
153                 UNI_RANGE(5),
154                 BIP_RANGE(2.5),
155                 UNI_RANGE(2.5),
156                 BIP_RANGE(1.25),
157                 UNI_RANGE(1.25)
158         }
159 };
160
161 enum das800_boardinfo {
162         BOARD_DAS800,
163         BOARD_CIODAS800,
164         BOARD_DAS801,
165         BOARD_CIODAS801,
166         BOARD_DAS802,
167         BOARD_CIODAS802,
168         BOARD_CIODAS80216,
169 };
170
171 static const struct das800_board das800_boards[] = {
172         [BOARD_DAS800] = {
173                 .name           = "das-800",
174                 .ai_speed       = 25000,
175                 .ai_range       = &range_bipolar5,
176                 .resolution     = 12,
177         },
178         [BOARD_CIODAS800] = {
179                 .name           = "cio-das800",
180                 .ai_speed       = 20000,
181                 .ai_range       = &range_bipolar5,
182                 .resolution     = 12,
183         },
184         [BOARD_DAS801] = {
185                 .name           = "das-801",
186                 .ai_speed       = 25000,
187                 .ai_range       = &range_das801_ai,
188                 .resolution     = 12,
189         },
190         [BOARD_CIODAS801] = {
191                 .name           = "cio-das801",
192                 .ai_speed       = 20000,
193                 .ai_range       = &range_cio_das801_ai,
194                 .resolution     = 12,
195         },
196         [BOARD_DAS802] = {
197                 .name           = "das-802",
198                 .ai_speed       = 25000,
199                 .ai_range       = &range_das802_ai,
200                 .resolution     = 12,
201         },
202         [BOARD_CIODAS802] = {
203                 .name           = "cio-das802",
204                 .ai_speed       = 20000,
205                 .ai_range       = &range_das802_ai,
206                 .resolution     = 12,
207         },
208         [BOARD_CIODAS80216] = {
209                 .name           = "cio-das802/16",
210                 .ai_speed       = 10000,
211                 .ai_range       = &range_das80216_ai,
212                 .resolution     = 16,
213         },
214 };
215
216 struct das800_private {
217         unsigned int do_bits;   /* digital output bits */
218 };
219
220 static void das800_ind_write(struct comedi_device *dev,
221                              unsigned val, unsigned reg)
222 {
223         /*
224          * Select dev->iobase + 2 to be desired register
225          * then write to that register.
226          */
227         outb(reg, dev->iobase + DAS800_GAIN);
228         outb(val, dev->iobase + 2);
229 }
230
231 static unsigned das800_ind_read(struct comedi_device *dev, unsigned reg)
232 {
233         /*
234          * Select dev->iobase + 7 to be desired register
235          * then read from that register.
236          */
237         outb(reg, dev->iobase + DAS800_GAIN);
238         return inb(dev->iobase + 7);
239 }
240
241 static void das800_enable(struct comedi_device *dev)
242 {
243         const struct das800_board *thisboard = dev->board_ptr;
244         struct das800_private *devpriv = dev->private;
245         unsigned long irq_flags;
246
247         spin_lock_irqsave(&dev->spinlock, irq_flags);
248         /*  enable fifo-half full interrupts for cio-das802/16 */
249         if (thisboard->resolution == 16)
250                 outb(CIO_ENHF, dev->iobase + DAS800_GAIN);
251         /* enable hardware triggering */
252         das800_ind_write(dev, CONV_HCEN, CONV_CONTROL);
253         /* enable card's interrupt */
254         das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1);
255         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
256 }
257
258 static void das800_disable(struct comedi_device *dev)
259 {
260         unsigned long irq_flags;
261
262         spin_lock_irqsave(&dev->spinlock, irq_flags);
263         /* disable hardware triggering of conversions */
264         das800_ind_write(dev, 0x0, CONV_CONTROL);
265         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
266 }
267
268 static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
269 {
270         das800_disable(dev);
271         return 0;
272 }
273
274 static int das800_ai_check_chanlist(struct comedi_device *dev,
275                                     struct comedi_subdevice *s,
276                                     struct comedi_cmd *cmd)
277 {
278         unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
279         unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
280         int i;
281
282         for (i = 1; i < cmd->chanlist_len; i++) {
283                 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
284                 unsigned int range = CR_RANGE(cmd->chanlist[i]);
285
286                 if (chan != (chan0 + i) % s->n_chan) {
287                         dev_dbg(dev->class_dev,
288                                 "chanlist must be consecutive, counting upwards\n");
289                         return -EINVAL;
290                 }
291
292                 if (range != range0) {
293                         dev_dbg(dev->class_dev,
294                                 "chanlist must all have the same gain\n");
295                         return -EINVAL;
296                 }
297         }
298
299         return 0;
300 }
301
302 static int das800_ai_do_cmdtest(struct comedi_device *dev,
303                                 struct comedi_subdevice *s,
304                                 struct comedi_cmd *cmd)
305 {
306         const struct das800_board *thisboard = dev->board_ptr;
307         int err = 0;
308
309         /* Step 1 : check if triggers are trivially valid */
310
311         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
312         err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
313         err |= comedi_check_trigger_src(&cmd->convert_src,
314                                         TRIG_TIMER | TRIG_EXT);
315         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
316         err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
317
318         if (err)
319                 return 1;
320
321         /* Step 2a : make sure trigger sources are unique */
322
323         err |= comedi_check_trigger_is_unique(cmd->start_src);
324         err |= comedi_check_trigger_is_unique(cmd->convert_src);
325         err |= comedi_check_trigger_is_unique(cmd->stop_src);
326
327         /* Step 2b : and mutually compatible */
328
329         if (err)
330                 return 2;
331
332         /* Step 3: check if arguments are trivially valid */
333
334         err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
335
336         if (cmd->convert_src == TRIG_TIMER) {
337                 err |= comedi_check_trigger_arg_min(&cmd->convert_arg,
338                                                     thisboard->ai_speed);
339         }
340
341         err |= comedi_check_trigger_arg_min(&cmd->chanlist_len, 1);
342         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
343                                            cmd->chanlist_len);
344
345         if (cmd->stop_src == TRIG_COUNT)
346                 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
347         else    /* TRIG_NONE */
348                 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
349
350         if (err)
351                 return 3;
352
353         /* step 4: fix up any arguments */
354
355         if (cmd->convert_src == TRIG_TIMER) {
356                 unsigned int arg = cmd->convert_arg;
357
358                 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
359                 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
360         }
361
362         if (err)
363                 return 4;
364
365         /* Step 5: check channel list if it exists */
366         if (cmd->chanlist && cmd->chanlist_len > 0)
367                 err |= das800_ai_check_chanlist(dev, s, cmd);
368
369         if (err)
370                 return 5;
371
372         return 0;
373 }
374
375 static int das800_ai_do_cmd(struct comedi_device *dev,
376                             struct comedi_subdevice *s)
377 {
378         const struct das800_board *thisboard = dev->board_ptr;
379         struct comedi_async *async = s->async;
380         struct comedi_cmd *cmd = &async->cmd;
381         unsigned int gain = CR_RANGE(cmd->chanlist[0]);
382         unsigned int start_chan = CR_CHAN(cmd->chanlist[0]);
383         unsigned int end_chan = (start_chan + cmd->chanlist_len - 1) % 8;
384         unsigned int scan_chans = (end_chan << 3) | start_chan;
385         int conv_bits;
386         unsigned long irq_flags;
387
388         das800_disable(dev);
389
390         spin_lock_irqsave(&dev->spinlock, irq_flags);
391         /* set scan limits */
392         das800_ind_write(dev, scan_chans, SCAN_LIMITS);
393         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
394
395         /* set gain */
396         if (thisboard->resolution == 12 && gain > 0)
397                 gain += 0x7;
398         gain &= 0xf;
399         outb(gain, dev->iobase + DAS800_GAIN);
400
401         /* enable auto channel scan, send interrupts on end of conversion
402          * and set clock source to internal or external
403          */
404         conv_bits = 0;
405         conv_bits |= EACS | IEOC;
406         if (cmd->start_src == TRIG_EXT)
407                 conv_bits |= DTEN;
408         if (cmd->convert_src == TRIG_TIMER) {
409                 conv_bits |= CASC | ITE;
410                 comedi_8254_update_divisors(dev->pacer);
411                 comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
412         }
413
414         spin_lock_irqsave(&dev->spinlock, irq_flags);
415         das800_ind_write(dev, conv_bits, CONV_CONTROL);
416         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
417
418         das800_enable(dev);
419         return 0;
420 }
421
422 static unsigned int das800_ai_get_sample(struct comedi_device *dev)
423 {
424         unsigned int lsb = inb(dev->iobase + DAS800_LSB);
425         unsigned int msb = inb(dev->iobase + DAS800_MSB);
426
427         return (msb << 8) | lsb;
428 }
429
430 static irqreturn_t das800_interrupt(int irq, void *d)
431 {
432         struct comedi_device *dev = d;
433         struct das800_private *devpriv = dev->private;
434         struct comedi_subdevice *s = dev->read_subdev;
435         struct comedi_async *async;
436         struct comedi_cmd *cmd;
437         unsigned long irq_flags;
438         unsigned int status;
439         unsigned int val;
440         bool fifo_empty;
441         bool fifo_overflow;
442         int i;
443
444         status = inb(dev->iobase + DAS800_STATUS);
445         if (!(status & IRQ))
446                 return IRQ_NONE;
447         if (!dev->attached)
448                 return IRQ_HANDLED;
449
450         async = s->async;
451         cmd = &async->cmd;
452
453         spin_lock_irqsave(&dev->spinlock, irq_flags);
454         status = das800_ind_read(dev, CONTROL1) & STATUS2_HCEN;
455         /*
456          * Don't release spinlock yet since we want to make sure
457          * no one else disables hardware conversions.
458          */
459
460         /* if hardware conversions are not enabled, then quit */
461         if (status == 0) {
462                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
463                 return IRQ_HANDLED;
464         }
465
466         for (i = 0; i < DAS802_16_HALF_FIFO_SZ; i++) {
467                 val = das800_ai_get_sample(dev);
468                 if (s->maxdata == 0x0fff) {
469                         fifo_empty = !!(val & FIFO_EMPTY);
470                         fifo_overflow = !!(val & FIFO_OVF);
471                 } else {
472                         /* cio-das802/16 has no fifo empty status bit */
473                         fifo_empty = false;
474                         fifo_overflow = !!(inb(dev->iobase + DAS800_GAIN) &
475                                                 CIO_FFOV);
476                 }
477                 if (fifo_empty || fifo_overflow)
478                         break;
479
480                 if (s->maxdata == 0x0fff)
481                         val >>= 4;      /* 12-bit sample */
482
483                 val &= s->maxdata;
484                 comedi_buf_write_samples(s, &val, 1);
485
486                 if (cmd->stop_src == TRIG_COUNT &&
487                     async->scans_done >= cmd->stop_arg) {
488                         async->events |= COMEDI_CB_EOA;
489                         break;
490                 }
491         }
492
493         if (fifo_overflow) {
494                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
495                 async->events |= COMEDI_CB_ERROR;
496                 comedi_handle_events(dev, s);
497                 return IRQ_HANDLED;
498         }
499
500         if (!(async->events & COMEDI_CB_CANCEL_MASK)) {
501                 /*
502                  * Re-enable card's interrupt.
503                  * We already have spinlock, so indirect addressing is safe
504                  */
505                 das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits,
506                                  CONTROL1);
507                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
508         } else {
509                 /* otherwise, stop taking data */
510                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
511                 das800_disable(dev);
512         }
513         comedi_handle_events(dev, s);
514         return IRQ_HANDLED;
515 }
516
517 static int das800_ai_eoc(struct comedi_device *dev,
518                          struct comedi_subdevice *s,
519                          struct comedi_insn *insn,
520                          unsigned long context)
521 {
522         unsigned int status;
523
524         status = inb(dev->iobase + DAS800_STATUS);
525         if ((status & BUSY) == 0)
526                 return 0;
527         return -EBUSY;
528 }
529
530 static int das800_ai_insn_read(struct comedi_device *dev,
531                                struct comedi_subdevice *s,
532                                struct comedi_insn *insn,
533                                unsigned int *data)
534 {
535         struct das800_private *devpriv = dev->private;
536         unsigned int chan = CR_CHAN(insn->chanspec);
537         unsigned int range = CR_RANGE(insn->chanspec);
538         unsigned long irq_flags;
539         unsigned int val;
540         int ret;
541         int i;
542
543         das800_disable(dev);
544
545         /* set multiplexer */
546         spin_lock_irqsave(&dev->spinlock, irq_flags);
547         das800_ind_write(dev, chan | devpriv->do_bits, CONTROL1);
548         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
549
550         /* set gain / range */
551         if (s->maxdata == 0x0fff && range)
552                 range += 0x7;
553         range &= 0xf;
554         outb(range, dev->iobase + DAS800_GAIN);
555
556         udelay(5);
557
558         for (i = 0; i < insn->n; i++) {
559                 /* trigger conversion */
560                 outb_p(0, dev->iobase + DAS800_MSB);
561
562                 ret = comedi_timeout(dev, s, insn, das800_ai_eoc, 0);
563                 if (ret)
564                         return ret;
565
566                 val = das800_ai_get_sample(dev);
567                 if (s->maxdata == 0x0fff)
568                         val >>= 4;      /* 12-bit sample */
569                 data[i] = val & s->maxdata;
570         }
571
572         return insn->n;
573 }
574
575 static int das800_di_insn_bits(struct comedi_device *dev,
576                                struct comedi_subdevice *s,
577                                struct comedi_insn *insn,
578                                unsigned int *data)
579 {
580         data[1] = (inb(dev->iobase + DAS800_STATUS) >> 4) & 0x7;
581
582         return insn->n;
583 }
584
585 static int das800_do_insn_bits(struct comedi_device *dev,
586                                struct comedi_subdevice *s,
587                                struct comedi_insn *insn,
588                                unsigned int *data)
589 {
590         struct das800_private *devpriv = dev->private;
591         unsigned long irq_flags;
592
593         if (comedi_dio_update_state(s, data)) {
594                 devpriv->do_bits = s->state << 4;
595
596                 spin_lock_irqsave(&dev->spinlock, irq_flags);
597                 das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits,
598                                  CONTROL1);
599                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
600         }
601
602         data[1] = s->state;
603
604         return insn->n;
605 }
606
607 static int das800_probe(struct comedi_device *dev)
608 {
609         const struct das800_board *thisboard = dev->board_ptr;
610         int board = thisboard ? thisboard - das800_boards : -EINVAL;
611         int id_bits;
612         unsigned long irq_flags;
613
614         spin_lock_irqsave(&dev->spinlock, irq_flags);
615         id_bits = das800_ind_read(dev, ID) & 0x3;
616         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
617
618         switch (id_bits) {
619         case 0x0:
620                 if (board == BOARD_DAS800 || board == BOARD_CIODAS800)
621                         break;
622                 dev_dbg(dev->class_dev, "Board model (probed): DAS-800\n");
623                 board = BOARD_DAS800;
624                 break;
625         case 0x2:
626                 if (board == BOARD_DAS801 || board == BOARD_CIODAS801)
627                         break;
628                 dev_dbg(dev->class_dev, "Board model (probed): DAS-801\n");
629                 board = BOARD_DAS801;
630                 break;
631         case 0x3:
632                 if (board == BOARD_DAS802 || board == BOARD_CIODAS802 ||
633                     board == BOARD_CIODAS80216)
634                         break;
635                 dev_dbg(dev->class_dev, "Board model (probed): DAS-802\n");
636                 board = BOARD_DAS802;
637                 break;
638         default:
639                 dev_dbg(dev->class_dev, "Board model: 0x%x (unknown)\n",
640                         id_bits);
641                 board = -EINVAL;
642                 break;
643         }
644         return board;
645 }
646
647 static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
648 {
649         const struct das800_board *thisboard;
650         struct das800_private *devpriv;
651         struct comedi_subdevice *s;
652         unsigned int irq = it->options[1];
653         unsigned long irq_flags;
654         int board;
655         int ret;
656
657         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
658         if (!devpriv)
659                 return -ENOMEM;
660
661         ret = comedi_request_region(dev, it->options[0], 0x8);
662         if (ret)
663                 return ret;
664
665         board = das800_probe(dev);
666         if (board < 0) {
667                 dev_dbg(dev->class_dev, "unable to determine board type\n");
668                 return -ENODEV;
669         }
670         dev->board_ptr = das800_boards + board;
671         thisboard = dev->board_ptr;
672         dev->board_name = thisboard->name;
673
674         if (irq > 1 && irq <= 7) {
675                 ret = request_irq(irq, das800_interrupt, 0, dev->board_name,
676                                   dev);
677                 if (ret == 0)
678                         dev->irq = irq;
679         }
680
681         dev->pacer = comedi_8254_init(dev->iobase + DAS800_8254,
682                                       I8254_OSC_BASE_1MHZ, I8254_IO8, 0);
683         if (!dev->pacer)
684                 return -ENOMEM;
685
686         ret = comedi_alloc_subdevices(dev, 3);
687         if (ret)
688                 return ret;
689
690         /* Analog Input subdevice */
691         s = &dev->subdevices[0];
692         dev->read_subdev = s;
693         s->type         = COMEDI_SUBD_AI;
694         s->subdev_flags = SDF_READABLE | SDF_GROUND;
695         s->n_chan       = 8;
696         s->maxdata      = (1 << thisboard->resolution) - 1;
697         s->range_table  = thisboard->ai_range;
698         s->insn_read    = das800_ai_insn_read;
699         if (dev->irq) {
700                 s->subdev_flags |= SDF_CMD_READ;
701                 s->len_chanlist = 8;
702                 s->do_cmdtest   = das800_ai_do_cmdtest;
703                 s->do_cmd       = das800_ai_do_cmd;
704                 s->cancel       = das800_cancel;
705         }
706
707         /* Digital Input subdevice */
708         s = &dev->subdevices[1];
709         s->type         = COMEDI_SUBD_DI;
710         s->subdev_flags = SDF_READABLE;
711         s->n_chan       = 3;
712         s->maxdata      = 1;
713         s->range_table  = &range_digital;
714         s->insn_bits    = das800_di_insn_bits;
715
716         /* Digital Output subdevice */
717         s = &dev->subdevices[2];
718         s->type         = COMEDI_SUBD_DO;
719         s->subdev_flags = SDF_WRITABLE;
720         s->n_chan       = 4;
721         s->maxdata      = 1;
722         s->range_table  = &range_digital;
723         s->insn_bits    = das800_do_insn_bits;
724
725         das800_disable(dev);
726
727         /* initialize digital out channels */
728         spin_lock_irqsave(&dev->spinlock, irq_flags);
729         das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1);
730         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
731
732         return 0;
733 };
734
735 static struct comedi_driver driver_das800 = {
736         .driver_name    = "das800",
737         .module         = THIS_MODULE,
738         .attach         = das800_attach,
739         .detach         = comedi_legacy_detach,
740         .num_names      = ARRAY_SIZE(das800_boards),
741         .board_name     = &das800_boards[0].name,
742         .offset         = sizeof(struct das800_board),
743 };
744 module_comedi_driver(driver_das800);
745
746 MODULE_AUTHOR("Comedi http://www.comedi.org");
747 MODULE_DESCRIPTION("Comedi low-level driver");
748 MODULE_LICENSE("GPL");