1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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
77
78
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
99#define CIO_ENHF 0x90
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
110struct das800_board {
111 const char *name;
112 int ai_speed;
113 const struct comedi_lrange *ai_range;
114 int resolution;
115};
116
117
118static const struct comedi_lrange range_das800_ai = {
119 1,
120 {
121 RANGE(-5, 5),
122 }
123};
124
125static const struct comedi_lrange range_das801_ai = {
126 9,
127 {
128 RANGE(-5, 5),
129 RANGE(-10, 10),
130 RANGE(0, 10),
131 RANGE(-0.5, 0.5),
132 RANGE(0, 1),
133 RANGE(-0.05, 0.05),
134 RANGE(0, 0.1),
135 RANGE(-0.01, 0.01),
136 RANGE(0, 0.02),
137 }
138};
139
140static const struct comedi_lrange range_cio_das801_ai = {
141 9,
142 {
143 RANGE(-5, 5),
144 RANGE(-10, 10),
145 RANGE(0, 10),
146 RANGE(-0.5, 0.5),
147 RANGE(0, 1),
148 RANGE(-0.05, 0.05),
149 RANGE(0, 0.1),
150 RANGE(-0.005, 0.005),
151 RANGE(0, 0.01),
152 }
153};
154
155static const struct comedi_lrange range_das802_ai = {
156 9,
157 {
158 RANGE(-5, 5),
159 RANGE(-10, 10),
160 RANGE(0, 10),
161 RANGE(-2.5, 2.5),
162 RANGE(0, 5),
163 RANGE(-1.25, 1.25),
164 RANGE(0, 2.5),
165 RANGE(-0.625, 0.625),
166 RANGE(0, 1.25),
167 }
168};
169
170static const struct comedi_lrange range_das80216_ai = {
171 8,
172 {
173 RANGE(-10, 10),
174 RANGE(0, 10),
175 RANGE(-5, 5),
176 RANGE(0, 5),
177 RANGE(-2.5, 2.5),
178 RANGE(0, 2.5),
179 RANGE(-1.25, 1.25),
180 RANGE(0, 1.25),
181 }
182};
183
184enum { das800, ciodas800, das801, ciodas801, das802, ciodas802, ciodas80216 };
185
186static const struct das800_board das800_boards[] = {
187 {
188 .name = "das-800",
189 .ai_speed = 25000,
190 .ai_range = &range_das800_ai,
191 .resolution = 12,
192 },
193 {
194 .name = "cio-das800",
195 .ai_speed = 20000,
196 .ai_range = &range_das800_ai,
197 .resolution = 12,
198 },
199 {
200 .name = "das-801",
201 .ai_speed = 25000,
202 .ai_range = &range_das801_ai,
203 .resolution = 12,
204 },
205 {
206 .name = "cio-das801",
207 .ai_speed = 20000,
208 .ai_range = &range_cio_das801_ai,
209 .resolution = 12,
210 },
211 {
212 .name = "das-802",
213 .ai_speed = 25000,
214 .ai_range = &range_das802_ai,
215 .resolution = 12,
216 },
217 {
218 .name = "cio-das802",
219 .ai_speed = 20000,
220 .ai_range = &range_das802_ai,
221 .resolution = 12,
222 },
223 {
224 .name = "cio-das802/16",
225 .ai_speed = 10000,
226 .ai_range = &range_das80216_ai,
227 .resolution = 16,
228 },
229};
230
231
232
233
234#define thisboard ((const struct das800_board *)dev->board_ptr)
235
236struct das800_private {
237 volatile unsigned int count;
238 volatile int forever;
239 unsigned int divisor1;
240 unsigned int divisor2;
241 volatile int do_bits;
242};
243
244#define devpriv ((struct das800_private *)dev->private)
245
246static int das800_attach(struct comedi_device *dev,
247 struct comedi_devconfig *it);
248static int das800_detach(struct comedi_device *dev);
249static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
250
251static struct comedi_driver driver_das800 = {
252 .driver_name = "das800",
253 .module = THIS_MODULE,
254 .attach = das800_attach,
255 .detach = das800_detach,
256 .num_names = ARRAY_SIZE(das800_boards),
257 .board_name = &das800_boards[0].name,
258 .offset = sizeof(struct das800_board),
259};
260
261static irqreturn_t das800_interrupt(int irq, void *d);
262static void enable_das800(struct comedi_device *dev);
263static void disable_das800(struct comedi_device *dev);
264static int das800_ai_do_cmdtest(struct comedi_device *dev,
265 struct comedi_subdevice *s,
266 struct comedi_cmd *cmd);
267static int das800_ai_do_cmd(struct comedi_device *dev,
268 struct comedi_subdevice *s);
269static int das800_ai_rinsn(struct comedi_device *dev,
270 struct comedi_subdevice *s, struct comedi_insn *insn,
271 unsigned int *data);
272static int das800_di_rbits(struct comedi_device *dev,
273 struct comedi_subdevice *s, struct comedi_insn *insn,
274 unsigned int *data);
275static int das800_do_wbits(struct comedi_device *dev,
276 struct comedi_subdevice *s, struct comedi_insn *insn,
277 unsigned int *data);
278static int das800_probe(struct comedi_device *dev);
279static int das800_set_frequency(struct comedi_device *dev);
280
281
282static int das800_probe(struct comedi_device *dev)
283{
284 int id_bits;
285 unsigned long irq_flags;
286 int board;
287
288
289 spin_lock_irqsave(&dev->spinlock, irq_flags);
290 outb(ID, dev->iobase + DAS800_GAIN);
291 id_bits = inb(dev->iobase + DAS800_ID) & 0x3;
292 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
293
294 board = thisboard - das800_boards;
295
296 switch (id_bits) {
297 case 0x0:
298 if (board == das800) {
299 printk(" Board model: DAS-800\n");
300 return board;
301 }
302 if (board == ciodas800) {
303 printk(" Board model: CIO-DAS800\n");
304 return board;
305 }
306 printk(" Board model (probed): DAS-800\n");
307 return das800;
308 break;
309 case 0x2:
310 if (board == das801) {
311 printk(" Board model: DAS-801\n");
312 return board;
313 }
314 if (board == ciodas801) {
315 printk(" Board model: CIO-DAS801\n");
316 return board;
317 }
318 printk(" Board model (probed): DAS-801\n");
319 return das801;
320 break;
321 case 0x3:
322 if (board == das802) {
323 printk(" Board model: DAS-802\n");
324 return board;
325 }
326 if (board == ciodas802) {
327 printk(" Board model: CIO-DAS802\n");
328 return board;
329 }
330 if (board == ciodas80216) {
331 printk(" Board model: CIO-DAS802/16\n");
332 return board;
333 }
334 printk(" Board model (probed): DAS-802\n");
335 return das802;
336 break;
337 default:
338 printk(" Board model: probe returned 0x%x (unknown)\n",
339 id_bits);
340 return board;
341 break;
342 }
343 return -1;
344}
345
346
347
348
349
350COMEDI_INITCLEANUP(driver_das800);
351
352
353static irqreturn_t das800_interrupt(int irq, void *d)
354{
355 short i;
356 short dataPoint = 0;
357 struct comedi_device *dev = d;
358 struct comedi_subdevice *s = dev->read_subdev;
359 struct comedi_async *async;
360 int status;
361 unsigned long irq_flags;
362 static const int max_loops = 128;
363
364 int fifo_empty = 0;
365 int fifo_overflow = 0;
366
367 status = inb(dev->iobase + DAS800_STATUS);
368
369 if (!(status & IRQ))
370 return IRQ_NONE;
371 if (!(dev->attached))
372 return IRQ_HANDLED;
373
374
375
376
377 async = s->async;
378
379
380 spin_lock_irqsave(&dev->spinlock, irq_flags);
381 outb(CONTROL1, dev->iobase + DAS800_GAIN);
382 status = inb(dev->iobase + DAS800_STATUS2) & STATUS2_HCEN;
383
384 if (status == 0) {
385 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
386 return IRQ_HANDLED;
387 }
388
389
390 for (i = 0; i < max_loops; i++) {
391
392 dataPoint = inb(dev->iobase + DAS800_LSB);
393 dataPoint += inb(dev->iobase + DAS800_MSB) << 8;
394 if (thisboard->resolution == 12) {
395 fifo_empty = dataPoint & FIFO_EMPTY;
396 fifo_overflow = dataPoint & FIFO_OVF;
397 if (fifo_overflow)
398 break;
399 } else {
400 fifo_empty = 0;
401 }
402 if (fifo_empty) {
403 break;
404 }
405
406 if (thisboard->resolution == 12)
407 dataPoint = (dataPoint >> 4) & 0xfff;
408
409 if (devpriv->count > 0 || devpriv->forever == 1) {
410
411 cfc_write_to_buffer(s, dataPoint);
412 if (devpriv->count > 0)
413 devpriv->count--;
414 }
415 }
416 async->events |= COMEDI_CB_BLOCK;
417
418 if (thisboard->resolution == 12) {
419 fifo_overflow = dataPoint & FIFO_OVF;
420
421 } else {
422 fifo_overflow = inb(dev->iobase + DAS800_GAIN) & CIO_FFOV;
423 }
424 if (fifo_overflow) {
425 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
426 comedi_error(dev, "DAS800 FIFO overflow");
427 das800_cancel(dev, dev->subdevices + 0);
428 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
429 comedi_event(dev, s);
430 async->events = 0;
431 return IRQ_HANDLED;
432 }
433 if (devpriv->count > 0 || devpriv->forever == 1) {
434
435
436 outb(CONTROL1, dev->iobase + DAS800_GAIN);
437 outb(CONTROL1_INTE | devpriv->do_bits,
438 dev->iobase + DAS800_CONTROL1);
439 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
440
441 } else {
442 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
443 disable_das800(dev);
444 async->events |= COMEDI_CB_EOA;
445 }
446 comedi_event(dev, s);
447 async->events = 0;
448 return IRQ_HANDLED;
449}
450
451static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
452{
453 struct comedi_subdevice *s;
454 unsigned long iobase = it->options[0];
455 unsigned int irq = it->options[1];
456 unsigned long irq_flags;
457 int board;
458
459 printk("comedi%d: das800: io 0x%lx", dev->minor, iobase);
460 if (irq) {
461 printk(", irq %u", irq);
462 }
463 printk("\n");
464
465
466 if (alloc_private(dev, sizeof(struct das800_private)) < 0)
467 return -ENOMEM;
468
469 if (iobase == 0) {
470 printk("io base address required for das800\n");
471 return -EINVAL;
472 }
473
474
475 if (!request_region(iobase, DAS800_SIZE, "das800")) {
476 printk("I/O port conflict\n");
477 return -EIO;
478 }
479 dev->iobase = iobase;
480
481 board = das800_probe(dev);
482 if (board < 0) {
483 printk("unable to determine board type\n");
484 return -ENODEV;
485 }
486 dev->board_ptr = das800_boards + board;
487
488
489 if (irq == 1 || irq > 7) {
490 printk("irq out of range\n");
491 return -EINVAL;
492 }
493 if (irq) {
494 if (request_irq(irq, das800_interrupt, 0, "das800", dev)) {
495 printk("unable to allocate irq %u\n", irq);
496 return -EINVAL;
497 }
498 }
499 dev->irq = irq;
500
501 dev->board_name = thisboard->name;
502
503 if (alloc_subdevices(dev, 3) < 0)
504 return -ENOMEM;
505
506
507 s = dev->subdevices + 0;
508 dev->read_subdev = s;
509 s->type = COMEDI_SUBD_AI;
510 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
511 s->n_chan = 8;
512 s->len_chanlist = 8;
513 s->maxdata = (1 << thisboard->resolution) - 1;
514 s->range_table = thisboard->ai_range;
515 s->do_cmd = das800_ai_do_cmd;
516 s->do_cmdtest = das800_ai_do_cmdtest;
517 s->insn_read = das800_ai_rinsn;
518 s->cancel = das800_cancel;
519
520
521 s = dev->subdevices + 1;
522 s->type = COMEDI_SUBD_DI;
523 s->subdev_flags = SDF_READABLE;
524 s->n_chan = 3;
525 s->maxdata = 1;
526 s->range_table = &range_digital;
527 s->insn_bits = das800_di_rbits;
528
529
530 s = dev->subdevices + 2;
531 s->type = COMEDI_SUBD_DO;
532 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
533 s->n_chan = 4;
534 s->maxdata = 1;
535 s->range_table = &range_digital;
536 s->insn_bits = das800_do_wbits;
537
538 disable_das800(dev);
539
540
541 spin_lock_irqsave(&dev->spinlock, irq_flags);
542 outb(CONTROL1, dev->iobase + DAS800_GAIN);
543 outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);
544 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
545
546 return 0;
547};
548
549static int das800_detach(struct comedi_device *dev)
550{
551 printk("comedi%d: das800: remove\n", dev->minor);
552
553
554 if (dev->iobase)
555 release_region(dev->iobase, DAS800_SIZE);
556 if (dev->irq)
557 free_irq(dev->irq, dev);
558 return 0;
559};
560
561static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
562{
563 devpriv->forever = 0;
564 devpriv->count = 0;
565 disable_das800(dev);
566 return 0;
567}
568
569
570static void enable_das800(struct comedi_device *dev)
571{
572 unsigned long irq_flags;
573 spin_lock_irqsave(&dev->spinlock, irq_flags);
574
575 if (thisboard->resolution == 16)
576 outb(CIO_ENHF, dev->iobase + DAS800_GAIN);
577 outb(CONV_CONTROL, dev->iobase + DAS800_GAIN);
578 outb(CONV_HCEN, dev->iobase + DAS800_CONV_CONTROL);
579 outb(CONTROL1, dev->iobase + DAS800_GAIN);
580 outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);
581 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
582}
583
584
585static void disable_das800(struct comedi_device *dev)
586{
587 unsigned long irq_flags;
588 spin_lock_irqsave(&dev->spinlock, irq_flags);
589 outb(CONV_CONTROL, dev->iobase + DAS800_GAIN);
590 outb(0x0, dev->iobase + DAS800_CONV_CONTROL);
591 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
592}
593
594static int das800_ai_do_cmdtest(struct comedi_device *dev,
595 struct comedi_subdevice *s,
596 struct comedi_cmd *cmd)
597{
598 int err = 0;
599 int tmp;
600 int gain, startChan;
601 int i;
602
603
604
605 tmp = cmd->start_src;
606 cmd->start_src &= TRIG_NOW | TRIG_EXT;
607 if (!cmd->start_src || tmp != cmd->start_src)
608 err++;
609
610 tmp = cmd->scan_begin_src;
611 cmd->scan_begin_src &= TRIG_FOLLOW;
612 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
613 err++;
614
615 tmp = cmd->convert_src;
616 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
617 if (!cmd->convert_src || tmp != cmd->convert_src)
618 err++;
619
620 tmp = cmd->scan_end_src;
621 cmd->scan_end_src &= TRIG_COUNT;
622 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
623 err++;
624
625 tmp = cmd->stop_src;
626 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
627 if (!cmd->stop_src || tmp != cmd->stop_src)
628 err++;
629
630 if (err)
631 return 1;
632
633
634
635 if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
636 err++;
637 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
638 err++;
639 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
640 err++;
641
642 if (err)
643 return 2;
644
645
646
647 if (cmd->start_arg != 0) {
648 cmd->start_arg = 0;
649 err++;
650 }
651 if (cmd->convert_src == TRIG_TIMER) {
652 if (cmd->convert_arg < thisboard->ai_speed) {
653 cmd->convert_arg = thisboard->ai_speed;
654 err++;
655 }
656 }
657 if (!cmd->chanlist_len) {
658 cmd->chanlist_len = 1;
659 err++;
660 }
661 if (cmd->scan_end_arg != cmd->chanlist_len) {
662 cmd->scan_end_arg = cmd->chanlist_len;
663 err++;
664 }
665 if (cmd->stop_src == TRIG_COUNT) {
666 if (!cmd->stop_arg) {
667 cmd->stop_arg = 1;
668 err++;
669 }
670 } else {
671 if (cmd->stop_arg != 0) {
672 cmd->stop_arg = 0;
673 err++;
674 }
675 }
676
677 if (err)
678 return 3;
679
680
681
682 if (cmd->convert_src == TRIG_TIMER) {
683 tmp = cmd->convert_arg;
684
685 i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
686 &(devpriv->divisor2),
687 &(cmd->convert_arg),
688 cmd->flags & TRIG_ROUND_MASK);
689 if (tmp != cmd->convert_arg)
690 err++;
691 }
692
693 if (err)
694 return 4;
695
696
697 if (cmd->chanlist) {
698 gain = CR_RANGE(cmd->chanlist[0]);
699 startChan = CR_CHAN(cmd->chanlist[0]);
700 for (i = 1; i < cmd->chanlist_len; i++) {
701 if (CR_CHAN(cmd->chanlist[i]) !=
702 (startChan + i) % N_CHAN_AI) {
703 comedi_error(dev,
704 "entries in chanlist must be consecutive channels, counting upwards\n");
705 err++;
706 }
707 if (CR_RANGE(cmd->chanlist[i]) != gain) {
708 comedi_error(dev,
709 "entries in chanlist must all have the same gain\n");
710 err++;
711 }
712 }
713 }
714
715 if (err)
716 return 5;
717
718 return 0;
719}
720
721static int das800_ai_do_cmd(struct comedi_device *dev,
722 struct comedi_subdevice *s)
723{
724 int startChan, endChan, scan, gain;
725 int conv_bits;
726 unsigned long irq_flags;
727 struct comedi_async *async = s->async;
728
729 if (!dev->irq) {
730 comedi_error(dev,
731 "no irq assigned for das-800, cannot do hardware conversions");
732 return -1;
733 }
734
735 disable_das800(dev);
736
737
738 startChan = CR_CHAN(async->cmd.chanlist[0]);
739 endChan = (startChan + async->cmd.chanlist_len - 1) % 8;
740 scan = (endChan << 3) | startChan;
741
742 spin_lock_irqsave(&dev->spinlock, irq_flags);
743 outb(SCAN_LIMITS, dev->iobase + DAS800_GAIN);
744 outb(scan, dev->iobase + DAS800_SCAN_LIMITS);
745 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
746
747
748 gain = CR_RANGE(async->cmd.chanlist[0]);
749 if (thisboard->resolution == 12 && gain > 0)
750 gain += 0x7;
751 gain &= 0xf;
752 outb(gain, dev->iobase + DAS800_GAIN);
753
754 switch (async->cmd.stop_src) {
755 case TRIG_COUNT:
756 devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len;
757 devpriv->forever = 0;
758 break;
759 case TRIG_NONE:
760 devpriv->forever = 1;
761 devpriv->count = 0;
762 break;
763 default:
764 break;
765 }
766
767
768
769
770 conv_bits = 0;
771 conv_bits |= EACS | IEOC;
772 if (async->cmd.start_src == TRIG_EXT)
773 conv_bits |= DTEN;
774 switch (async->cmd.convert_src) {
775 case TRIG_TIMER:
776 conv_bits |= CASC | ITE;
777
778 i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
779 &(devpriv->divisor2),
780 &(async->cmd.convert_arg),
781 async->cmd.
782 flags & TRIG_ROUND_MASK);
783 if (das800_set_frequency(dev) < 0) {
784 comedi_error(dev, "Error setting up counters");
785 return -1;
786 }
787 break;
788 case TRIG_EXT:
789 break;
790 default:
791 break;
792 }
793
794 spin_lock_irqsave(&dev->spinlock, irq_flags);
795 outb(CONV_CONTROL, dev->iobase + DAS800_GAIN);
796 outb(conv_bits, dev->iobase + DAS800_CONV_CONTROL);
797 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
798 async->events = 0;
799 enable_das800(dev);
800 return 0;
801}
802
803static int das800_ai_rinsn(struct comedi_device *dev,
804 struct comedi_subdevice *s, struct comedi_insn *insn,
805 unsigned int *data)
806{
807 int i, n;
808 int chan;
809 int range;
810 int lsb, msb;
811 int timeout = 1000;
812 unsigned long irq_flags;
813
814 disable_das800(dev);
815
816
817 chan = CR_CHAN(insn->chanspec);
818
819 spin_lock_irqsave(&dev->spinlock, irq_flags);
820 outb(CONTROL1, dev->iobase + DAS800_GAIN);
821 outb(chan | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);
822 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
823
824
825 range = CR_RANGE(insn->chanspec);
826 if (thisboard->resolution == 12 && range)
827 range += 0x7;
828 range &= 0xf;
829 outb(range, dev->iobase + DAS800_GAIN);
830
831 udelay(5);
832
833 for (n = 0; n < insn->n; n++) {
834
835 outb_p(0, dev->iobase + DAS800_MSB);
836
837 for (i = 0; i < timeout; i++) {
838 if (!(inb(dev->iobase + DAS800_STATUS) & BUSY))
839 break;
840 }
841 if (i == timeout) {
842 comedi_error(dev, "timeout");
843 return -ETIME;
844 }
845 lsb = inb(dev->iobase + DAS800_LSB);
846 msb = inb(dev->iobase + DAS800_MSB);
847 if (thisboard->resolution == 12) {
848 data[n] = (lsb >> 4) & 0xff;
849 data[n] |= (msb << 4);
850 } else {
851 data[n] = (msb << 8) | lsb;
852 }
853 }
854
855 return n;
856}
857
858static int das800_di_rbits(struct comedi_device *dev,
859 struct comedi_subdevice *s, struct comedi_insn *insn,
860 unsigned int *data)
861{
862 unsigned int bits;
863
864 bits = inb(dev->iobase + DAS800_STATUS) >> 4;
865 bits &= 0x7;
866 data[1] = bits;
867 data[0] = 0;
868
869 return 2;
870}
871
872static int das800_do_wbits(struct comedi_device *dev,
873 struct comedi_subdevice *s, struct comedi_insn *insn,
874 unsigned int *data)
875{
876 int wbits;
877 unsigned long irq_flags;
878
879
880 data[0] &= 0xf;
881 wbits = devpriv->do_bits >> 4;
882 wbits &= ~data[0];
883 wbits |= data[0] & data[1];
884 devpriv->do_bits = wbits << 4;
885
886 spin_lock_irqsave(&dev->spinlock, irq_flags);
887 outb(CONTROL1, dev->iobase + DAS800_GAIN);
888 outb(devpriv->do_bits | CONTROL1_INTE, dev->iobase + DAS800_CONTROL1);
889 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
890
891 data[1] = wbits;
892
893 return 2;
894}
895
896
897static int das800_set_frequency(struct comedi_device *dev)
898{
899 int err = 0;
900
901 if (i8254_load(dev->iobase + DAS800_8254, 0, 1, devpriv->divisor1, 2))
902 err++;
903 if (i8254_load(dev->iobase + DAS800_8254, 0, 2, devpriv->divisor2, 2))
904 err++;
905 if (err)
906 return -1;
907
908 return 0;
909}
910