staging: comedi: das800: cleanup range table declarations
[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, ciodas800, das801, ciodas801, das802, ciodas802, ciodas80216 };
173
174 static const struct das800_board das800_boards[] = {
175         {
176          .name = "das-800",
177          .ai_speed = 25000,
178          .ai_range = &range_bipolar5,
179          .resolution = 12,
180          },
181         {
182          .name = "cio-das800",
183          .ai_speed = 20000,
184          .ai_range = &range_bipolar5,
185          .resolution = 12,
186          },
187         {
188          .name = "das-801",
189          .ai_speed = 25000,
190          .ai_range = &range_das801_ai,
191          .resolution = 12,
192          },
193         {
194          .name = "cio-das801",
195          .ai_speed = 20000,
196          .ai_range = &range_cio_das801_ai,
197          .resolution = 12,
198          },
199         {
200          .name = "das-802",
201          .ai_speed = 25000,
202          .ai_range = &range_das802_ai,
203          .resolution = 12,
204          },
205         {
206          .name = "cio-das802",
207          .ai_speed = 20000,
208          .ai_range = &range_das802_ai,
209          .resolution = 12,
210          },
211         {
212          .name = "cio-das802/16",
213          .ai_speed = 10000,
214          .ai_range = &range_das80216_ai,
215          .resolution = 16,
216          },
217 };
218
219 struct das800_private {
220         volatile unsigned int count;    /* number of data points left to be taken */
221         volatile int forever;   /* flag indicating whether we should take data forever */
222         unsigned int divisor1;  /* value to load into board's counter 1 for timed conversions */
223         unsigned int divisor2;  /* value to load into board's counter 2 for timed conversions */
224         volatile int do_bits;   /* digital output bits */
225 };
226
227 static void das800_ind_write(struct comedi_device *dev,
228                              unsigned val, unsigned reg)
229 {
230         /*
231          * Select dev->iobase + 2 to be desired register
232          * then write to that register.
233          */
234         outb(reg, dev->iobase + DAS800_GAIN);
235         outb(val, dev->iobase + 2);
236 }
237
238 static unsigned das800_ind_read(struct comedi_device *dev, unsigned reg)
239 {
240         /*
241          * Select dev->iobase + 7 to be desired register
242          * then read from that register.
243          */
244         outb(reg, dev->iobase + DAS800_GAIN);
245         return inb(dev->iobase + 7);
246 }
247
248 /* enable_das800 makes the card start taking hardware triggered conversions */
249 static void enable_das800(struct comedi_device *dev)
250 {
251         const struct das800_board *thisboard = comedi_board(dev);
252         struct das800_private *devpriv = dev->private;
253         unsigned long irq_flags;
254
255         spin_lock_irqsave(&dev->spinlock, irq_flags);
256         /*  enable fifo-half full interrupts for cio-das802/16 */
257         if (thisboard->resolution == 16)
258                 outb(CIO_ENHF, dev->iobase + DAS800_GAIN);
259         /* enable hardware triggering */
260         das800_ind_write(dev, CONV_HCEN, CONV_CONTROL);
261         /* enable card's interrupt */
262         das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1);
263         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
264 }
265
266 /* disable_das800 stops hardware triggered conversions */
267 static void disable_das800(struct comedi_device *dev)
268 {
269         unsigned long irq_flags;
270
271         spin_lock_irqsave(&dev->spinlock, irq_flags);
272         /* disable hardware triggering of conversions */
273         das800_ind_write(dev, 0x0, CONV_CONTROL);
274         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
275 }
276
277 static int das800_set_frequency(struct comedi_device *dev)
278 {
279         struct das800_private *devpriv = dev->private;
280         int err = 0;
281
282         if (i8254_load(dev->iobase + DAS800_8254, 0, 1, devpriv->divisor1, 2))
283                 err++;
284         if (i8254_load(dev->iobase + DAS800_8254, 0, 2, devpriv->divisor2, 2))
285                 err++;
286         if (err)
287                 return -1;
288
289         return 0;
290 }
291
292 static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
293 {
294         struct das800_private *devpriv = dev->private;
295
296         devpriv->forever = 0;
297         devpriv->count = 0;
298         disable_das800(dev);
299         return 0;
300 }
301
302 static int das800_ai_do_cmdtest(struct comedi_device *dev,
303                                 struct comedi_subdevice *s,
304                                 struct comedi_cmd *cmd)
305 {
306         const struct das800_board *thisboard = comedi_board(dev);
307         struct das800_private *devpriv = dev->private;
308         int err = 0;
309         int tmp;
310         int gain, startChan;
311         int i;
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                 tmp = cmd->convert_arg;
358                 /* calculate counter values that give desired timing */
359                 i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
360                                                &(devpriv->divisor2),
361                                                &(cmd->convert_arg),
362                                                cmd->flags & TRIG_ROUND_MASK);
363                 if (tmp != cmd->convert_arg)
364                         err++;
365         }
366
367         if (err)
368                 return 4;
369
370         /*  check channel/gain list against card's limitations */
371         if (cmd->chanlist) {
372                 gain = CR_RANGE(cmd->chanlist[0]);
373                 startChan = CR_CHAN(cmd->chanlist[0]);
374                 for (i = 1; i < cmd->chanlist_len; i++) {
375                         if (CR_CHAN(cmd->chanlist[i]) !=
376                             (startChan + i) % N_CHAN_AI) {
377                                 comedi_error(dev,
378                                              "entries in chanlist must be consecutive channels, counting upwards\n");
379                                 err++;
380                         }
381                         if (CR_RANGE(cmd->chanlist[i]) != gain) {
382                                 comedi_error(dev,
383                                              "entries in chanlist must all have the same gain\n");
384                                 err++;
385                         }
386                 }
387         }
388
389         if (err)
390                 return 5;
391
392         return 0;
393 }
394
395 static int das800_ai_do_cmd(struct comedi_device *dev,
396                             struct comedi_subdevice *s)
397 {
398         const struct das800_board *thisboard = comedi_board(dev);
399         struct das800_private *devpriv = dev->private;
400         int startChan, endChan, scan, gain;
401         int conv_bits;
402         unsigned long irq_flags;
403         struct comedi_async *async = s->async;
404
405         if (!dev->irq) {
406                 comedi_error(dev,
407                              "no irq assigned for das-800, cannot do hardware conversions");
408                 return -1;
409         }
410
411         disable_das800(dev);
412
413         /* set channel scan limits */
414         startChan = CR_CHAN(async->cmd.chanlist[0]);
415         endChan = (startChan + async->cmd.chanlist_len - 1) % 8;
416         scan = (endChan << 3) | startChan;
417
418         spin_lock_irqsave(&dev->spinlock, irq_flags);
419         /* set scan limits */
420         das800_ind_write(dev, scan, SCAN_LIMITS);
421         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
422
423         /* set gain */
424         gain = CR_RANGE(async->cmd.chanlist[0]);
425         if (thisboard->resolution == 12 && gain > 0)
426                 gain += 0x7;
427         gain &= 0xf;
428         outb(gain, dev->iobase + DAS800_GAIN);
429
430         switch (async->cmd.stop_src) {
431         case TRIG_COUNT:
432                 devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len;
433                 devpriv->forever = 0;
434                 break;
435         case TRIG_NONE:
436                 devpriv->forever = 1;
437                 devpriv->count = 0;
438                 break;
439         default:
440                 break;
441         }
442
443         /* enable auto channel scan, send interrupts on end of conversion
444          * and set clock source to internal or external
445          */
446         conv_bits = 0;
447         conv_bits |= EACS | IEOC;
448         if (async->cmd.start_src == TRIG_EXT)
449                 conv_bits |= DTEN;
450         switch (async->cmd.convert_src) {
451         case TRIG_TIMER:
452                 conv_bits |= CASC | ITE;
453                 /* set conversion frequency */
454                 i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
455                                                &(devpriv->divisor2),
456                                                &(async->cmd.convert_arg),
457                                                async->cmd.
458                                                flags & TRIG_ROUND_MASK);
459                 if (das800_set_frequency(dev) < 0) {
460                         comedi_error(dev, "Error setting up counters");
461                         return -1;
462                 }
463                 break;
464         case TRIG_EXT:
465                 break;
466         default:
467                 break;
468         }
469
470         spin_lock_irqsave(&dev->spinlock, irq_flags);
471         das800_ind_write(dev, conv_bits, CONV_CONTROL);
472         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
473
474         async->events = 0;
475         enable_das800(dev);
476         return 0;
477 }
478
479 static irqreturn_t das800_interrupt(int irq, void *d)
480 {
481         short i;                /* loop index */
482         short dataPoint = 0;
483         struct comedi_device *dev = d;
484         const struct das800_board *thisboard = comedi_board(dev);
485         struct das800_private *devpriv = dev->private;
486         struct comedi_subdevice *s = dev->read_subdev;  /* analog input subdevice */
487         struct comedi_async *async;
488         int status;
489         unsigned long irq_flags;
490         static const int max_loops = 128;       /*  half-fifo size for cio-das802/16 */
491         /*  flags */
492         int fifo_empty = 0;
493         int fifo_overflow = 0;
494
495         status = inb(dev->iobase + DAS800_STATUS);
496         /* if interrupt was not generated by board or driver not attached, quit */
497         if (!(status & IRQ))
498                 return IRQ_NONE;
499         if (!(dev->attached))
500                 return IRQ_HANDLED;
501
502         /* wait until here to initialize async, since we will get null dereference
503          * if interrupt occurs before driver is fully attached!
504          */
505         async = s->async;
506
507         /*  if hardware conversions are not enabled, then quit */
508         spin_lock_irqsave(&dev->spinlock, irq_flags);
509         status = das800_ind_read(dev, CONTROL1) & STATUS2_HCEN;
510         /* don't release spinlock yet since we want to make sure no one else disables hardware conversions */
511         if (status == 0) {
512                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
513                 return IRQ_HANDLED;
514         }
515
516         /* loop while card's fifo is not empty (and limit to half fifo for cio-das802/16) */
517         for (i = 0; i < max_loops; i++) {
518                 /* read 16 bits from dev->iobase and dev->iobase + 1 */
519                 dataPoint = inb(dev->iobase + DAS800_LSB);
520                 dataPoint += inb(dev->iobase + DAS800_MSB) << 8;
521                 if (thisboard->resolution == 12) {
522                         fifo_empty = dataPoint & FIFO_EMPTY;
523                         fifo_overflow = dataPoint & FIFO_OVF;
524                         if (fifo_overflow)
525                                 break;
526                 } else {
527                         fifo_empty = 0; /*  cio-das802/16 has no fifo empty status bit */
528                 }
529                 if (fifo_empty)
530                         break;
531                 /* strip off extraneous bits for 12 bit cards */
532                 if (thisboard->resolution == 12)
533                         dataPoint = (dataPoint >> 4) & 0xfff;
534                 /* if there are more data points to collect */
535                 if (devpriv->count > 0 || devpriv->forever == 1) {
536                         /* write data point to buffer */
537                         cfc_write_to_buffer(s, dataPoint);
538                         if (devpriv->count > 0)
539                                 devpriv->count--;
540                 }
541         }
542         async->events |= COMEDI_CB_BLOCK;
543         /* check for fifo overflow */
544         if (thisboard->resolution == 12) {
545                 fifo_overflow = dataPoint & FIFO_OVF;
546                 /*  else cio-das802/16 */
547         } else {
548                 fifo_overflow = inb(dev->iobase + DAS800_GAIN) & CIO_FFOV;
549         }
550         if (fifo_overflow) {
551                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
552                 comedi_error(dev, "DAS800 FIFO overflow");
553                 das800_cancel(dev, s);
554                 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
555                 comedi_event(dev, s);
556                 async->events = 0;
557                 return IRQ_HANDLED;
558         }
559         if (devpriv->count > 0 || devpriv->forever == 1) {
560                 /* Re-enable card's interrupt.
561                  * We already have spinlock, so indirect addressing is safe */
562                 das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits,
563                                  CONTROL1);
564                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
565                 /* otherwise, stop taking data */
566         } else {
567                 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
568                 disable_das800(dev);    /* disable hardware triggered conversions */
569                 async->events |= COMEDI_CB_EOA;
570         }
571         comedi_event(dev, s);
572         async->events = 0;
573         return IRQ_HANDLED;
574 }
575
576 static int das800_ai_rinsn(struct comedi_device *dev,
577                            struct comedi_subdevice *s, struct comedi_insn *insn,
578                            unsigned int *data)
579 {
580         const struct das800_board *thisboard = comedi_board(dev);
581         struct das800_private *devpriv = dev->private;
582         int i, n;
583         int chan;
584         int range;
585         int lsb, msb;
586         int timeout = 1000;
587         unsigned long irq_flags;
588
589         disable_das800(dev);    /* disable hardware conversions (enables software conversions) */
590
591         /* set multiplexer */
592         chan = CR_CHAN(insn->chanspec);
593
594         spin_lock_irqsave(&dev->spinlock, irq_flags);
595         das800_ind_write(dev, chan | devpriv->do_bits, CONTROL1);
596         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
597
598         /* set gain / range */
599         range = CR_RANGE(insn->chanspec);
600         if (thisboard->resolution == 12 && range)
601                 range += 0x7;
602         range &= 0xf;
603         outb(range, dev->iobase + DAS800_GAIN);
604
605         udelay(5);
606
607         for (n = 0; n < insn->n; n++) {
608                 /* trigger conversion */
609                 outb_p(0, dev->iobase + DAS800_MSB);
610
611                 for (i = 0; i < timeout; i++) {
612                         if (!(inb(dev->iobase + DAS800_STATUS) & BUSY))
613                                 break;
614                 }
615                 if (i == timeout) {
616                         comedi_error(dev, "timeout");
617                         return -ETIME;
618                 }
619                 lsb = inb(dev->iobase + DAS800_LSB);
620                 msb = inb(dev->iobase + DAS800_MSB);
621                 if (thisboard->resolution == 12) {
622                         data[n] = (lsb >> 4) & 0xff;
623                         data[n] |= (msb << 4);
624                 } else {
625                         data[n] = (msb << 8) | lsb;
626                 }
627         }
628
629         return n;
630 }
631
632 static int das800_di_rbits(struct comedi_device *dev,
633                            struct comedi_subdevice *s, struct comedi_insn *insn,
634                            unsigned int *data)
635 {
636         unsigned int bits;
637
638         bits = inb(dev->iobase + DAS800_STATUS) >> 4;
639         bits &= 0x7;
640         data[1] = bits;
641         data[0] = 0;
642
643         return insn->n;
644 }
645
646 static int das800_do_wbits(struct comedi_device *dev,
647                            struct comedi_subdevice *s, struct comedi_insn *insn,
648                            unsigned int *data)
649 {
650         struct das800_private *devpriv = dev->private;
651         int wbits;
652         unsigned long irq_flags;
653
654         /*  only set bits that have been masked */
655         data[0] &= 0xf;
656         wbits = devpriv->do_bits >> 4;
657         wbits &= ~data[0];
658         wbits |= data[0] & data[1];
659         devpriv->do_bits = wbits << 4;
660
661         spin_lock_irqsave(&dev->spinlock, irq_flags);
662         das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1);
663         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
664
665         data[1] = wbits;
666
667         return insn->n;
668 }
669
670 static int das800_probe(struct comedi_device *dev)
671 {
672         const struct das800_board *thisboard = comedi_board(dev);
673         int id_bits;
674         unsigned long irq_flags;
675         int board;
676
677         spin_lock_irqsave(&dev->spinlock, irq_flags);
678         id_bits = das800_ind_read(dev, ID) & 0x3;
679         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
680
681         board = thisboard - das800_boards;
682
683         switch (id_bits) {
684         case 0x0:
685                 if (board == das800) {
686                         dev_dbg(dev->class_dev, "Board model: DAS-800\n");
687                         return board;
688                 }
689                 if (board == ciodas800) {
690                         dev_dbg(dev->class_dev, "Board model: CIO-DAS800\n");
691                         return board;
692                 }
693                 dev_dbg(dev->class_dev, "Board model (probed): DAS-800\n");
694                 return das800;
695                 break;
696         case 0x2:
697                 if (board == das801) {
698                         dev_dbg(dev->class_dev, "Board model: DAS-801\n");
699                         return board;
700                 }
701                 if (board == ciodas801) {
702                         dev_dbg(dev->class_dev, "Board model: CIO-DAS801\n");
703                         return board;
704                 }
705                 dev_dbg(dev->class_dev, "Board model (probed): DAS-801\n");
706                 return das801;
707                 break;
708         case 0x3:
709                 if (board == das802) {
710                         dev_dbg(dev->class_dev, "Board model: DAS-802\n");
711                         return board;
712                 }
713                 if (board == ciodas802) {
714                         dev_dbg(dev->class_dev, "Board model: CIO-DAS802\n");
715                         return board;
716                 }
717                 if (board == ciodas80216) {
718                         dev_dbg(dev->class_dev, "Board model: CIO-DAS802/16\n");
719                         return board;
720                 }
721                 dev_dbg(dev->class_dev, "Board model (probed): DAS-802\n");
722                 return das802;
723                 break;
724         default:
725                 dev_dbg(dev->class_dev,
726                         "Board model: probe returned 0x%x (unknown)\n",
727                         id_bits);
728                 return board;
729                 break;
730         }
731         return -1;
732 }
733
734 static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
735 {
736         const struct das800_board *thisboard = comedi_board(dev);
737         struct das800_private *devpriv;
738         struct comedi_subdevice *s;
739         unsigned int irq = it->options[1];
740         unsigned long irq_flags;
741         int board;
742         int ret;
743
744         devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
745         if (!devpriv)
746                 return -ENOMEM;
747         dev->private = devpriv;
748
749         ret = comedi_request_region(dev, it->options[0], DAS800_SIZE);
750         if (ret)
751                 return ret;
752
753         board = das800_probe(dev);
754         if (board < 0) {
755                 dev_dbg(dev->class_dev, "unable to determine board type\n");
756                 return -ENODEV;
757         }
758         dev->board_ptr = das800_boards + board;
759         thisboard = comedi_board(dev);
760
761         /* grab our IRQ */
762         if (irq == 1 || irq > 7) {
763                 dev_err(dev->class_dev, "irq out of range\n");
764                 return -EINVAL;
765         }
766         if (irq) {
767                 if (request_irq(irq, das800_interrupt, 0, "das800", dev)) {
768                         dev_err(dev->class_dev, "unable to allocate irq %u\n",
769                                 irq);
770                         return -EINVAL;
771                 }
772         }
773         dev->irq = irq;
774
775         dev->board_name = thisboard->name;
776
777         ret = comedi_alloc_subdevices(dev, 3);
778         if (ret)
779                 return ret;
780
781         /* analog input subdevice */
782         s = &dev->subdevices[0];
783         dev->read_subdev = s;
784         s->type = COMEDI_SUBD_AI;
785         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
786         s->n_chan = 8;
787         s->len_chanlist = 8;
788         s->maxdata = (1 << thisboard->resolution) - 1;
789         s->range_table = thisboard->ai_range;
790         s->do_cmd = das800_ai_do_cmd;
791         s->do_cmdtest = das800_ai_do_cmdtest;
792         s->insn_read = das800_ai_rinsn;
793         s->cancel = das800_cancel;
794
795         /* di */
796         s = &dev->subdevices[1];
797         s->type = COMEDI_SUBD_DI;
798         s->subdev_flags = SDF_READABLE;
799         s->n_chan = 3;
800         s->maxdata = 1;
801         s->range_table = &range_digital;
802         s->insn_bits = das800_di_rbits;
803
804         /* do */
805         s = &dev->subdevices[2];
806         s->type = COMEDI_SUBD_DO;
807         s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
808         s->n_chan = 4;
809         s->maxdata = 1;
810         s->range_table = &range_digital;
811         s->insn_bits = das800_do_wbits;
812
813         disable_das800(dev);
814
815         /* initialize digital out channels */
816         spin_lock_irqsave(&dev->spinlock, irq_flags);
817         das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1);
818         spin_unlock_irqrestore(&dev->spinlock, irq_flags);
819
820         return 0;
821 };
822
823 static struct comedi_driver driver_das800 = {
824         .driver_name    = "das800",
825         .module         = THIS_MODULE,
826         .attach         = das800_attach,
827         .detach         = comedi_legacy_detach,
828         .num_names      = ARRAY_SIZE(das800_boards),
829         .board_name     = &das800_boards[0].name,
830         .offset         = sizeof(struct das800_board),
831 };
832 module_comedi_driver(driver_das800);
833
834 MODULE_AUTHOR("Comedi http://www.comedi.org");
835 MODULE_DESCRIPTION("Comedi low-level driver");
836 MODULE_LICENSE("GPL");