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