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