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