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