]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/comedi/drivers/das800.c
Merge branch 'for-4.8/core' of git://git.kernel.dk/linux-block
[karo-tx-linux.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 /*
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 int val, unsigned int 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 int das800_ind_read(struct comedi_device *dev, unsigned int 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 *board = 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 (board->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 *board = 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                                                     board->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 *board = 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 (board->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 const struct das800_board *das800_probe(struct comedi_device *dev)
608 {
609         const struct das800_board *board = dev->board_ptr;
610         int index = board ? board - das800_boards : -EINVAL;
611         int id_bits;
612         unsigned long irq_flags;
613
614         /*
615          * The dev->board_ptr will be set by comedi_device_attach() if the
616          * board name provided by the user matches a board->name in this
617          * driver. If so, this function sanity checks the id_bits to verify
618          * that the board is correct.
619          *
620          * If the dev->board_ptr is not set, the user is trying to attach
621          * an unspecified board to this driver. In this case the id_bits
622          * are used to 'probe' for the correct dev->board_ptr.
623          */
624         spin_lock_irqsave(&dev->spinlock, irq_flags);
625         id_bits = das800_ind_read(dev, ID) & 0x3;
626         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
627
628         switch (id_bits) {
629         case 0x0:
630                 if (index == BOARD_DAS800 || index == BOARD_CIODAS800)
631                         return board;
632                 index = BOARD_DAS800;
633                 break;
634         case 0x2:
635                 if (index == BOARD_DAS801 || index == BOARD_CIODAS801)
636                         return board;
637                 index = BOARD_DAS801;
638                 break;
639         case 0x3:
640                 if (index == BOARD_DAS802 || index == BOARD_CIODAS802 ||
641                     index == BOARD_CIODAS80216)
642                         return board;
643                 index = BOARD_DAS802;
644                 break;
645         default:
646                 dev_dbg(dev->class_dev, "Board model: 0x%x (unknown)\n",
647                         id_bits);
648                 return NULL;
649         }
650         dev_dbg(dev->class_dev, "Board model (probed): %s series\n",
651                 das800_boards[index].name);
652
653         return &das800_boards[index];
654 }
655
656 static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
657 {
658         const struct das800_board *board;
659         struct das800_private *devpriv;
660         struct comedi_subdevice *s;
661         unsigned int irq = it->options[1];
662         unsigned long irq_flags;
663         int ret;
664
665         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
666         if (!devpriv)
667                 return -ENOMEM;
668
669         ret = comedi_request_region(dev, it->options[0], 0x8);
670         if (ret)
671                 return ret;
672
673         board = das800_probe(dev);
674         if (!board)
675                 return -ENODEV;
676         dev->board_ptr = board;
677         dev->board_name = board->name;
678
679         if (irq > 1 && irq <= 7) {
680                 ret = request_irq(irq, das800_interrupt, 0, dev->board_name,
681                                   dev);
682                 if (ret == 0)
683                         dev->irq = irq;
684         }
685
686         dev->pacer = comedi_8254_init(dev->iobase + DAS800_8254,
687                                       I8254_OSC_BASE_1MHZ, I8254_IO8, 0);
688         if (!dev->pacer)
689                 return -ENOMEM;
690
691         ret = comedi_alloc_subdevices(dev, 3);
692         if (ret)
693                 return ret;
694
695         /* Analog Input subdevice */
696         s = &dev->subdevices[0];
697         dev->read_subdev = s;
698         s->type         = COMEDI_SUBD_AI;
699         s->subdev_flags = SDF_READABLE | SDF_GROUND;
700         s->n_chan       = 8;
701         s->maxdata      = (1 << board->resolution) - 1;
702         s->range_table  = board->ai_range;
703         s->insn_read    = das800_ai_insn_read;
704         if (dev->irq) {
705                 s->subdev_flags |= SDF_CMD_READ;
706                 s->len_chanlist = 8;
707                 s->do_cmdtest   = das800_ai_do_cmdtest;
708                 s->do_cmd       = das800_ai_do_cmd;
709                 s->cancel       = das800_cancel;
710         }
711
712         /* Digital Input subdevice */
713         s = &dev->subdevices[1];
714         s->type         = COMEDI_SUBD_DI;
715         s->subdev_flags = SDF_READABLE;
716         s->n_chan       = 3;
717         s->maxdata      = 1;
718         s->range_table  = &range_digital;
719         s->insn_bits    = das800_di_insn_bits;
720
721         /* Digital Output subdevice */
722         s = &dev->subdevices[2];
723         s->type         = COMEDI_SUBD_DO;
724         s->subdev_flags = SDF_WRITABLE;
725         s->n_chan       = 4;
726         s->maxdata      = 1;
727         s->range_table  = &range_digital;
728         s->insn_bits    = das800_do_insn_bits;
729
730         das800_disable(dev);
731
732         /* initialize digital out channels */
733         spin_lock_irqsave(&dev->spinlock, irq_flags);
734         das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1);
735         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
736
737         return 0;
738 };
739
740 static struct comedi_driver driver_das800 = {
741         .driver_name    = "das800",
742         .module         = THIS_MODULE,
743         .attach         = das800_attach,
744         .detach         = comedi_legacy_detach,
745         .num_names      = ARRAY_SIZE(das800_boards),
746         .board_name     = &das800_boards[0].name,
747         .offset         = sizeof(struct das800_board),
748 };
749 module_comedi_driver(driver_das800);
750
751 MODULE_AUTHOR("Comedi http://www.comedi.org");
752 MODULE_DESCRIPTION("Comedi low-level driver");
753 MODULE_LICENSE("GPL");