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#include <linux/module.h>
106#include <linux/pci.h>
107#include <linux/interrupt.h>
108#include <linux/slab.h>
109
110#include "../comedidev.h"
111
112#include "comedi_fc.h"
113#include "8253.h"
114
115
116
117
118#define PCI224_Z2_CT0 0x14
119#define PCI224_Z2_CT1 0x15
120#define PCI224_Z2_CT2 0x16
121#define PCI224_Z2_CTC 0x17
122#define PCI224_ZCLK_SCE 0x1A
123#define PCI224_ZGAT_SCE 0x1D
124#define PCI224_INT_SCE 0x1E
125
126
127
128
129
130#define PCI224_DACDATA 0x00
131#define PCI224_SOFTTRIG 0x00
132#define PCI224_DACCON 0x02
133#define PCI224_FIFOSIZ 0x04
134#define PCI224_DACCEN 0x06
135
136
137
138
139
140#define PCI224_DACCON_TRIG_MASK (7 << 0)
141#define PCI224_DACCON_TRIG_NONE (0 << 0)
142#define PCI224_DACCON_TRIG_SW (1 << 0)
143#define PCI224_DACCON_TRIG_EXTP (2 << 0)
144#define PCI224_DACCON_TRIG_EXTN (3 << 0)
145#define PCI224_DACCON_TRIG_Z2CT0 (4 << 0)
146#define PCI224_DACCON_TRIG_Z2CT1 (5 << 0)
147#define PCI224_DACCON_TRIG_Z2CT2 (6 << 0)
148
149#define PCI224_DACCON_POLAR_MASK (1 << 3)
150#define PCI224_DACCON_POLAR_UNI (0 << 3)
151#define PCI224_DACCON_POLAR_BI (1 << 3)
152
153#define PCI224_DACCON_VREF_MASK (3 << 4)
154#define PCI224_DACCON_VREF_1_25 (0 << 4)
155#define PCI224_DACCON_VREF_2_5 (1 << 4)
156#define PCI224_DACCON_VREF_5 (2 << 4)
157#define PCI224_DACCON_VREF_10 (3 << 4)
158
159#define PCI224_DACCON_FIFOWRAP (1 << 7)
160
161#define PCI224_DACCON_FIFOENAB (1 << 8)
162
163#define PCI224_DACCON_FIFOINTR_MASK (7 << 9)
164#define PCI224_DACCON_FIFOINTR_EMPTY (0 << 9)
165#define PCI224_DACCON_FIFOINTR_NEMPTY (1 << 9)
166#define PCI224_DACCON_FIFOINTR_NHALF (2 << 9)
167#define PCI224_DACCON_FIFOINTR_HALF (3 << 9)
168#define PCI224_DACCON_FIFOINTR_NFULL (4 << 9)
169#define PCI224_DACCON_FIFOINTR_FULL (5 << 9)
170
171#define PCI224_DACCON_FIFOFL_MASK (7 << 12)
172#define PCI224_DACCON_FIFOFL_EMPTY (1 << 12)
173#define PCI224_DACCON_FIFOFL_ONETOHALF (0 << 12)
174#define PCI224_DACCON_FIFOFL_HALFTOFULL (4 << 12)
175#define PCI224_DACCON_FIFOFL_FULL (6 << 12)
176
177#define PCI224_DACCON_BUSY (1 << 15)
178
179#define PCI224_DACCON_FIFORESET (1 << 12)
180
181#define PCI224_DACCON_GLOBALRESET (1 << 13)
182
183
184
185
186#define PCI224_FIFO_SIZE 4096
187
188
189
190
191
192
193#define PCI224_FIFO_ROOM_EMPTY PCI224_FIFO_SIZE
194#define PCI224_FIFO_ROOM_ONETOHALF (PCI224_FIFO_SIZE / 2)
195#define PCI224_FIFO_ROOM_HALFTOFULL 1
196#define PCI224_FIFO_ROOM_FULL 0
197
198
199
200
201#define CLK_CLK 0
202#define CLK_10MHZ 1
203#define CLK_1MHZ 2
204#define CLK_100KHZ 3
205#define CLK_10KHZ 4
206#define CLK_1KHZ 5
207#define CLK_OUTNM1 6
208#define CLK_EXT 7
209
210#define CLK_CONFIG(chan, src) ((((chan) & 3) << 3) | ((src) & 7))
211
212
213
214
215#define GAT_VCC 0
216#define GAT_GND 1
217#define GAT_EXT 2
218#define GAT_NOUTNM2 3
219
220#define GAT_CONFIG(chan, src) ((((chan) & 3) << 3) | ((src) & 7))
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237#define PCI224_INTR_EXT 0x01
238#define PCI224_INTR_DAC 0x04
239#define PCI224_INTR_Z2CT1 0x20
240
241#define PCI224_INTR_EDGE_BITS (PCI224_INTR_EXT | PCI224_INTR_Z2CT1)
242#define PCI224_INTR_LEVEL_BITS PCI224_INTR_DACFIFO
243
244
245
246
247
248
249#define COMBINE(old, new, mask) (((old) & ~(mask)) | ((new) & (mask)))
250
251
252#define THISCPU smp_processor_id()
253
254
255#define AO_CMD_STARTED 0
256
257
258
259
260
261
262
263
264
265
266
267
268
269static const struct comedi_lrange range_pci224 = {
270 10, {
271
272 BIP_RANGE(10),
273 BIP_RANGE(5),
274 BIP_RANGE(2.5),
275 BIP_RANGE(1.25),
276 UNI_RANGE(10),
277 UNI_RANGE(5),
278 UNI_RANGE(2.5),
279 UNI_RANGE(1.25),
280
281 RANGE_ext(-1, 1),
282 RANGE_ext(0, 1),
283 }
284};
285
286static const unsigned short hwrange_pci224[10] = {
287
288 PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_10,
289 PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_5,
290 PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_2_5,
291 PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_1_25,
292 PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_10,
293 PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_5,
294 PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_2_5,
295 PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_1_25,
296
297 PCI224_DACCON_POLAR_BI,
298 PCI224_DACCON_POLAR_UNI,
299};
300
301
302static const unsigned char range_check_pci224[10] = {
303 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
304};
305
306
307
308
309
310
311
312
313static const struct comedi_lrange range_pci234 = {
314 4, {
315
316 BIP_RANGE(10),
317
318 BIP_RANGE(5),
319
320 RANGE_ext(-2, 2),
321
322 RANGE_ext(-1, 1),
323 }
324};
325
326
327static const unsigned short hwrange_pci234[4] = {
328 PCI224_DACCON_POLAR_BI,
329 PCI224_DACCON_POLAR_BI,
330 PCI224_DACCON_POLAR_BI,
331 PCI224_DACCON_POLAR_BI,
332};
333
334
335static const unsigned char range_check_pci234[4] = {
336 0, 0, 1, 1,
337};
338
339
340
341
342
343enum pci224_model { pci224_model, pci234_model };
344
345struct pci224_board {
346 const char *name;
347 unsigned int ao_chans;
348 unsigned int ao_bits;
349 const struct comedi_lrange *ao_range;
350 const unsigned short *ao_hwrange;
351 const unsigned char *ao_range_check;
352};
353
354static const struct pci224_board pci224_boards[] = {
355 [pci224_model] = {
356 .name = "pci224",
357 .ao_chans = 16,
358 .ao_bits = 12,
359 .ao_range = &range_pci224,
360 .ao_hwrange = &hwrange_pci224[0],
361 .ao_range_check = &range_check_pci224[0],
362 },
363 [pci234_model] = {
364 .name = "pci234",
365 .ao_chans = 4,
366 .ao_bits = 16,
367 .ao_range = &range_pci234,
368 .ao_hwrange = &hwrange_pci234[0],
369 .ao_range_check = &range_check_pci234[0],
370 },
371};
372
373struct pci224_private {
374 unsigned long iobase1;
375 unsigned long state;
376 spinlock_t ao_spinlock;
377 unsigned short *ao_scan_vals;
378 unsigned char *ao_scan_order;
379 int intr_cpuid;
380 short intr_running;
381 unsigned short daccon;
382 unsigned int cached_div1;
383 unsigned int cached_div2;
384 unsigned short ao_enab;
385 unsigned char intsce;
386};
387
388
389
390
391static void
392pci224_ao_set_data(struct comedi_device *dev, int chan, int range,
393 unsigned int data)
394{
395 const struct pci224_board *thisboard = dev->board_ptr;
396 struct pci224_private *devpriv = dev->private;
397 unsigned short mangled;
398
399
400 outw(1 << chan, dev->iobase + PCI224_DACCEN);
401
402 devpriv->daccon = COMBINE(devpriv->daccon, thisboard->ao_hwrange[range],
403 PCI224_DACCON_POLAR_MASK |
404 PCI224_DACCON_VREF_MASK);
405 outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
406 dev->iobase + PCI224_DACCON);
407
408
409
410
411
412 mangled = (unsigned short)data << (16 - thisboard->ao_bits);
413 if ((devpriv->daccon & PCI224_DACCON_POLAR_MASK) ==
414 PCI224_DACCON_POLAR_BI) {
415 mangled ^= 0x8000;
416 }
417
418 outw(mangled, dev->iobase + PCI224_DACDATA);
419
420 inw(dev->iobase + PCI224_SOFTTRIG);
421}
422
423static int pci224_ao_insn_write(struct comedi_device *dev,
424 struct comedi_subdevice *s,
425 struct comedi_insn *insn,
426 unsigned int *data)
427{
428 unsigned int chan = CR_CHAN(insn->chanspec);
429 unsigned int range = CR_RANGE(insn->chanspec);
430 unsigned int val = s->readback[chan];
431 int i;
432
433 for (i = 0; i < insn->n; i++) {
434 val = data[i];
435 pci224_ao_set_data(dev, chan, range, val);
436 }
437 s->readback[chan] = val;
438
439 return insn->n;
440}
441
442
443
444
445static void pci224_ao_stop(struct comedi_device *dev,
446 struct comedi_subdevice *s)
447{
448 struct pci224_private *devpriv = dev->private;
449 unsigned long flags;
450
451 if (!test_and_clear_bit(AO_CMD_STARTED, &devpriv->state))
452 return;
453
454
455 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
456
457 devpriv->intsce = 0;
458 outb(0, devpriv->iobase1 + PCI224_INT_SCE);
459
460
461
462
463
464
465
466
467
468
469
470 while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
471 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
472 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
473 }
474 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
475
476 outw(0, dev->iobase + PCI224_DACCEN);
477 devpriv->daccon =
478 COMBINE(devpriv->daccon,
479 PCI224_DACCON_TRIG_SW | PCI224_DACCON_FIFOINTR_EMPTY,
480 PCI224_DACCON_TRIG_MASK | PCI224_DACCON_FIFOINTR_MASK);
481 outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
482 dev->iobase + PCI224_DACCON);
483}
484
485
486
487
488static void pci224_ao_start(struct comedi_device *dev,
489 struct comedi_subdevice *s)
490{
491 struct pci224_private *devpriv = dev->private;
492 struct comedi_cmd *cmd = &s->async->cmd;
493 unsigned long flags;
494
495 set_bit(AO_CMD_STARTED, &devpriv->state);
496
497
498 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
499 if (cmd->stop_src == TRIG_EXT)
500 devpriv->intsce = PCI224_INTR_EXT | PCI224_INTR_DAC;
501 else
502 devpriv->intsce = PCI224_INTR_DAC;
503
504 outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE);
505 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
506}
507
508
509
510
511static void pci224_ao_handle_fifo(struct comedi_device *dev,
512 struct comedi_subdevice *s)
513{
514 struct pci224_private *devpriv = dev->private;
515 struct comedi_cmd *cmd = &s->async->cmd;
516 unsigned int num_scans = comedi_nscans_left(s, 0);
517 unsigned int room;
518 unsigned short dacstat;
519 unsigned int i, n;
520
521
522 dacstat = inw(dev->iobase + PCI224_DACCON);
523 switch (dacstat & PCI224_DACCON_FIFOFL_MASK) {
524 case PCI224_DACCON_FIFOFL_EMPTY:
525 room = PCI224_FIFO_ROOM_EMPTY;
526 if (cmd->stop_src == TRIG_COUNT &&
527 s->async->scans_done >= cmd->stop_arg) {
528
529 s->async->events |= COMEDI_CB_EOA;
530 comedi_handle_events(dev, s);
531 return;
532 }
533 break;
534 case PCI224_DACCON_FIFOFL_ONETOHALF:
535 room = PCI224_FIFO_ROOM_ONETOHALF;
536 break;
537 case PCI224_DACCON_FIFOFL_HALFTOFULL:
538 room = PCI224_FIFO_ROOM_HALFTOFULL;
539 break;
540 default:
541 room = PCI224_FIFO_ROOM_FULL;
542 break;
543 }
544 if (room >= PCI224_FIFO_ROOM_ONETOHALF) {
545
546 if (num_scans == 0) {
547
548 dev_err(dev->class_dev, "AO buffer underrun\n");
549 s->async->events |= COMEDI_CB_OVERFLOW;
550 }
551 }
552
553 room /= cmd->chanlist_len;
554
555
556 if (num_scans > room)
557 num_scans = room;
558
559
560 for (n = 0; n < num_scans; n++) {
561 comedi_buf_read_samples(s, &devpriv->ao_scan_vals[0],
562 cmd->chanlist_len);
563 for (i = 0; i < cmd->chanlist_len; i++) {
564 outw(devpriv->ao_scan_vals[devpriv->ao_scan_order[i]],
565 dev->iobase + PCI224_DACDATA);
566 }
567 }
568 if (cmd->stop_src == TRIG_COUNT &&
569 s->async->scans_done >= cmd->stop_arg) {
570
571
572
573
574 devpriv->daccon = COMBINE(devpriv->daccon,
575 PCI224_DACCON_FIFOINTR_EMPTY,
576 PCI224_DACCON_FIFOINTR_MASK);
577 outw(devpriv->daccon, dev->iobase + PCI224_DACCON);
578 }
579 if ((devpriv->daccon & PCI224_DACCON_TRIG_MASK) ==
580 PCI224_DACCON_TRIG_NONE) {
581 unsigned short trig;
582
583
584
585
586
587
588
589
590
591
592
593
594
595 if (cmd->scan_begin_src == TRIG_TIMER) {
596 trig = PCI224_DACCON_TRIG_Z2CT0;
597 } else {
598
599 if (cmd->scan_begin_arg & CR_INVERT)
600 trig = PCI224_DACCON_TRIG_EXTN;
601 else
602 trig = PCI224_DACCON_TRIG_EXTP;
603 }
604 devpriv->daccon =
605 COMBINE(devpriv->daccon, trig, PCI224_DACCON_TRIG_MASK);
606 outw(devpriv->daccon, dev->iobase + PCI224_DACCON);
607 }
608
609 comedi_handle_events(dev, s);
610}
611
612static int pci224_ao_inttrig_start(struct comedi_device *dev,
613 struct comedi_subdevice *s,
614 unsigned int trig_num)
615{
616 struct comedi_cmd *cmd = &s->async->cmd;
617
618 if (trig_num != cmd->start_arg)
619 return -EINVAL;
620
621 s->async->inttrig = NULL;
622 pci224_ao_start(dev, s);
623
624 return 1;
625}
626
627static int pci224_ao_check_chanlist(struct comedi_device *dev,
628 struct comedi_subdevice *s,
629 struct comedi_cmd *cmd)
630{
631 const struct pci224_board *thisboard = dev->board_ptr;
632 unsigned int range_check_0;
633 unsigned int chan_mask = 0;
634 int i;
635
636 range_check_0 = thisboard->ao_range_check[CR_RANGE(cmd->chanlist[0])];
637 for (i = 0; i < cmd->chanlist_len; i++) {
638 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
639
640 if (chan_mask & (1 << chan)) {
641 dev_dbg(dev->class_dev,
642 "%s: entries in chanlist must contain no duplicate channels\n",
643 __func__);
644 return -EINVAL;
645 }
646 chan_mask |= 1 << chan;
647
648 if (thisboard->ao_range_check[CR_RANGE(cmd->chanlist[i])] !=
649 range_check_0) {
650 dev_dbg(dev->class_dev,
651 "%s: entries in chanlist have incompatible ranges\n",
652 __func__);
653 return -EINVAL;
654 }
655 }
656
657 return 0;
658}
659
660#define MAX_SCAN_PERIOD 0xFFFFFFFFU
661#define MIN_SCAN_PERIOD 2500
662#define CONVERT_PERIOD 625
663
664
665
666
667static int
668pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
669 struct comedi_cmd *cmd)
670{
671 struct pci224_private *devpriv = dev->private;
672 int err = 0;
673 unsigned int arg;
674
675
676
677 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT | TRIG_EXT);
678 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
679 TRIG_EXT | TRIG_TIMER);
680 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
681 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
682 err |= cfc_check_trigger_src(&cmd->stop_src,
683 TRIG_COUNT | TRIG_EXT | TRIG_NONE);
684
685 if (err)
686 return 1;
687
688
689
690 err |= cfc_check_trigger_is_unique(cmd->start_src);
691 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
692 err |= cfc_check_trigger_is_unique(cmd->stop_src);
693
694
695
696
697
698
699
700 arg = 0;
701 if (cmd->start_src & TRIG_EXT)
702 arg++;
703 if (cmd->scan_begin_src & TRIG_EXT)
704 arg++;
705 if (cmd->stop_src & TRIG_EXT)
706 arg++;
707 if (arg > 1)
708 err |= -EINVAL;
709
710 if (err)
711 return 2;
712
713
714
715 switch (cmd->start_src) {
716 case TRIG_INT:
717 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
718 break;
719 case TRIG_EXT:
720
721 if (cmd->start_arg & ~CR_FLAGS_MASK) {
722 cmd->start_arg =
723 COMBINE(cmd->start_arg, 0, ~CR_FLAGS_MASK);
724 err |= -EINVAL;
725 }
726
727 if (cmd->start_arg & CR_FLAGS_MASK & ~CR_EDGE) {
728 cmd->start_arg = COMBINE(cmd->start_arg, 0,
729 CR_FLAGS_MASK & ~CR_EDGE);
730 err |= -EINVAL;
731 }
732 break;
733 }
734
735 switch (cmd->scan_begin_src) {
736 case TRIG_TIMER:
737 err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
738 MAX_SCAN_PERIOD);
739
740 arg = cmd->chanlist_len * CONVERT_PERIOD;
741 if (arg < MIN_SCAN_PERIOD)
742 arg = MIN_SCAN_PERIOD;
743 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, arg);
744 break;
745 case TRIG_EXT:
746
747 if (cmd->scan_begin_arg & ~CR_FLAGS_MASK) {
748 cmd->scan_begin_arg =
749 COMBINE(cmd->scan_begin_arg, 0, ~CR_FLAGS_MASK);
750 err |= -EINVAL;
751 }
752
753 if (cmd->scan_begin_arg & CR_FLAGS_MASK &
754 ~(CR_EDGE | CR_INVERT)) {
755 cmd->scan_begin_arg =
756 COMBINE(cmd->scan_begin_arg, 0,
757 CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT));
758 err |= -EINVAL;
759 }
760 break;
761 }
762
763 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
764 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
765
766 switch (cmd->stop_src) {
767 case TRIG_COUNT:
768 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
769 break;
770 case TRIG_EXT:
771
772 if (cmd->stop_arg & ~CR_FLAGS_MASK) {
773 cmd->stop_arg =
774 COMBINE(cmd->stop_arg, 0, ~CR_FLAGS_MASK);
775 err |= -EINVAL;
776 }
777
778 if (cmd->stop_arg & CR_FLAGS_MASK & ~CR_EDGE) {
779 cmd->stop_arg =
780 COMBINE(cmd->stop_arg, 0, CR_FLAGS_MASK & ~CR_EDGE);
781 }
782 break;
783 case TRIG_NONE:
784 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
785 break;
786 }
787
788 if (err)
789 return 3;
790
791
792
793 if (cmd->scan_begin_src == TRIG_TIMER) {
794 arg = cmd->scan_begin_arg;
795
796 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
797 &devpriv->cached_div1,
798 &devpriv->cached_div2,
799 &arg, cmd->flags);
800 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
801 }
802
803 if (err)
804 return 4;
805
806
807 if (cmd->chanlist && cmd->chanlist_len > 0)
808 err |= pci224_ao_check_chanlist(dev, s, cmd);
809
810 if (err)
811 return 5;
812
813 return 0;
814}
815
816static void pci224_ao_start_pacer(struct comedi_device *dev,
817 struct comedi_subdevice *s)
818{
819 struct pci224_private *devpriv = dev->private;
820 unsigned long timer_base = devpriv->iobase1 + PCI224_Z2_CT0;
821
822
823
824
825
826
827 outb(GAT_CONFIG(0, GAT_VCC), devpriv->iobase1 + PCI224_ZGAT_SCE);
828
829
830 outb(GAT_CONFIG(2, GAT_VCC), devpriv->iobase1 + PCI224_ZGAT_SCE);
831
832 outb(CLK_CONFIG(2, CLK_10MHZ), devpriv->iobase1 + PCI224_ZCLK_SCE);
833
834 i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
835 i8254_write(timer_base, 0, 2, devpriv->cached_div1);
836
837 outb(CLK_CONFIG(0, CLK_OUTNM1), devpriv->iobase1 + PCI224_ZCLK_SCE);
838
839 i8254_set_mode(timer_base, 0, 0, I8254_MODE2 | I8254_BINARY);
840 i8254_write(timer_base, 0, 0, devpriv->cached_div2);
841}
842
843static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
844{
845 const struct pci224_board *thisboard = dev->board_ptr;
846 struct pci224_private *devpriv = dev->private;
847 struct comedi_cmd *cmd = &s->async->cmd;
848 int range;
849 unsigned int i, j;
850 unsigned int ch;
851 unsigned int rank;
852 unsigned long flags;
853
854
855 if (cmd->chanlist == NULL || cmd->chanlist_len == 0)
856 return -EINVAL;
857
858
859
860 devpriv->ao_enab = 0;
861
862 for (i = 0; i < cmd->chanlist_len; i++) {
863 ch = CR_CHAN(cmd->chanlist[i]);
864 devpriv->ao_enab |= 1U << ch;
865 rank = 0;
866 for (j = 0; j < cmd->chanlist_len; j++) {
867 if (CR_CHAN(cmd->chanlist[j]) < ch)
868 rank++;
869 }
870 devpriv->ao_scan_order[rank] = i;
871 }
872
873
874 outw(devpriv->ao_enab, dev->iobase + PCI224_DACCEN);
875
876
877 range = CR_RANGE(cmd->chanlist[0]);
878
879
880
881
882
883
884
885
886
887 devpriv->daccon =
888 COMBINE(devpriv->daccon,
889 thisboard->ao_hwrange[range] | PCI224_DACCON_TRIG_NONE |
890 PCI224_DACCON_FIFOINTR_NHALF,
891 PCI224_DACCON_POLAR_MASK | PCI224_DACCON_VREF_MASK |
892 PCI224_DACCON_TRIG_MASK | PCI224_DACCON_FIFOINTR_MASK);
893 outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
894 dev->iobase + PCI224_DACCON);
895
896 if (cmd->scan_begin_src == TRIG_TIMER)
897 pci224_ao_start_pacer(dev, s);
898
899 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
900 if (cmd->start_src == TRIG_INT) {
901 s->async->inttrig = pci224_ao_inttrig_start;
902 } else {
903
904 devpriv->intsce |= PCI224_INTR_EXT;
905 outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE);
906 }
907 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
908
909 return 0;
910}
911
912
913
914
915static int pci224_ao_cancel(struct comedi_device *dev,
916 struct comedi_subdevice *s)
917{
918 pci224_ao_stop(dev, s);
919 return 0;
920}
921
922
923
924
925static void
926pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s,
927 void *data, unsigned int num_bytes, unsigned int chan_index)
928{
929 const struct pci224_board *thisboard = dev->board_ptr;
930 struct comedi_cmd *cmd = &s->async->cmd;
931 unsigned short *array = data;
932 unsigned int length = num_bytes / sizeof(*array);
933 unsigned int offset;
934 unsigned int shift;
935 unsigned int i;
936
937
938 shift = 16 - thisboard->ao_bits;
939
940 if ((thisboard->ao_hwrange[CR_RANGE(cmd->chanlist[0])] &
941 PCI224_DACCON_POLAR_MASK) == PCI224_DACCON_POLAR_UNI) {
942
943 offset = 0;
944 } else {
945
946 offset = 32768;
947 }
948
949 for (i = 0; i < length; i++)
950 array[i] = (array[i] << shift) - offset;
951}
952
953
954
955
956static irqreturn_t pci224_interrupt(int irq, void *d)
957{
958 struct comedi_device *dev = d;
959 struct pci224_private *devpriv = dev->private;
960 struct comedi_subdevice *s = dev->write_subdev;
961 struct comedi_cmd *cmd;
962 unsigned char intstat, valid_intstat;
963 unsigned char curenab;
964 int retval = 0;
965 unsigned long flags;
966
967 intstat = inb(devpriv->iobase1 + PCI224_INT_SCE) & 0x3F;
968 if (intstat) {
969 retval = 1;
970 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
971 valid_intstat = devpriv->intsce & intstat;
972
973 curenab = devpriv->intsce & ~intstat;
974 outb(curenab, devpriv->iobase1 + PCI224_INT_SCE);
975 devpriv->intr_running = 1;
976 devpriv->intr_cpuid = THISCPU;
977 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
978 if (valid_intstat) {
979 cmd = &s->async->cmd;
980 if (valid_intstat & PCI224_INTR_EXT) {
981 devpriv->intsce &= ~PCI224_INTR_EXT;
982 if (cmd->start_src == TRIG_EXT)
983 pci224_ao_start(dev, s);
984 else if (cmd->stop_src == TRIG_EXT)
985 pci224_ao_stop(dev, s);
986 }
987 if (valid_intstat & PCI224_INTR_DAC)
988 pci224_ao_handle_fifo(dev, s);
989 }
990
991 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
992 if (curenab != devpriv->intsce) {
993 outb(devpriv->intsce,
994 devpriv->iobase1 + PCI224_INT_SCE);
995 }
996 devpriv->intr_running = 0;
997 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
998 }
999 return IRQ_RETVAL(retval);
1000}
1001
1002static int
1003pci224_auto_attach(struct comedi_device *dev, unsigned long context_model)
1004{
1005 struct pci_dev *pci_dev = comedi_to_pci_dev(dev);
1006 const struct pci224_board *thisboard = NULL;
1007 struct pci224_private *devpriv;
1008 struct comedi_subdevice *s;
1009 unsigned int irq;
1010 int ret;
1011
1012 if (context_model < ARRAY_SIZE(pci224_boards))
1013 thisboard = &pci224_boards[context_model];
1014 if (!thisboard || !thisboard->name) {
1015 dev_err(dev->class_dev,
1016 "amplc_pci224: BUG! cannot determine board type!\n");
1017 return -EINVAL;
1018 }
1019 dev->board_ptr = thisboard;
1020 dev->board_name = thisboard->name;
1021
1022 dev_info(dev->class_dev, "amplc_pci224: attach pci %s - %s\n",
1023 pci_name(pci_dev), dev->board_name);
1024
1025 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1026 if (!devpriv)
1027 return -ENOMEM;
1028
1029 ret = comedi_pci_enable(dev);
1030 if (ret)
1031 return ret;
1032
1033 spin_lock_init(&devpriv->ao_spinlock);
1034
1035 devpriv->iobase1 = pci_resource_start(pci_dev, 2);
1036 dev->iobase = pci_resource_start(pci_dev, 3);
1037 irq = pci_dev->irq;
1038
1039
1040 devpriv->ao_scan_vals = kmalloc(sizeof(devpriv->ao_scan_vals[0]) *
1041 thisboard->ao_chans, GFP_KERNEL);
1042 if (!devpriv->ao_scan_vals)
1043 return -ENOMEM;
1044
1045
1046
1047 devpriv->ao_scan_order = kmalloc(sizeof(devpriv->ao_scan_order[0]) *
1048 thisboard->ao_chans, GFP_KERNEL);
1049 if (!devpriv->ao_scan_order)
1050 return -ENOMEM;
1051
1052
1053
1054 devpriv->intsce = 0;
1055 outb(0, devpriv->iobase1 + PCI224_INT_SCE);
1056
1057
1058 outw(PCI224_DACCON_GLOBALRESET, dev->iobase + PCI224_DACCON);
1059 outw(0, dev->iobase + PCI224_DACCEN);
1060 outw(0, dev->iobase + PCI224_FIFOSIZ);
1061 devpriv->daccon = PCI224_DACCON_TRIG_SW | PCI224_DACCON_POLAR_BI |
1062 PCI224_DACCON_FIFOENAB | PCI224_DACCON_FIFOINTR_EMPTY;
1063 outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
1064 dev->iobase + PCI224_DACCON);
1065
1066 ret = comedi_alloc_subdevices(dev, 1);
1067 if (ret)
1068 return ret;
1069
1070 s = &dev->subdevices[0];
1071
1072 s->type = COMEDI_SUBD_AO;
1073 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
1074 s->n_chan = thisboard->ao_chans;
1075 s->maxdata = (1 << thisboard->ao_bits) - 1;
1076 s->range_table = thisboard->ao_range;
1077 s->insn_write = pci224_ao_insn_write;
1078 s->len_chanlist = s->n_chan;
1079 dev->write_subdev = s;
1080 s->do_cmd = pci224_ao_cmd;
1081 s->do_cmdtest = pci224_ao_cmdtest;
1082 s->cancel = pci224_ao_cancel;
1083 s->munge = pci224_ao_munge;
1084
1085 ret = comedi_alloc_subdev_readback(s);
1086 if (ret)
1087 return ret;
1088
1089 if (irq) {
1090 ret = request_irq(irq, pci224_interrupt, IRQF_SHARED,
1091 dev->board_name, dev);
1092 if (ret < 0) {
1093 dev_err(dev->class_dev,
1094 "error! unable to allocate irq %u\n", irq);
1095 return ret;
1096 }
1097 dev->irq = irq;
1098 }
1099
1100 return 0;
1101}
1102
1103static void pci224_detach(struct comedi_device *dev)
1104{
1105 struct pci224_private *devpriv = dev->private;
1106
1107 comedi_pci_detach(dev);
1108 if (devpriv) {
1109 kfree(devpriv->ao_scan_vals);
1110 kfree(devpriv->ao_scan_order);
1111 }
1112}
1113
1114static struct comedi_driver amplc_pci224_driver = {
1115 .driver_name = "amplc_pci224",
1116 .module = THIS_MODULE,
1117 .detach = pci224_detach,
1118 .auto_attach = pci224_auto_attach,
1119 .board_name = &pci224_boards[0].name,
1120 .offset = sizeof(struct pci224_board),
1121 .num_names = ARRAY_SIZE(pci224_boards),
1122};
1123
1124static int amplc_pci224_pci_probe(struct pci_dev *dev,
1125 const struct pci_device_id *id)
1126{
1127 return comedi_pci_auto_config(dev, &lc_pci224_driver,
1128 id->driver_data);
1129}
1130
1131static const struct pci_device_id amplc_pci224_pci_table[] = {
1132 { PCI_VDEVICE(AMPLICON, 0x0007), pci224_model },
1133 { PCI_VDEVICE(AMPLICON, 0x0008), pci234_model },
1134 { 0 }
1135};
1136MODULE_DEVICE_TABLE(pci, amplc_pci224_pci_table);
1137
1138static struct pci_driver amplc_pci224_pci_driver = {
1139 .name = "amplc_pci224",
1140 .id_table = amplc_pci224_pci_table,
1141 .probe = amplc_pci224_pci_probe,
1142 .remove = comedi_pci_auto_unconfig,
1143};
1144module_comedi_pci_driver(amplc_pci224_driver, amplc_pci224_pci_driver);
1145
1146MODULE_AUTHOR("Comedi http://www.comedi.org");
1147MODULE_DESCRIPTION("Comedi driver for Amplicon PCI224 and PCI234 AO boards");
1148MODULE_LICENSE("GPL");
1149