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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111#include <linux/module.h>
112#include <linux/interrupt.h>
113#include <linux/gfp.h>
114#include "../comedidev.h"
115
116#include <linux/delay.h>
117#include <linux/io.h>
118#include <asm/dma.h>
119
120#include "comedi_fc.h"
121#include "8253.h"
122
123
124#define boardPCL812PG 0
125#define boardPCL813B 1
126#define boardPCL812 2
127#define boardPCL813 3
128#define boardISO813 5
129#define boardACL8113 6
130#define boardACL8112 7
131#define boardACL8216 8
132#define boardA821 9
133
134
135
136
137#define PCL812_TIMER_BASE 0x00
138#define PCL812_AI_LSB_REG 0x04
139#define PCL812_AI_MSB_REG 0x05
140#define PCL812_AI_MSB_DRDY (1 << 4)
141#define PCL812_AO_LSB_REG(x) (0x04 + ((x) * 2))
142#define PCL812_AO_MSB_REG(x) (0x05 + ((x) * 2))
143#define PCL812_DI_LSB_REG 0x06
144#define PCL812_DI_MSB_REG 0x07
145#define PCL812_STATUS_REG 0x08
146#define PCL812_STATUS_DRDY (1 << 5)
147#define PCL812_RANGE_REG 0x09
148#define PCL812_MUX_REG 0x0a
149#define PCL812_MUX_CHAN(x) ((x) << 0)
150#define PCL812_MUX_CS0 (1 << 4)
151#define PCL812_MUX_CS1 (1 << 5)
152#define PCL812_CTRL_REG 0x0b
153#define PCL812_CTRL_DISABLE_TRIG (0 << 0)
154#define PCL812_CTRL_SOFT_TRIG (1 << 0)
155#define PCL812_CTRL_PACER_DMA_TRIG (2 << 0)
156#define PCL812_CTRL_PACER_EOC_TRIG (6 << 0)
157#define PCL812_SOFTTRIG_REG 0x0c
158#define PCL812_DO_LSB_REG 0x0d
159#define PCL812_DO_MSB_REG 0x0e
160
161#define MAX_CHANLIST_LEN 256
162
163static const struct comedi_lrange range_pcl812pg_ai = {
164 5, {
165 BIP_RANGE(5),
166 BIP_RANGE(2.5),
167 BIP_RANGE(1.25),
168 BIP_RANGE(0.625),
169 BIP_RANGE(0.3125)
170 }
171};
172
173static const struct comedi_lrange range_pcl812pg2_ai = {
174 5, {
175 BIP_RANGE(10),
176 BIP_RANGE(5),
177 BIP_RANGE(2.5),
178 BIP_RANGE(1.25),
179 BIP_RANGE(0.625)
180 }
181};
182
183static const struct comedi_lrange range812_bipolar1_25 = {
184 1, {
185 BIP_RANGE(1.25)
186 }
187};
188
189static const struct comedi_lrange range812_bipolar0_625 = {
190 1, {
191 BIP_RANGE(0.625)
192 }
193};
194
195static const struct comedi_lrange range812_bipolar0_3125 = {
196 1, {
197 BIP_RANGE(0.3125)
198 }
199};
200
201static const struct comedi_lrange range_pcl813b_ai = {
202 4, {
203 BIP_RANGE(5),
204 BIP_RANGE(2.5),
205 BIP_RANGE(1.25),
206 BIP_RANGE(0.625)
207 }
208};
209
210static const struct comedi_lrange range_pcl813b2_ai = {
211 4, {
212 UNI_RANGE(10),
213 UNI_RANGE(5),
214 UNI_RANGE(2.5),
215 UNI_RANGE(1.25)
216 }
217};
218
219static const struct comedi_lrange range_iso813_1_ai = {
220 5, {
221 BIP_RANGE(5),
222 BIP_RANGE(2.5),
223 BIP_RANGE(1.25),
224 BIP_RANGE(0.625),
225 BIP_RANGE(0.3125)
226 }
227};
228
229static const struct comedi_lrange range_iso813_1_2_ai = {
230 5, {
231 UNI_RANGE(10),
232 UNI_RANGE(5),
233 UNI_RANGE(2.5),
234 UNI_RANGE(1.25),
235 UNI_RANGE(0.625)
236 }
237};
238
239static const struct comedi_lrange range_iso813_2_ai = {
240 4, {
241 BIP_RANGE(5),
242 BIP_RANGE(2.5),
243 BIP_RANGE(1.25),
244 BIP_RANGE(0.625)
245 }
246};
247
248static const struct comedi_lrange range_iso813_2_2_ai = {
249 4, {
250 UNI_RANGE(10),
251 UNI_RANGE(5),
252 UNI_RANGE(2.5),
253 UNI_RANGE(1.25)
254 }
255};
256
257static const struct comedi_lrange range_acl8113_1_ai = {
258 4, {
259 BIP_RANGE(5),
260 BIP_RANGE(2.5),
261 BIP_RANGE(1.25),
262 BIP_RANGE(0.625)
263 }
264};
265
266static const struct comedi_lrange range_acl8113_1_2_ai = {
267 4, {
268 UNI_RANGE(10),
269 UNI_RANGE(5),
270 UNI_RANGE(2.5),
271 UNI_RANGE(1.25)
272 }
273};
274
275static const struct comedi_lrange range_acl8113_2_ai = {
276 3, {
277 BIP_RANGE(5),
278 BIP_RANGE(2.5),
279 BIP_RANGE(1.25)
280 }
281};
282
283static const struct comedi_lrange range_acl8113_2_2_ai = {
284 3, {
285 UNI_RANGE(10),
286 UNI_RANGE(5),
287 UNI_RANGE(2.5)
288 }
289};
290
291static const struct comedi_lrange range_acl8112dg_ai = {
292 9, {
293 BIP_RANGE(5),
294 BIP_RANGE(2.5),
295 BIP_RANGE(1.25),
296 BIP_RANGE(0.625),
297 UNI_RANGE(10),
298 UNI_RANGE(5),
299 UNI_RANGE(2.5),
300 UNI_RANGE(1.25),
301 BIP_RANGE(10)
302 }
303};
304
305static const struct comedi_lrange range_acl8112hg_ai = {
306 12, {
307 BIP_RANGE(5),
308 BIP_RANGE(0.5),
309 BIP_RANGE(0.05),
310 BIP_RANGE(0.005),
311 UNI_RANGE(10),
312 UNI_RANGE(1),
313 UNI_RANGE(0.1),
314 UNI_RANGE(0.01),
315 BIP_RANGE(10),
316 BIP_RANGE(1),
317 BIP_RANGE(0.1),
318 BIP_RANGE(0.01)
319 }
320};
321
322static const struct comedi_lrange range_a821pgh_ai = {
323 4, {
324 BIP_RANGE(5),
325 BIP_RANGE(0.5),
326 BIP_RANGE(0.05),
327 BIP_RANGE(0.005)
328 }
329};
330
331struct pcl812_board {
332 const char *name;
333 int board_type;
334 int n_aichan;
335 int n_aochan;
336 unsigned int ai_ns_min;
337 const struct comedi_lrange *rangelist_ai;
338 unsigned int IRQbits;
339 unsigned int has_dma:1;
340 unsigned int has_16bit_ai:1;
341 unsigned int has_mpc508_mux:1;
342 unsigned int has_dio:1;
343};
344
345static const struct pcl812_board boardtypes[] = {
346 {
347 .name = "pcl812",
348 .board_type = boardPCL812,
349 .n_aichan = 16,
350 .n_aochan = 2,
351 .ai_ns_min = 33000,
352 .rangelist_ai = &range_bipolar10,
353 .IRQbits = 0xdcfc,
354 .has_dma = 1,
355 .has_dio = 1,
356 }, {
357 .name = "pcl812pg",
358 .board_type = boardPCL812PG,
359 .n_aichan = 16,
360 .n_aochan = 2,
361 .ai_ns_min = 33000,
362 .rangelist_ai = &range_pcl812pg_ai,
363 .IRQbits = 0xdcfc,
364 .has_dma = 1,
365 .has_dio = 1,
366 }, {
367 .name = "acl8112pg",
368 .board_type = boardPCL812PG,
369 .n_aichan = 16,
370 .n_aochan = 2,
371 .ai_ns_min = 10000,
372 .rangelist_ai = &range_pcl812pg_ai,
373 .IRQbits = 0xdcfc,
374 .has_dma = 1,
375 .has_dio = 1,
376 }, {
377 .name = "acl8112dg",
378 .board_type = boardACL8112,
379 .n_aichan = 16,
380 .n_aochan = 2,
381 .ai_ns_min = 10000,
382 .rangelist_ai = &range_acl8112dg_ai,
383 .IRQbits = 0xdcfc,
384 .has_dma = 1,
385 .has_mpc508_mux = 1,
386 .has_dio = 1,
387 }, {
388 .name = "acl8112hg",
389 .board_type = boardACL8112,
390 .n_aichan = 16,
391 .n_aochan = 2,
392 .ai_ns_min = 10000,
393 .rangelist_ai = &range_acl8112hg_ai,
394 .IRQbits = 0xdcfc,
395 .has_dma = 1,
396 .has_mpc508_mux = 1,
397 .has_dio = 1,
398 }, {
399 .name = "a821pgl",
400 .board_type = boardA821,
401 .n_aichan = 16,
402 .n_aochan = 1,
403 .ai_ns_min = 10000,
404 .rangelist_ai = &range_pcl813b_ai,
405 .IRQbits = 0x000c,
406 .has_dio = 1,
407 }, {
408 .name = "a821pglnda",
409 .board_type = boardA821,
410 .n_aichan = 16,
411 .ai_ns_min = 10000,
412 .rangelist_ai = &range_pcl813b_ai,
413 .IRQbits = 0x000c,
414 }, {
415 .name = "a821pgh",
416 .board_type = boardA821,
417 .n_aichan = 16,
418 .n_aochan = 1,
419 .ai_ns_min = 10000,
420 .rangelist_ai = &range_a821pgh_ai,
421 .IRQbits = 0x000c,
422 .has_dio = 1,
423 }, {
424 .name = "a822pgl",
425 .board_type = boardACL8112,
426 .n_aichan = 16,
427 .n_aochan = 2,
428 .ai_ns_min = 10000,
429 .rangelist_ai = &range_acl8112dg_ai,
430 .IRQbits = 0xdcfc,
431 .has_dma = 1,
432 .has_dio = 1,
433 }, {
434 .name = "a822pgh",
435 .board_type = boardACL8112,
436 .n_aichan = 16,
437 .n_aochan = 2,
438 .ai_ns_min = 10000,
439 .rangelist_ai = &range_acl8112hg_ai,
440 .IRQbits = 0xdcfc,
441 .has_dma = 1,
442 .has_dio = 1,
443 }, {
444 .name = "a823pgl",
445 .board_type = boardACL8112,
446 .n_aichan = 16,
447 .n_aochan = 2,
448 .ai_ns_min = 8000,
449 .rangelist_ai = &range_acl8112dg_ai,
450 .IRQbits = 0xdcfc,
451 .has_dma = 1,
452 .has_dio = 1,
453 }, {
454 .name = "a823pgh",
455 .board_type = boardACL8112,
456 .n_aichan = 16,
457 .n_aochan = 2,
458 .ai_ns_min = 8000,
459 .rangelist_ai = &range_acl8112hg_ai,
460 .IRQbits = 0xdcfc,
461 .has_dma = 1,
462 .has_dio = 1,
463 }, {
464 .name = "pcl813",
465 .board_type = boardPCL813,
466 .n_aichan = 32,
467 .rangelist_ai = &range_pcl813b_ai,
468 }, {
469 .name = "pcl813b",
470 .board_type = boardPCL813B,
471 .n_aichan = 32,
472 .rangelist_ai = &range_pcl813b_ai,
473 }, {
474 .name = "acl8113",
475 .board_type = boardACL8113,
476 .n_aichan = 32,
477 .rangelist_ai = &range_acl8113_1_ai,
478 }, {
479 .name = "iso813",
480 .board_type = boardISO813,
481 .n_aichan = 32,
482 .rangelist_ai = &range_iso813_1_ai,
483 }, {
484 .name = "acl8216",
485 .board_type = boardACL8216,
486 .n_aichan = 16,
487 .n_aochan = 2,
488 .ai_ns_min = 10000,
489 .rangelist_ai = &range_pcl813b2_ai,
490 .IRQbits = 0xdcfc,
491 .has_dma = 1,
492 .has_16bit_ai = 1,
493 .has_mpc508_mux = 1,
494 .has_dio = 1,
495 }, {
496 .name = "a826pg",
497 .board_type = boardACL8216,
498 .n_aichan = 16,
499 .n_aochan = 2,
500 .ai_ns_min = 10000,
501 .rangelist_ai = &range_pcl813b2_ai,
502 .IRQbits = 0xdcfc,
503 .has_dma = 1,
504 .has_16bit_ai = 1,
505 .has_dio = 1,
506 },
507};
508
509struct pcl812_private {
510 unsigned char dma;
511 unsigned char range_correction;
512 unsigned int last_ai_chanspec;
513 unsigned char mode_reg_int;
514 unsigned int ai_poll_ptr;
515 unsigned int ai_act_scan;
516 unsigned int dmapages;
517 unsigned int hwdmasize;
518 unsigned long dmabuf[2];
519 unsigned int hwdmaptr[2];
520 unsigned int dmabytestomove[2];
521 int next_dma_buf;
522 unsigned int dma_runs_to_end;
523 unsigned int last_dma_run;
524 unsigned int max_812_ai_mode0_rangewait;
525 unsigned int divisor1;
526 unsigned int divisor2;
527 unsigned int use_diff:1;
528 unsigned int use_mpc508:1;
529 unsigned int use_ext_trg:1;
530 unsigned int ai_dma:1;
531 unsigned int ai_eos:1;
532};
533
534static void pcl812_start_pacer(struct comedi_device *dev, bool load_timers)
535{
536 struct pcl812_private *devpriv = dev->private;
537 unsigned long timer_base = dev->iobase + PCL812_TIMER_BASE;
538
539 i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
540 i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
541 udelay(1);
542
543 if (load_timers) {
544 i8254_write(timer_base, 0, 2, devpriv->divisor2);
545 i8254_write(timer_base, 0, 1, devpriv->divisor1);
546 }
547}
548
549static void pcl812_ai_setup_dma(struct comedi_device *dev,
550 struct comedi_subdevice *s)
551{
552 struct pcl812_private *devpriv = dev->private;
553 struct comedi_cmd *cmd = &s->async->cmd;
554 unsigned int dma_flags;
555 unsigned int bytes;
556
557
558 if (devpriv->ai_eos) {
559 devpriv->dmabytestomove[0] = cfc_bytes_per_scan(s);
560 devpriv->dmabytestomove[1] = cfc_bytes_per_scan(s);
561 devpriv->dma_runs_to_end = 1;
562 } else {
563 devpriv->dmabytestomove[0] = devpriv->hwdmasize;
564 devpriv->dmabytestomove[1] = devpriv->hwdmasize;
565 if (s->async->prealloc_bufsz < devpriv->hwdmasize) {
566 devpriv->dmabytestomove[0] =
567 s->async->prealloc_bufsz;
568 devpriv->dmabytestomove[1] =
569 s->async->prealloc_bufsz;
570 }
571 if (cmd->stop_src == TRIG_NONE) {
572 devpriv->dma_runs_to_end = 1;
573 } else {
574
575 bytes = cmd->stop_arg * cfc_bytes_per_scan(s);
576
577
578 devpriv->dma_runs_to_end =
579 bytes / devpriv->dmabytestomove[0];
580
581
582 devpriv->last_dma_run =
583 bytes % devpriv->dmabytestomove[0];
584 if (devpriv->dma_runs_to_end == 0)
585 devpriv->dmabytestomove[0] =
586 devpriv->last_dma_run;
587 devpriv->dma_runs_to_end--;
588 }
589 }
590 if (devpriv->dmabytestomove[0] > devpriv->hwdmasize) {
591 devpriv->dmabytestomove[0] = devpriv->hwdmasize;
592 devpriv->ai_eos = 0;
593 }
594 if (devpriv->dmabytestomove[1] > devpriv->hwdmasize) {
595 devpriv->dmabytestomove[1] = devpriv->hwdmasize;
596 devpriv->ai_eos = 0;
597 }
598 devpriv->next_dma_buf = 0;
599 set_dma_mode(devpriv->dma, DMA_MODE_READ);
600 dma_flags = claim_dma_lock();
601 clear_dma_ff(devpriv->dma);
602 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
603 set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]);
604 release_dma_lock(dma_flags);
605 enable_dma(devpriv->dma);
606}
607
608static void pcl812_ai_setup_next_dma(struct comedi_device *dev,
609 struct comedi_subdevice *s)
610{
611 struct pcl812_private *devpriv = dev->private;
612 unsigned long dma_flags;
613
614 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
615 disable_dma(devpriv->dma);
616 set_dma_mode(devpriv->dma, DMA_MODE_READ);
617 dma_flags = claim_dma_lock();
618 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]);
619 if (devpriv->ai_eos) {
620 set_dma_count(devpriv->dma,
621 devpriv->dmabytestomove[devpriv->next_dma_buf]);
622 } else {
623 if (devpriv->dma_runs_to_end) {
624 set_dma_count(devpriv->dma,
625 devpriv->dmabytestomove[devpriv->
626 next_dma_buf]);
627 } else {
628 set_dma_count(devpriv->dma, devpriv->last_dma_run);
629 }
630 devpriv->dma_runs_to_end--;
631 }
632 release_dma_lock(dma_flags);
633 enable_dma(devpriv->dma);
634}
635
636static void pcl812_ai_set_chan_range(struct comedi_device *dev,
637 unsigned int chanspec, char wait)
638{
639 struct pcl812_private *devpriv = dev->private;
640 unsigned int chan = CR_CHAN(chanspec);
641 unsigned int range = CR_RANGE(chanspec);
642 unsigned int mux = 0;
643
644 if (chanspec == devpriv->last_ai_chanspec)
645 return;
646
647 devpriv->last_ai_chanspec = chanspec;
648
649 if (devpriv->use_mpc508) {
650 if (devpriv->use_diff) {
651 mux |= PCL812_MUX_CS0 | PCL812_MUX_CS1;
652 } else {
653 if (chan < 8)
654 mux |= PCL812_MUX_CS0;
655 else
656 mux |= PCL812_MUX_CS1;
657 }
658 }
659
660 outb(mux | PCL812_MUX_CHAN(chan), dev->iobase + PCL812_MUX_REG);
661 outb(range + devpriv->range_correction, dev->iobase + PCL812_RANGE_REG);
662
663 if (wait)
664
665
666
667
668 udelay(devpriv->max_812_ai_mode0_rangewait);
669}
670
671static void pcl812_ai_clear_eoc(struct comedi_device *dev)
672{
673
674 outb(0, dev->iobase + PCL812_STATUS_REG);
675}
676
677static void pcl812_ai_soft_trig(struct comedi_device *dev)
678{
679
680 outb(255, dev->iobase + PCL812_SOFTTRIG_REG);
681}
682
683static unsigned int pcl812_ai_get_sample(struct comedi_device *dev,
684 struct comedi_subdevice *s)
685{
686 unsigned int val;
687
688 val = inb(dev->iobase + PCL812_AI_MSB_REG) << 8;
689 val |= inb(dev->iobase + PCL812_AI_LSB_REG);
690
691 return val & s->maxdata;
692}
693
694static int pcl812_ai_eoc(struct comedi_device *dev,
695 struct comedi_subdevice *s,
696 struct comedi_insn *insn,
697 unsigned long context)
698{
699 unsigned int status;
700
701 if (s->maxdata > 0x0fff) {
702 status = inb(dev->iobase + PCL812_STATUS_REG);
703 if ((status & PCL812_STATUS_DRDY) == 0)
704 return 0;
705 } else {
706 status = inb(dev->iobase + PCL812_AI_MSB_REG);
707 if ((status & PCL812_AI_MSB_DRDY) == 0)
708 return 0;
709 }
710 return -EBUSY;
711}
712
713static int pcl812_ai_cmdtest(struct comedi_device *dev,
714 struct comedi_subdevice *s, struct comedi_cmd *cmd)
715{
716 const struct pcl812_board *board = dev->board_ptr;
717 struct pcl812_private *devpriv = dev->private;
718 int err = 0;
719 unsigned int flags;
720 unsigned int arg;
721
722
723
724 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
725 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
726
727 if (devpriv->use_ext_trg)
728 flags = TRIG_EXT;
729 else
730 flags = TRIG_TIMER;
731 err |= cfc_check_trigger_src(&cmd->convert_src, flags);
732
733 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
734 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
735
736 if (err)
737 return 1;
738
739
740
741 err |= cfc_check_trigger_is_unique(cmd->stop_src);
742
743
744
745 if (err)
746 return 2;
747
748
749
750 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
751 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
752
753 if (cmd->convert_src == TRIG_TIMER)
754 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
755 board->ai_ns_min);
756 else
757 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
758
759 err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
760 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
761
762 if (cmd->stop_src == TRIG_COUNT)
763 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
764 else
765 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
766
767 if (err)
768 return 3;
769
770
771
772 if (cmd->convert_src == TRIG_TIMER) {
773 arg = cmd->convert_arg;
774 i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ,
775 &devpriv->divisor1,
776 &devpriv->divisor2,
777 &arg, cmd->flags);
778 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
779 }
780
781 if (err)
782 return 4;
783
784 return 0;
785}
786
787static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
788{
789 struct pcl812_private *devpriv = dev->private;
790 struct comedi_cmd *cmd = &s->async->cmd;
791 unsigned int ctrl = 0;
792 unsigned int i;
793
794 pcl812_start_pacer(dev, false);
795
796 pcl812_ai_set_chan_range(dev, cmd->chanlist[0], 1);
797
798 if (devpriv->dma) {
799 devpriv->ai_dma = 1;
800 for (i = 1; i < cmd->chanlist_len; i++)
801 if (cmd->chanlist[0] != cmd->chanlist[i]) {
802
803 devpriv->ai_dma = 0;
804 break;
805 }
806 } else {
807 devpriv->ai_dma = 0;
808 }
809
810 devpriv->ai_act_scan = 0;
811 devpriv->ai_poll_ptr = 0;
812 s->async->cur_chan = 0;
813
814
815 if (cmd->flags & CMDF_WAKE_EOS) {
816 devpriv->ai_eos = 1;
817
818
819 if (cmd->chanlist_len == 1)
820 devpriv->ai_dma = 0;
821 }
822
823 if (devpriv->ai_dma)
824 pcl812_ai_setup_dma(dev, s);
825
826 switch (cmd->convert_src) {
827 case TRIG_TIMER:
828 pcl812_start_pacer(dev, true);
829 break;
830 }
831
832 if (devpriv->ai_dma)
833 ctrl |= PCL812_CTRL_PACER_DMA_TRIG;
834 else
835 ctrl |= PCL812_CTRL_PACER_EOC_TRIG;
836 outb(devpriv->mode_reg_int | ctrl, dev->iobase + PCL812_CTRL_REG);
837
838 return 0;
839}
840
841static bool pcl812_ai_next_chan(struct comedi_device *dev,
842 struct comedi_subdevice *s)
843{
844 struct pcl812_private *devpriv = dev->private;
845 struct comedi_cmd *cmd = &s->async->cmd;
846
847 s->async->events |= COMEDI_CB_BLOCK;
848
849 s->async->cur_chan++;
850 if (s->async->cur_chan >= cmd->chanlist_len) {
851 s->async->cur_chan = 0;
852 devpriv->ai_act_scan++;
853 s->async->events |= COMEDI_CB_EOS;
854 }
855
856 if (cmd->stop_src == TRIG_COUNT &&
857 devpriv->ai_act_scan >= cmd->stop_arg) {
858
859 s->async->events |= COMEDI_CB_EOA;
860 return false;
861 }
862
863 return true;
864}
865
866static void pcl812_handle_eoc(struct comedi_device *dev,
867 struct comedi_subdevice *s)
868{
869 struct comedi_cmd *cmd = &s->async->cmd;
870 unsigned int next_chan;
871
872 if (pcl812_ai_eoc(dev, s, NULL, 0)) {
873 dev_dbg(dev->class_dev, "A/D cmd IRQ without DRDY!\n");
874 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
875 return;
876 }
877
878 comedi_buf_put(s, pcl812_ai_get_sample(dev, s));
879
880
881 next_chan = s->async->cur_chan + 1;
882 if (next_chan >= cmd->chanlist_len)
883 next_chan = 0;
884 if (cmd->chanlist[s->async->cur_chan] != cmd->chanlist[next_chan])
885 pcl812_ai_set_chan_range(dev, cmd->chanlist[next_chan], 0);
886
887 pcl812_ai_next_chan(dev, s);
888}
889
890static void transfer_from_dma_buf(struct comedi_device *dev,
891 struct comedi_subdevice *s,
892 unsigned short *ptr,
893 unsigned int bufptr, unsigned int len)
894{
895 unsigned int i;
896
897 for (i = len; i; i--) {
898 comedi_buf_put(s, ptr[bufptr++]);
899
900 if (!pcl812_ai_next_chan(dev, s))
901 break;
902 }
903}
904
905static void pcl812_handle_dma(struct comedi_device *dev,
906 struct comedi_subdevice *s)
907{
908 struct pcl812_private *devpriv = dev->private;
909 int len, bufptr;
910 unsigned short *ptr;
911
912 ptr = (unsigned short *)devpriv->dmabuf[devpriv->next_dma_buf];
913 len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) -
914 devpriv->ai_poll_ptr;
915
916 pcl812_ai_setup_next_dma(dev, s);
917
918 bufptr = devpriv->ai_poll_ptr;
919 devpriv->ai_poll_ptr = 0;
920
921 transfer_from_dma_buf(dev, s, ptr, bufptr, len);
922}
923
924static irqreturn_t pcl812_interrupt(int irq, void *d)
925{
926 struct comedi_device *dev = d;
927 struct comedi_subdevice *s = dev->read_subdev;
928 struct pcl812_private *devpriv = dev->private;
929
930 if (!dev->attached) {
931 pcl812_ai_clear_eoc(dev);
932 return IRQ_HANDLED;
933 }
934
935 if (devpriv->ai_dma)
936 pcl812_handle_dma(dev, s);
937 else
938 pcl812_handle_eoc(dev, s);
939
940 pcl812_ai_clear_eoc(dev);
941
942 cfc_handle_events(dev, s);
943 return IRQ_HANDLED;
944}
945
946static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
947{
948 struct pcl812_private *devpriv = dev->private;
949 unsigned long flags;
950 unsigned int top1, top2, i;
951
952 if (!devpriv->ai_dma)
953 return 0;
954
955 spin_lock_irqsave(&dev->spinlock, flags);
956
957 for (i = 0; i < 10; i++) {
958
959 top1 = get_dma_residue(devpriv->ai_dma);
960 top2 = get_dma_residue(devpriv->ai_dma);
961 if (top1 == top2)
962 break;
963 }
964
965 if (top1 != top2) {
966 spin_unlock_irqrestore(&dev->spinlock, flags);
967 return 0;
968 }
969
970 top1 = devpriv->dmabytestomove[1 - devpriv->next_dma_buf] - top1;
971 top1 >>= 1;
972 top2 = top1 - devpriv->ai_poll_ptr;
973 if (top2 < 1) {
974 spin_unlock_irqrestore(&dev->spinlock, flags);
975 return 0;
976 }
977
978 transfer_from_dma_buf(dev, s,
979 (void *)devpriv->dmabuf[1 -
980 devpriv->next_dma_buf],
981 devpriv->ai_poll_ptr, top2);
982
983 devpriv->ai_poll_ptr = top1;
984
985 spin_unlock_irqrestore(&dev->spinlock, flags);
986
987 return comedi_buf_n_bytes_ready(s);
988}
989
990static int pcl812_ai_cancel(struct comedi_device *dev,
991 struct comedi_subdevice *s)
992{
993 struct pcl812_private *devpriv = dev->private;
994
995 if (devpriv->ai_dma)
996 disable_dma(devpriv->dma);
997
998 outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG,
999 dev->iobase + PCL812_CTRL_REG);
1000 pcl812_start_pacer(dev, false);
1001 pcl812_ai_clear_eoc(dev);
1002 return 0;
1003}
1004
1005static int pcl812_ai_insn_read(struct comedi_device *dev,
1006 struct comedi_subdevice *s,
1007 struct comedi_insn *insn,
1008 unsigned int *data)
1009{
1010 struct pcl812_private *devpriv = dev->private;
1011 int ret = 0;
1012 int i;
1013
1014 outb(devpriv->mode_reg_int | PCL812_CTRL_SOFT_TRIG,
1015 dev->iobase + PCL812_CTRL_REG);
1016
1017 pcl812_ai_set_chan_range(dev, insn->chanspec, 1);
1018
1019 for (i = 0; i < insn->n; i++) {
1020 pcl812_ai_clear_eoc(dev);
1021 pcl812_ai_soft_trig(dev);
1022
1023 ret = comedi_timeout(dev, s, insn, pcl812_ai_eoc, 0);
1024 if (ret)
1025 break;
1026
1027 data[i] = pcl812_ai_get_sample(dev, s);
1028 }
1029 outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG,
1030 dev->iobase + PCL812_CTRL_REG);
1031 pcl812_ai_clear_eoc(dev);
1032
1033 return ret ? ret : insn->n;
1034}
1035
1036static int pcl812_ao_insn_write(struct comedi_device *dev,
1037 struct comedi_subdevice *s,
1038 struct comedi_insn *insn,
1039 unsigned int *data)
1040{
1041 unsigned int chan = CR_CHAN(insn->chanspec);
1042 unsigned int val = s->readback[chan];
1043 int i;
1044
1045 for (i = 0; i < insn->n; i++) {
1046 val = data[i];
1047 outb(val & 0xff, dev->iobase + PCL812_AO_LSB_REG(chan));
1048 outb((val >> 8) & 0x0f, dev->iobase + PCL812_AO_MSB_REG(chan));
1049 }
1050 s->readback[chan] = val;
1051
1052 return insn->n;
1053}
1054
1055static int pcl812_di_insn_bits(struct comedi_device *dev,
1056 struct comedi_subdevice *s,
1057 struct comedi_insn *insn,
1058 unsigned int *data)
1059{
1060 data[1] = inb(dev->iobase + PCL812_DI_LSB_REG) |
1061 (inb(dev->iobase + PCL812_DI_MSB_REG) << 8);
1062
1063 return insn->n;
1064}
1065
1066static int pcl812_do_insn_bits(struct comedi_device *dev,
1067 struct comedi_subdevice *s,
1068 struct comedi_insn *insn,
1069 unsigned int *data)
1070{
1071 if (comedi_dio_update_state(s, data)) {
1072 outb(s->state & 0xff, dev->iobase + PCL812_DO_LSB_REG);
1073 outb((s->state >> 8), dev->iobase + PCL812_DO_MSB_REG);
1074 }
1075
1076 data[1] = s->state;
1077
1078 return insn->n;
1079}
1080
1081static void pcl812_reset(struct comedi_device *dev)
1082{
1083 const struct pcl812_board *board = dev->board_ptr;
1084 struct pcl812_private *devpriv = dev->private;
1085 unsigned int chan;
1086
1087
1088 outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG,
1089 dev->iobase + PCL812_CTRL_REG);
1090 pcl812_ai_clear_eoc(dev);
1091
1092
1093 if (board->IRQbits)
1094 pcl812_start_pacer(dev, false);
1095
1096
1097
1098
1099
1100 devpriv->last_ai_chanspec = CR_PACK(16, 0, 0);
1101 pcl812_ai_set_chan_range(dev, CR_PACK(0, 0, 0), 0);
1102
1103
1104 for (chan = 0; chan < board->n_aochan; chan++) {
1105 outb(0, dev->iobase + PCL812_AO_LSB_REG(chan));
1106 outb(0, dev->iobase + PCL812_AO_MSB_REG(chan));
1107 }
1108
1109
1110 if (board->has_dio) {
1111 outb(0, dev->iobase + PCL812_DO_MSB_REG);
1112 outb(0, dev->iobase + PCL812_DO_LSB_REG);
1113 }
1114}
1115
1116static void pcl812_set_ai_range_table(struct comedi_device *dev,
1117 struct comedi_subdevice *s,
1118 struct comedi_devconfig *it)
1119{
1120 const struct pcl812_board *board = dev->board_ptr;
1121 struct pcl812_private *devpriv = dev->private;
1122
1123
1124 s->range_table = board->rangelist_ai;
1125
1126
1127 switch (board->board_type) {
1128 case boardPCL812PG:
1129 if (it->options[4] == 1)
1130 s->range_table = &range_pcl812pg2_ai;
1131 break;
1132 case boardPCL812:
1133 switch (it->options[4]) {
1134 case 0:
1135 s->range_table = &range_bipolar10;
1136 break;
1137 case 1:
1138 s->range_table = &range_bipolar5;
1139 break;
1140 case 2:
1141 s->range_table = &range_bipolar2_5;
1142 break;
1143 case 3:
1144 s->range_table = &range812_bipolar1_25;
1145 break;
1146 case 4:
1147 s->range_table = &range812_bipolar0_625;
1148 break;
1149 case 5:
1150 s->range_table = &range812_bipolar0_3125;
1151 break;
1152 default:
1153 s->range_table = &range_bipolar10;
1154 break;
1155 }
1156 break;
1157 case boardPCL813B:
1158 if (it->options[1] == 1)
1159 s->range_table = &range_pcl813b2_ai;
1160 break;
1161 case boardISO813:
1162 switch (it->options[1]) {
1163 case 0:
1164 s->range_table = &range_iso813_1_ai;
1165 break;
1166 case 1:
1167 s->range_table = &range_iso813_1_2_ai;
1168 break;
1169 case 2:
1170 s->range_table = &range_iso813_2_ai;
1171 devpriv->range_correction = 1;
1172 break;
1173 case 3:
1174 s->range_table = &range_iso813_2_2_ai;
1175 devpriv->range_correction = 1;
1176 break;
1177 default:
1178 s->range_table = &range_iso813_1_ai;
1179 break;
1180 }
1181 break;
1182 case boardACL8113:
1183 switch (it->options[1]) {
1184 case 0:
1185 s->range_table = &range_acl8113_1_ai;
1186 break;
1187 case 1:
1188 s->range_table = &range_acl8113_1_2_ai;
1189 break;
1190 case 2:
1191 s->range_table = &range_acl8113_2_ai;
1192 devpriv->range_correction = 1;
1193 break;
1194 case 3:
1195 s->range_table = &range_acl8113_2_2_ai;
1196 devpriv->range_correction = 1;
1197 break;
1198 default:
1199 s->range_table = &range_acl8113_1_ai;
1200 break;
1201 }
1202 break;
1203 }
1204}
1205
1206static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1207{
1208 const struct pcl812_board *board = dev->board_ptr;
1209 struct pcl812_private *devpriv;
1210 struct comedi_subdevice *s;
1211 int n_subdevices;
1212 int subdev;
1213 int ret;
1214 int i;
1215
1216 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1217 if (!devpriv)
1218 return -ENOMEM;
1219
1220 ret = comedi_request_region(dev, it->options[0], 0x10);
1221 if (ret)
1222 return ret;
1223
1224 if ((1 << it->options[1]) & board->IRQbits) {
1225 ret = request_irq(it->options[1], pcl812_interrupt, 0,
1226 dev->board_name, dev);
1227 if (ret == 0)
1228 dev->irq = it->options[1];
1229 }
1230
1231
1232 if (dev->irq && board->has_dma &&
1233 (it->options[2] == 3 || it->options[2] == 1)) {
1234 ret = request_dma(it->options[2], dev->board_name);
1235 if (ret) {
1236 dev_err(dev->class_dev,
1237 "unable to request DMA channel %d\n",
1238 it->options[2]);
1239 return -EBUSY;
1240 }
1241 devpriv->dma = it->options[2];
1242
1243 devpriv->dmapages = 1;
1244 devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
1245
1246 for (i = 0; i < 2; i++) {
1247 unsigned long dmabuf;
1248
1249 dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
1250 if (!dmabuf)
1251 return -ENOMEM;
1252
1253 devpriv->dmabuf[i] = dmabuf;
1254 devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
1255 }
1256 }
1257
1258
1259 switch (board->board_type) {
1260 case boardA821:
1261 if (it->options[2] == 1)
1262 devpriv->use_diff = 1;
1263 break;
1264 case boardACL8112:
1265 case boardACL8216:
1266 if (it->options[4] == 1)
1267 devpriv->use_diff = 1;
1268 break;
1269 }
1270
1271 n_subdevices = 1;
1272 if (board->n_aochan > 0)
1273 n_subdevices++;
1274 if (board->has_dio)
1275 n_subdevices += 2;
1276
1277 ret = comedi_alloc_subdevices(dev, n_subdevices);
1278 if (ret)
1279 return ret;
1280
1281 subdev = 0;
1282
1283
1284 s = &dev->subdevices[subdev];
1285 s->type = COMEDI_SUBD_AI;
1286 s->subdev_flags = SDF_READABLE;
1287 if (devpriv->use_diff) {
1288 s->subdev_flags |= SDF_DIFF;
1289 s->n_chan = board->n_aichan / 2;
1290 } else {
1291 s->subdev_flags |= SDF_GROUND;
1292 s->n_chan = board->n_aichan;
1293 }
1294 s->maxdata = board->has_16bit_ai ? 0xffff : 0x0fff;
1295
1296 pcl812_set_ai_range_table(dev, s, it);
1297
1298 s->insn_read = pcl812_ai_insn_read;
1299
1300 if (dev->irq) {
1301 dev->read_subdev = s;
1302 s->subdev_flags |= SDF_CMD_READ;
1303 s->len_chanlist = MAX_CHANLIST_LEN;
1304 s->do_cmdtest = pcl812_ai_cmdtest;
1305 s->do_cmd = pcl812_ai_cmd;
1306 s->poll = pcl812_ai_poll;
1307 s->cancel = pcl812_ai_cancel;
1308 }
1309
1310 devpriv->use_mpc508 = board->has_mpc508_mux;
1311
1312 subdev++;
1313
1314
1315 if (board->n_aochan > 0) {
1316 s = &dev->subdevices[subdev];
1317 s->type = COMEDI_SUBD_AO;
1318 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1319 s->n_chan = board->n_aochan;
1320 s->maxdata = 0xfff;
1321 s->range_table = &range_unipolar5;
1322 switch (board->board_type) {
1323 case boardA821:
1324 if (it->options[3] == 1)
1325 s->range_table = &range_unipolar10;
1326 break;
1327 case boardPCL812:
1328 case boardACL8112:
1329 case boardPCL812PG:
1330 case boardACL8216:
1331 if (it->options[5] == 1)
1332 s->range_table = &range_unipolar10;
1333 if (it->options[5] == 2)
1334 s->range_table = &range_unknown;
1335 break;
1336 }
1337 s->insn_write = pcl812_ao_insn_write;
1338 s->insn_read = comedi_readback_insn_read;
1339
1340 ret = comedi_alloc_subdev_readback(s);
1341 if (ret)
1342 return ret;
1343
1344 subdev++;
1345 }
1346
1347 if (board->has_dio) {
1348
1349 s = &dev->subdevices[subdev];
1350 s->type = COMEDI_SUBD_DI;
1351 s->subdev_flags = SDF_READABLE;
1352 s->n_chan = 16;
1353 s->maxdata = 1;
1354 s->range_table = &range_digital;
1355 s->insn_bits = pcl812_di_insn_bits;
1356 subdev++;
1357
1358
1359 s = &dev->subdevices[subdev];
1360 s->type = COMEDI_SUBD_DO;
1361 s->subdev_flags = SDF_WRITABLE;
1362 s->n_chan = 16;
1363 s->maxdata = 1;
1364 s->range_table = &range_digital;
1365 s->insn_bits = pcl812_do_insn_bits;
1366 subdev++;
1367 }
1368
1369 switch (board->board_type) {
1370 case boardACL8216:
1371 case boardPCL812PG:
1372 case boardPCL812:
1373 case boardACL8112:
1374 devpriv->max_812_ai_mode0_rangewait = 1;
1375 if (it->options[3] > 0)
1376
1377 devpriv->use_ext_trg = 1;
1378 break;
1379 case boardA821:
1380 devpriv->max_812_ai_mode0_rangewait = 1;
1381 devpriv->mode_reg_int = (dev->irq << 4) & 0xf0;
1382 break;
1383 case boardPCL813B:
1384 case boardPCL813:
1385 case boardISO813:
1386 case boardACL8113:
1387
1388 devpriv->max_812_ai_mode0_rangewait = 5;
1389 break;
1390 }
1391
1392 pcl812_reset(dev);
1393
1394 return 0;
1395}
1396
1397static void pcl812_detach(struct comedi_device *dev)
1398{
1399 struct pcl812_private *devpriv = dev->private;
1400
1401 if (devpriv) {
1402 if (devpriv->dmabuf[0])
1403 free_pages(devpriv->dmabuf[0], devpriv->dmapages);
1404 if (devpriv->dmabuf[1])
1405 free_pages(devpriv->dmabuf[1], devpriv->dmapages);
1406 if (devpriv->dma)
1407 free_dma(devpriv->dma);
1408 }
1409 comedi_legacy_detach(dev);
1410}
1411
1412static struct comedi_driver pcl812_driver = {
1413 .driver_name = "pcl812",
1414 .module = THIS_MODULE,
1415 .attach = pcl812_attach,
1416 .detach = pcl812_detach,
1417 .board_name = &boardtypes[0].name,
1418 .num_names = ARRAY_SIZE(boardtypes),
1419 .offset = sizeof(struct pcl812_board),
1420};
1421module_comedi_driver(pcl812_driver);
1422
1423MODULE_AUTHOR("Comedi http://www.comedi.org");
1424MODULE_DESCRIPTION("Comedi low-level driver");
1425MODULE_LICENSE("GPL");
1426