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