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#include <linux/interrupt.h>
107
108#include "../comedidev.h"
109
110#include "comedi_pci.h"
111
112#include "comedi_fc.h"
113#include "8253.h"
114
115#define DRIVER_NAME "amplc_pci224"
116
117
118
119
120
121#define PCI_DEVICE_ID_AMPLICON_PCI224 0x0007
122#define PCI_DEVICE_ID_AMPLICON_PCI234 0x0008
123#define PCI_DEVICE_ID_INVALID 0xffff
124
125
126
127
128#define PCI224_IO1_SIZE 0x20
129#define PCI224_Z2_CT0 0x14
130#define PCI224_Z2_CT1 0x15
131#define PCI224_Z2_CT2 0x16
132#define PCI224_Z2_CTC 0x17
133#define PCI224_ZCLK_SCE 0x1A
134#define PCI224_ZGAT_SCE 0x1D
135#define PCI224_INT_SCE 0x1E
136
137
138
139
140
141#define PCI224_IO2_SIZE 0x10
142#define PCI224_DACDATA 0x00
143#define PCI224_SOFTTRIG 0x00
144#define PCI224_DACCON 0x02
145#define PCI224_FIFOSIZ 0x04
146#define PCI224_DACCEN 0x06
147
148
149
150
151
152#define PCI224_DACCON_TRIG_MASK (7 << 0)
153#define PCI224_DACCON_TRIG_NONE (0 << 0)
154#define PCI224_DACCON_TRIG_SW (1 << 0)
155#define PCI224_DACCON_TRIG_EXTP (2 << 0)
156#define PCI224_DACCON_TRIG_EXTN (3 << 0)
157#define PCI224_DACCON_TRIG_Z2CT0 (4 << 0)
158#define PCI224_DACCON_TRIG_Z2CT1 (5 << 0)
159#define PCI224_DACCON_TRIG_Z2CT2 (6 << 0)
160
161#define PCI224_DACCON_POLAR_MASK (1 << 3)
162#define PCI224_DACCON_POLAR_UNI (0 << 3)
163#define PCI224_DACCON_POLAR_BI (1 << 3)
164
165#define PCI224_DACCON_VREF_MASK (3 << 4)
166#define PCI224_DACCON_VREF_1_25 (0 << 4)
167#define PCI224_DACCON_VREF_2_5 (1 << 4)
168#define PCI224_DACCON_VREF_5 (2 << 4)
169#define PCI224_DACCON_VREF_10 (3 << 4)
170
171#define PCI224_DACCON_FIFOWRAP (1 << 7)
172
173#define PCI224_DACCON_FIFOENAB (1 << 8)
174
175#define PCI224_DACCON_FIFOINTR_MASK (7 << 9)
176#define PCI224_DACCON_FIFOINTR_EMPTY (0 << 9)
177#define PCI224_DACCON_FIFOINTR_NEMPTY (1 << 9)
178#define PCI224_DACCON_FIFOINTR_NHALF (2 << 9)
179#define PCI224_DACCON_FIFOINTR_HALF (3 << 9)
180#define PCI224_DACCON_FIFOINTR_NFULL (4 << 9)
181#define PCI224_DACCON_FIFOINTR_FULL (5 << 9)
182
183#define PCI224_DACCON_FIFOFL_MASK (7 << 12)
184#define PCI224_DACCON_FIFOFL_EMPTY (1 << 12)
185#define PCI224_DACCON_FIFOFL_ONETOHALF (0 << 12)
186#define PCI224_DACCON_FIFOFL_HALFTOFULL (4 << 12)
187#define PCI224_DACCON_FIFOFL_FULL (6 << 12)
188
189#define PCI224_DACCON_BUSY (1 << 15)
190
191#define PCI224_DACCON_FIFORESET (1 << 12)
192
193#define PCI224_DACCON_GLOBALRESET (1 << 13)
194
195
196
197
198#define PCI224_FIFO_SIZE 4096
199
200
201
202
203
204
205#define PCI224_FIFO_ROOM_EMPTY PCI224_FIFO_SIZE
206#define PCI224_FIFO_ROOM_ONETOHALF (PCI224_FIFO_SIZE / 2)
207#define PCI224_FIFO_ROOM_HALFTOFULL 1
208#define PCI224_FIFO_ROOM_FULL 0
209
210
211
212
213#define CLK_CLK 0
214#define CLK_10MHZ 1
215#define CLK_1MHZ 2
216#define CLK_100KHZ 3
217#define CLK_10KHZ 4
218#define CLK_1KHZ 5
219#define CLK_OUTNM1 6
220#define CLK_EXT 7
221
222#define CLK_CONFIG(chan, src) ((((chan) & 3) << 3) | ((src) & 7))
223
224#define TIMEBASE_10MHZ 100
225#define TIMEBASE_1MHZ 1000
226#define TIMEBASE_100KHZ 10000
227#define TIMEBASE_10KHZ 100000
228#define TIMEBASE_1KHZ 1000000
229
230
231
232
233#define GAT_VCC 0
234#define GAT_GND 1
235#define GAT_EXT 2
236#define GAT_NOUTNM2 3
237
238#define GAT_CONFIG(chan, src) ((((chan) & 3) << 3) | ((src) & 7))
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255#define PCI224_INTR_EXT 0x01
256#define PCI224_INTR_DAC 0x04
257#define PCI224_INTR_Z2CT1 0x20
258
259#define PCI224_INTR_EDGE_BITS (PCI224_INTR_EXT | PCI224_INTR_Z2CT1)
260#define PCI224_INTR_LEVEL_BITS PCI224_INTR_DACFIFO
261
262
263
264
265
266
267#define COMBINE(old, new, mask) (((old) & ~(mask)) | ((new) & (mask)))
268
269
270#define NULLFUNC 0
271
272
273#define THISCPU smp_processor_id()
274
275
276#define AO_CMD_STARTED 0
277
278
279
280
281
282
283static const struct comedi_lrange range_pci224_internal = {
284 8,
285 {
286 BIP_RANGE(10),
287 BIP_RANGE(5),
288 BIP_RANGE(2.5),
289 BIP_RANGE(1.25),
290 UNI_RANGE(10),
291 UNI_RANGE(5),
292 UNI_RANGE(2.5),
293 UNI_RANGE(1.25),
294 }
295};
296
297static const unsigned short hwrange_pci224_internal[8] = {
298 PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_10,
299 PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_5,
300 PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_2_5,
301 PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_1_25,
302 PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_10,
303 PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_5,
304 PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_2_5,
305 PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_1_25,
306};
307
308
309static const struct comedi_lrange range_pci224_external = {
310 2,
311 {
312 RANGE_ext(-1, 1),
313 RANGE_ext(0, 1),
314 }
315};
316
317static const unsigned short hwrange_pci224_external[2] = {
318 PCI224_DACCON_POLAR_BI,
319 PCI224_DACCON_POLAR_UNI,
320};
321
322
323
324static const struct comedi_lrange range_pci234_ext2 = {
325 1,
326 {
327 RANGE_ext(-2, 2),
328 }
329};
330
331
332
333static const struct comedi_lrange range_pci234_ext = {
334 1,
335 {
336 RANGE_ext(-1, 1),
337 }
338};
339
340
341static const unsigned short hwrange_pci234[1] = {
342 PCI224_DACCON_POLAR_BI,
343};
344
345
346
347
348
349enum pci224_model { any_model, pci224_model, pci234_model };
350
351struct pci224_board {
352 const char *name;
353 unsigned short devid;
354 enum pci224_model model;
355 unsigned int ao_chans;
356 unsigned int ao_bits;
357};
358
359static const struct pci224_board pci224_boards[] = {
360 {
361 .name = "pci224",
362 .devid = PCI_DEVICE_ID_AMPLICON_PCI224,
363 .model = pci224_model,
364 .ao_chans = 16,
365 .ao_bits = 12,
366 },
367 {
368 .name = "pci234",
369 .devid = PCI_DEVICE_ID_AMPLICON_PCI234,
370 .model = pci234_model,
371 .ao_chans = 4,
372 .ao_bits = 16,
373 },
374 {
375 .name = DRIVER_NAME,
376 .devid = PCI_DEVICE_ID_INVALID,
377 .model = any_model,
378 },
379};
380
381
382
383
384
385static DEFINE_PCI_DEVICE_TABLE(pci224_pci_table) = {
386 {
387 PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224,
388 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
389 PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234,
390 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
391 0}
392};
393
394MODULE_DEVICE_TABLE(pci, pci224_pci_table);
395
396
397
398
399#define thisboard ((struct pci224_board *)dev->board_ptr)
400
401
402
403
404struct pci224_private {
405 struct pci_dev *pci_dev;
406 const unsigned short *hwrange;
407 unsigned long iobase1;
408 unsigned long state;
409 spinlock_t ao_spinlock;
410 unsigned int *ao_readback;
411 short *ao_scan_vals;
412 unsigned char *ao_scan_order;
413 int intr_cpuid;
414 short intr_running;
415 unsigned short daccon;
416 unsigned int cached_div1;
417 unsigned int cached_div2;
418 unsigned int ao_stop_count;
419 short ao_stop_continuous;
420 unsigned short ao_enab;
421 unsigned char intsce;
422};
423
424#define devpriv ((struct pci224_private *)dev->private)
425
426
427
428
429
430
431
432static int pci224_attach(struct comedi_device *dev,
433 struct comedi_devconfig *it);
434static int pci224_detach(struct comedi_device *dev);
435static struct comedi_driver driver_amplc_pci224 = {
436 .driver_name = DRIVER_NAME,
437 .module = THIS_MODULE,
438 .attach = pci224_attach,
439 .detach = pci224_detach,
440 .board_name = &pci224_boards[0].name,
441 .offset = sizeof(struct pci224_board),
442 .num_names = ARRAY_SIZE(pci224_boards),
443};
444
445COMEDI_PCI_INITCLEANUP(driver_amplc_pci224, pci224_pci_table);
446
447
448
449
450static void
451pci224_ao_set_data(struct comedi_device *dev, int chan, int range,
452 unsigned int data)
453{
454 unsigned short mangled;
455
456
457 devpriv->ao_readback[chan] = data;
458
459 outw(1 << chan, dev->iobase + PCI224_DACCEN);
460
461 devpriv->daccon = COMBINE(devpriv->daccon, devpriv->hwrange[range],
462 (PCI224_DACCON_POLAR_MASK |
463 PCI224_DACCON_VREF_MASK));
464 outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
465 dev->iobase + PCI224_DACCON);
466
467
468
469
470
471 mangled = (unsigned short)data << (16 - thisboard->ao_bits);
472 if ((devpriv->daccon & PCI224_DACCON_POLAR_MASK) ==
473 PCI224_DACCON_POLAR_BI) {
474 mangled ^= 0x8000;
475 }
476
477 outw(mangled, dev->iobase + PCI224_DACDATA);
478
479 inw(dev->iobase + PCI224_SOFTTRIG);
480}
481
482
483
484
485static int
486pci224_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s,
487 struct comedi_insn *insn, unsigned int *data)
488{
489 int i;
490 int chan, range;
491
492
493 chan = CR_CHAN(insn->chanspec);
494 range = CR_RANGE(insn->chanspec);
495
496
497
498 for (i = 0; i < insn->n; i++) {
499 pci224_ao_set_data(dev, chan, range, data[i]);
500 }
501 return i;
502}
503
504
505
506
507
508
509
510
511
512static int
513pci224_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
514 struct comedi_insn *insn, unsigned int *data)
515{
516 int i;
517 int chan;
518
519 chan = CR_CHAN(insn->chanspec);
520
521 for (i = 0; i < insn->n; i++) {
522 data[i] = devpriv->ao_readback[chan];
523 }
524
525 return i;
526}
527
528
529
530
531static void
532pci224_cascade_ns_to_timer(int osc_base, unsigned int *d1, unsigned int *d2,
533 unsigned int *nanosec, int round_mode)
534{
535 i8253_cascade_ns_to_timer(osc_base, d1, d2, nanosec, round_mode);
536}
537
538
539
540
541static void pci224_ao_stop(struct comedi_device *dev,
542 struct comedi_subdevice *s)
543{
544 unsigned long flags;
545
546 if (!test_and_clear_bit(AO_CMD_STARTED, &devpriv->state)) {
547 return;
548 }
549
550 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
551
552 devpriv->intsce = 0;
553 outb(0, devpriv->iobase1 + PCI224_INT_SCE);
554
555
556
557
558
559
560
561
562
563
564
565 while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
566 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
567 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
568 }
569 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
570
571 outw(0, dev->iobase + PCI224_DACCEN);
572 devpriv->daccon = COMBINE(devpriv->daccon,
573 PCI224_DACCON_TRIG_SW |
574 PCI224_DACCON_FIFOINTR_EMPTY,
575 PCI224_DACCON_TRIG_MASK |
576 PCI224_DACCON_FIFOINTR_MASK);
577 outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
578 dev->iobase + PCI224_DACCON);
579}
580
581
582
583
584static void pci224_ao_start(struct comedi_device *dev,
585 struct comedi_subdevice *s)
586{
587 struct comedi_cmd *cmd = &s->async->cmd;
588 unsigned long flags;
589
590 set_bit(AO_CMD_STARTED, &devpriv->state);
591 if (!devpriv->ao_stop_continuous && devpriv->ao_stop_count == 0) {
592
593 pci224_ao_stop(dev, s);
594 s->async->events |= COMEDI_CB_EOA;
595 comedi_event(dev, s);
596 } else {
597
598 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
599 if (cmd->stop_src == TRIG_EXT) {
600 devpriv->intsce = PCI224_INTR_EXT | PCI224_INTR_DAC;
601 } else {
602 devpriv->intsce = PCI224_INTR_DAC;
603 }
604 outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE);
605 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
606 }
607}
608
609
610
611
612static void pci224_ao_handle_fifo(struct comedi_device *dev,
613 struct comedi_subdevice *s)
614{
615 struct comedi_cmd *cmd = &s->async->cmd;
616 unsigned int num_scans;
617 unsigned int room;
618 unsigned short dacstat;
619 unsigned int i, n;
620 unsigned int bytes_per_scan;
621
622 if (cmd->chanlist_len) {
623 bytes_per_scan = cmd->chanlist_len * sizeof(short);
624 } else {
625
626 bytes_per_scan = sizeof(short);
627 }
628
629 num_scans = comedi_buf_read_n_available(s->async) / bytes_per_scan;
630 if (!devpriv->ao_stop_continuous) {
631
632 if (num_scans > devpriv->ao_stop_count) {
633 num_scans = devpriv->ao_stop_count;
634 }
635 }
636
637
638 dacstat = inw(dev->iobase + PCI224_DACCON);
639 switch (dacstat & PCI224_DACCON_FIFOFL_MASK) {
640 case PCI224_DACCON_FIFOFL_EMPTY:
641 room = PCI224_FIFO_ROOM_EMPTY;
642 if (!devpriv->ao_stop_continuous && devpriv->ao_stop_count == 0) {
643
644 pci224_ao_stop(dev, s);
645 s->async->events |= COMEDI_CB_EOA;
646 comedi_event(dev, s);
647 return;
648 }
649 break;
650 case PCI224_DACCON_FIFOFL_ONETOHALF:
651 room = PCI224_FIFO_ROOM_ONETOHALF;
652 break;
653 case PCI224_DACCON_FIFOFL_HALFTOFULL:
654 room = PCI224_FIFO_ROOM_HALFTOFULL;
655 break;
656 default:
657 room = PCI224_FIFO_ROOM_FULL;
658 break;
659 }
660 if (room >= PCI224_FIFO_ROOM_ONETOHALF) {
661
662 if (num_scans == 0) {
663
664 pci224_ao_stop(dev, s);
665 s->async->events |= COMEDI_CB_OVERFLOW;
666 printk(KERN_ERR "comedi%d: "
667 "AO buffer underrun\n", dev->minor);
668 }
669 }
670
671 if (cmd->chanlist_len) {
672 room /= cmd->chanlist_len;
673 }
674
675 if (num_scans > room) {
676 num_scans = room;
677 }
678
679 for (n = 0; n < num_scans; n++) {
680 cfc_read_array_from_buffer(s, &devpriv->ao_scan_vals[0],
681 bytes_per_scan);
682 for (i = 0; i < cmd->chanlist_len; i++) {
683 outw(devpriv->ao_scan_vals[devpriv->ao_scan_order[i]],
684 dev->iobase + PCI224_DACDATA);
685 }
686 }
687 if (!devpriv->ao_stop_continuous) {
688 devpriv->ao_stop_count -= num_scans;
689 if (devpriv->ao_stop_count == 0) {
690
691
692
693
694 devpriv->daccon = COMBINE(devpriv->daccon,
695 PCI224_DACCON_FIFOINTR_EMPTY,
696 PCI224_DACCON_FIFOINTR_MASK);
697 outw(devpriv->daccon, dev->iobase + PCI224_DACCON);
698 }
699 }
700 if ((devpriv->daccon & PCI224_DACCON_TRIG_MASK) ==
701 PCI224_DACCON_TRIG_NONE) {
702 unsigned short trig;
703
704
705
706
707
708
709
710
711
712
713
714
715
716 if (cmd->scan_begin_src == TRIG_TIMER) {
717 trig = PCI224_DACCON_TRIG_Z2CT0;
718 } else {
719
720 if (cmd->scan_begin_arg & CR_INVERT) {
721 trig = PCI224_DACCON_TRIG_EXTN;
722 } else {
723 trig = PCI224_DACCON_TRIG_EXTP;
724 }
725 }
726 devpriv->daccon = COMBINE(devpriv->daccon, trig,
727 PCI224_DACCON_TRIG_MASK);
728 outw(devpriv->daccon, dev->iobase + PCI224_DACCON);
729 }
730 if (s->async->events) {
731 comedi_event(dev, s);
732 }
733}
734
735
736
737
738static int
739pci224_ao_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s,
740 unsigned int trignum)
741{
742 if (trignum != 0)
743 return -EINVAL;
744
745 s->async->inttrig = NULLFUNC;
746 pci224_ao_start(dev, s);
747
748 return 1;
749}
750
751#define MAX_SCAN_PERIOD 0xFFFFFFFFU
752#define MIN_SCAN_PERIOD 2500
753#define CONVERT_PERIOD 625
754
755
756
757
758static int
759pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
760 struct comedi_cmd *cmd)
761{
762 int err = 0;
763 unsigned int tmp;
764
765
766
767 tmp = cmd->start_src;
768 cmd->start_src &= TRIG_INT | TRIG_EXT;
769 if (!cmd->start_src || tmp != cmd->start_src)
770 err++;
771
772 tmp = cmd->scan_begin_src;
773 cmd->scan_begin_src &= TRIG_EXT | TRIG_TIMER;
774 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
775 err++;
776
777 tmp = cmd->convert_src;
778 cmd->convert_src &= TRIG_NOW;
779 if (!cmd->convert_src || tmp != cmd->convert_src)
780 err++;
781
782 tmp = cmd->scan_end_src;
783 cmd->scan_end_src &= TRIG_COUNT;
784 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
785 err++;
786
787 tmp = cmd->stop_src;
788 cmd->stop_src &= TRIG_COUNT | TRIG_EXT | TRIG_NONE;
789 if (!cmd->stop_src || tmp != cmd->stop_src)
790 err++;
791
792 if (err)
793 return 1;
794
795
796
797
798
799 if ((cmd->start_src & (cmd->start_src - 1)) != 0)
800 err++;
801 if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
802 err++;
803 if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
804 err++;
805 if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
806 err++;
807 if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
808 err++;
809
810
811
812 tmp = 0;
813 if (cmd->start_src & TRIG_EXT)
814 tmp++;
815 if (cmd->scan_begin_src & TRIG_EXT)
816 tmp++;
817 if (cmd->stop_src & TRIG_EXT)
818 tmp++;
819 if (tmp > 1)
820 err++;
821
822 if (err)
823 return 2;
824
825
826
827 switch (cmd->start_src) {
828 case TRIG_INT:
829 if (cmd->start_arg != 0) {
830 cmd->start_arg = 0;
831 err++;
832 }
833 break;
834 case TRIG_EXT:
835
836 if ((cmd->start_arg & ~CR_FLAGS_MASK) != 0) {
837 cmd->start_arg = COMBINE(cmd->start_arg, 0,
838 ~CR_FLAGS_MASK);
839 err++;
840 }
841
842 if ((cmd->start_arg & CR_FLAGS_MASK & ~CR_EDGE) != 0) {
843 cmd->start_arg = COMBINE(cmd->start_arg, 0,
844 CR_FLAGS_MASK & ~CR_EDGE);
845 err++;
846 }
847 break;
848 }
849
850 switch (cmd->scan_begin_src) {
851 case TRIG_TIMER:
852 if (cmd->scan_begin_arg > MAX_SCAN_PERIOD) {
853 cmd->scan_begin_arg = MAX_SCAN_PERIOD;
854 err++;
855 }
856 tmp = cmd->chanlist_len * CONVERT_PERIOD;
857 if (tmp < MIN_SCAN_PERIOD) {
858 tmp = MIN_SCAN_PERIOD;
859 }
860 if (cmd->scan_begin_arg < tmp) {
861 cmd->scan_begin_arg = tmp;
862 err++;
863 }
864 break;
865 case TRIG_EXT:
866
867 if ((cmd->scan_begin_arg & ~CR_FLAGS_MASK) != 0) {
868 cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
869 ~CR_FLAGS_MASK);
870 err++;
871 }
872
873 if ((cmd->scan_begin_arg & CR_FLAGS_MASK &
874 ~(CR_EDGE | CR_INVERT)) != 0) {
875 cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
876 CR_FLAGS_MASK & ~(CR_EDGE
877 |
878 CR_INVERT));
879 err++;
880 }
881 break;
882 }
883
884
885 if (cmd->convert_arg != 0) {
886 cmd->convert_arg = 0;
887 err++;
888 }
889
890
891 if (cmd->scan_end_arg != cmd->chanlist_len) {
892 cmd->scan_end_arg = cmd->chanlist_len;
893 err++;
894 }
895
896 switch (cmd->stop_src) {
897 case TRIG_COUNT:
898
899 break;
900 case TRIG_EXT:
901
902 if ((cmd->stop_arg & ~CR_FLAGS_MASK) != 0) {
903 cmd->stop_arg = COMBINE(cmd->stop_arg, 0,
904 ~CR_FLAGS_MASK);
905 err++;
906 }
907
908 if ((cmd->stop_arg & CR_FLAGS_MASK & ~CR_EDGE) != 0) {
909 cmd->stop_arg = COMBINE(cmd->stop_arg, 0,
910 CR_FLAGS_MASK & ~CR_EDGE);
911 }
912 break;
913 case TRIG_NONE:
914 if (cmd->stop_arg != 0) {
915 cmd->stop_arg = 0;
916 err++;
917 }
918 break;
919 }
920
921 if (err)
922 return 3;
923
924
925
926 if (cmd->scan_begin_src == TRIG_TIMER) {
927 unsigned int div1, div2, round;
928 int round_mode = cmd->flags & TRIG_ROUND_MASK;
929
930 tmp = cmd->scan_begin_arg;
931
932 switch (round_mode) {
933 case TRIG_ROUND_NEAREST:
934 default:
935 round = TIMEBASE_10MHZ / 2;
936 break;
937 case TRIG_ROUND_DOWN:
938 round = 0;
939 break;
940 case TRIG_ROUND_UP:
941 round = TIMEBASE_10MHZ - 1;
942 break;
943 }
944
945 div2 = cmd->scan_begin_arg / TIMEBASE_10MHZ;
946 div2 += (round + cmd->scan_begin_arg % TIMEBASE_10MHZ) /
947 TIMEBASE_10MHZ;
948 if (div2 <= 0x10000) {
949
950 if (div2 < 2)
951 div2 = 2;
952 cmd->scan_begin_arg = div2 * TIMEBASE_10MHZ;
953 if (cmd->scan_begin_arg < div2 ||
954 cmd->scan_begin_arg < TIMEBASE_10MHZ) {
955
956 cmd->scan_begin_arg = MAX_SCAN_PERIOD;
957 }
958 } else {
959
960 div1 = devpriv->cached_div1;
961 div2 = devpriv->cached_div2;
962 pci224_cascade_ns_to_timer(TIMEBASE_10MHZ, &div1, &div2,
963 &cmd->scan_begin_arg,
964 round_mode);
965 devpriv->cached_div1 = div1;
966 devpriv->cached_div2 = div2;
967 }
968 if (tmp != cmd->scan_begin_arg) {
969 err++;
970 }
971 }
972
973 if (err)
974 return 4;
975
976
977
978 if (cmd->chanlist && (cmd->chanlist_len > 0)) {
979 unsigned int range;
980 enum { range_err = 1, dupchan_err = 2, };
981 unsigned errors;
982 unsigned int n;
983 unsigned int ch;
984
985
986
987
988
989
990
991 range = CR_RANGE(cmd->chanlist[0]);
992 errors = 0;
993 tmp = 0;
994 for (n = 0; n < cmd->chanlist_len; n++) {
995 ch = CR_CHAN(cmd->chanlist[n]);
996 if (tmp & (1U << ch)) {
997 errors |= dupchan_err;
998 }
999 tmp |= (1U << ch);
1000 if (CR_RANGE(cmd->chanlist[n]) != range) {
1001 errors |= range_err;
1002 }
1003 }
1004 if (errors) {
1005 if (errors & dupchan_err) {
1006 DPRINTK("comedi%d: " DRIVER_NAME
1007 ": ao_cmdtest: "
1008 "entries in chanlist must contain no "
1009 "duplicate channels\n", dev->minor);
1010 }
1011 if (errors & range_err) {
1012 DPRINTK("comedi%d: " DRIVER_NAME
1013 ": ao_cmdtest: "
1014 "entries in chanlist must all have "
1015 "the same range index\n", dev->minor);
1016 }
1017 err++;
1018 }
1019 }
1020
1021 if (err)
1022 return 5;
1023
1024 return 0;
1025}
1026
1027
1028
1029
1030static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1031{
1032 struct comedi_cmd *cmd = &s->async->cmd;
1033 int range;
1034 unsigned int i, j;
1035 unsigned int ch;
1036 unsigned int rank;
1037 unsigned long flags;
1038
1039
1040 if (cmd->chanlist == NULL || cmd->chanlist_len == 0) {
1041 return -EINVAL;
1042 }
1043
1044
1045 devpriv->ao_enab = 0;
1046
1047 for (i = 0; i < cmd->chanlist_len; i++) {
1048 ch = CR_CHAN(cmd->chanlist[i]);
1049 devpriv->ao_enab |= 1U << ch;
1050 rank = 0;
1051 for (j = 0; j < cmd->chanlist_len; j++) {
1052 if (CR_CHAN(cmd->chanlist[j]) < ch) {
1053 rank++;
1054 }
1055 }
1056 devpriv->ao_scan_order[rank] = i;
1057 }
1058
1059
1060 outw(devpriv->ao_enab, dev->iobase + PCI224_DACCEN);
1061
1062
1063 range = CR_RANGE(cmd->chanlist[0]);
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073 devpriv->daccon = COMBINE(devpriv->daccon,
1074 (devpriv->
1075 hwrange[range] | PCI224_DACCON_TRIG_NONE |
1076 PCI224_DACCON_FIFOINTR_NHALF),
1077 (PCI224_DACCON_POLAR_MASK |
1078 PCI224_DACCON_VREF_MASK |
1079 PCI224_DACCON_TRIG_MASK |
1080 PCI224_DACCON_FIFOINTR_MASK));
1081 outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
1082 dev->iobase + PCI224_DACCON);
1083
1084 if (cmd->scan_begin_src == TRIG_TIMER) {
1085 unsigned int div1, div2, round;
1086 unsigned int ns = cmd->scan_begin_arg;
1087 int round_mode = cmd->flags & TRIG_ROUND_MASK;
1088
1089
1090 switch (round_mode) {
1091 case TRIG_ROUND_NEAREST:
1092 default:
1093 round = TIMEBASE_10MHZ / 2;
1094 break;
1095 case TRIG_ROUND_DOWN:
1096 round = 0;
1097 break;
1098 case TRIG_ROUND_UP:
1099 round = TIMEBASE_10MHZ - 1;
1100 break;
1101 }
1102
1103 div2 = cmd->scan_begin_arg / TIMEBASE_10MHZ;
1104 div2 += (round + cmd->scan_begin_arg % TIMEBASE_10MHZ) /
1105 TIMEBASE_10MHZ;
1106 if (div2 <= 0x10000) {
1107
1108 if (div2 < 2)
1109 div2 = 2;
1110 div2 &= 0xffff;
1111 div1 = 1;
1112 } else {
1113
1114 div1 = devpriv->cached_div1;
1115 div2 = devpriv->cached_div2;
1116 pci224_cascade_ns_to_timer(TIMEBASE_10MHZ, &div1, &div2,
1117 &ns, round_mode);
1118 }
1119
1120
1121
1122
1123
1124
1125 outb(GAT_CONFIG(0, GAT_VCC),
1126 devpriv->iobase1 + PCI224_ZGAT_SCE);
1127 if (div1 == 1) {
1128
1129 outb(CLK_CONFIG(0, CLK_10MHZ),
1130 devpriv->iobase1 + PCI224_ZCLK_SCE);
1131 } else {
1132
1133
1134 outb(GAT_CONFIG(2, GAT_VCC),
1135 devpriv->iobase1 + PCI224_ZGAT_SCE);
1136
1137 outb(CLK_CONFIG(2, CLK_10MHZ),
1138 devpriv->iobase1 + PCI224_ZCLK_SCE);
1139
1140 i8254_load(devpriv->iobase1 + PCI224_Z2_CT0, 0,
1141 2, div1, 2);
1142
1143 outb(CLK_CONFIG(0, CLK_OUTNM1),
1144 devpriv->iobase1 + PCI224_ZCLK_SCE);
1145 }
1146
1147 i8254_load(devpriv->iobase1 + PCI224_Z2_CT0, 0, 0, div2, 2);
1148 }
1149
1150
1151
1152
1153 switch (cmd->stop_src) {
1154 case TRIG_COUNT:
1155
1156 devpriv->ao_stop_continuous = 0;
1157 devpriv->ao_stop_count = cmd->stop_arg;
1158 break;
1159 default:
1160
1161 devpriv->ao_stop_continuous = 1;
1162 devpriv->ao_stop_count = 0;
1163 break;
1164 }
1165
1166
1167
1168
1169 switch (cmd->start_src) {
1170 case TRIG_INT:
1171 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
1172 s->async->inttrig = &pci224_ao_inttrig_start;
1173 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
1174 break;
1175 case TRIG_EXT:
1176
1177 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
1178 devpriv->intsce |= PCI224_INTR_EXT;
1179 outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE);
1180 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
1181 break;
1182 }
1183
1184 return 0;
1185}
1186
1187
1188
1189
1190static int pci224_ao_cancel(struct comedi_device *dev,
1191 struct comedi_subdevice *s)
1192{
1193 pci224_ao_stop(dev, s);
1194 return 0;
1195}
1196
1197
1198
1199
1200static void
1201pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s,
1202 void *data, unsigned int num_bytes, unsigned int chan_index)
1203{
1204 struct comedi_async *async = s->async;
1205 short *array = data;
1206 unsigned int length = num_bytes / sizeof(*array);
1207 unsigned int offset;
1208 unsigned int shift;
1209 unsigned int i;
1210
1211
1212 shift = 16 - thisboard->ao_bits;
1213
1214 if ((devpriv->hwrange[CR_RANGE(async->cmd.chanlist[0])] &
1215 PCI224_DACCON_POLAR_MASK) == PCI224_DACCON_POLAR_UNI) {
1216
1217 offset = 0;
1218 } else {
1219
1220 offset = 32768;
1221 }
1222
1223 for (i = 0; i < length; i++) {
1224 array[i] = (array[i] << shift) - offset;
1225 }
1226}
1227
1228
1229
1230
1231static irqreturn_t pci224_interrupt(int irq, void *d)
1232{
1233 struct comedi_device *dev = d;
1234 struct comedi_subdevice *s = &dev->subdevices[0];
1235 struct comedi_cmd *cmd;
1236 unsigned char intstat, valid_intstat;
1237 unsigned char curenab;
1238 int retval = 0;
1239 unsigned long flags;
1240
1241 intstat = inb(devpriv->iobase1 + PCI224_INT_SCE) & 0x3F;
1242 if (intstat) {
1243 retval = 1;
1244 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
1245 valid_intstat = devpriv->intsce & intstat;
1246
1247 curenab = devpriv->intsce & ~intstat;
1248 outb(curenab, devpriv->iobase1 + PCI224_INT_SCE);
1249 devpriv->intr_running = 1;
1250 devpriv->intr_cpuid = THISCPU;
1251 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
1252 if (valid_intstat != 0) {
1253 cmd = &s->async->cmd;
1254 if (valid_intstat & PCI224_INTR_EXT) {
1255 devpriv->intsce &= ~PCI224_INTR_EXT;
1256 if (cmd->start_src == TRIG_EXT) {
1257 pci224_ao_start(dev, s);
1258 } else if (cmd->stop_src == TRIG_EXT) {
1259 pci224_ao_stop(dev, s);
1260 }
1261 }
1262 if (valid_intstat & PCI224_INTR_DAC) {
1263 pci224_ao_handle_fifo(dev, s);
1264 }
1265 }
1266
1267 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
1268 if (curenab != devpriv->intsce) {
1269 outb(devpriv->intsce,
1270 devpriv->iobase1 + PCI224_INT_SCE);
1271 }
1272 devpriv->intr_running = 0;
1273 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
1274 }
1275 return IRQ_RETVAL(retval);
1276}
1277
1278
1279
1280
1281
1282static int
1283pci224_find_pci(struct comedi_device *dev, int bus, int slot,
1284 struct pci_dev **pci_dev_p)
1285{
1286 struct pci_dev *pci_dev = NULL;
1287
1288 *pci_dev_p = NULL;
1289
1290
1291 for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
1292 pci_dev != NULL;
1293 pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID,
1294 pci_dev)) {
1295
1296 if (bus || slot) {
1297 if (bus != pci_dev->bus->number
1298 || slot != PCI_SLOT(pci_dev->devfn))
1299 continue;
1300 }
1301 if (thisboard->model == any_model) {
1302
1303 int i;
1304
1305 for (i = 0; i < ARRAY_SIZE(pci224_boards); i++) {
1306 if (pci_dev->device == pci224_boards[i].devid) {
1307
1308 dev->board_ptr = &pci224_boards[i];
1309 break;
1310 }
1311 }
1312 if (i == ARRAY_SIZE(pci224_boards))
1313 continue;
1314 } else {
1315
1316 if (thisboard->devid != pci_dev->device)
1317 continue;
1318 }
1319
1320
1321 *pci_dev_p = pci_dev;
1322 return 0;
1323 }
1324
1325 if (bus || slot) {
1326 printk(KERN_ERR "comedi%d: error! "
1327 "no %s found at pci %02x:%02x!\n",
1328 dev->minor, thisboard->name, bus, slot);
1329 } else {
1330 printk(KERN_ERR "comedi%d: error! no %s found!\n",
1331 dev->minor, thisboard->name);
1332 }
1333 return -EIO;
1334}
1335
1336
1337
1338
1339
1340
1341
1342static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1343{
1344 struct comedi_subdevice *s;
1345 struct pci_dev *pci_dev;
1346 unsigned int irq;
1347 int bus = 0, slot = 0;
1348 unsigned n;
1349 int ret;
1350
1351 printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor, DRIVER_NAME);
1352
1353 bus = it->options[0];
1354 slot = it->options[1];
1355 ret = alloc_private(dev, sizeof(struct pci224_private));
1356 if (ret < 0) {
1357 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1358 dev->minor);
1359 return ret;
1360 }
1361
1362 ret = pci224_find_pci(dev, bus, slot, &pci_dev);
1363 if (ret < 0)
1364 return ret;
1365
1366 devpriv->pci_dev = pci_dev;
1367 ret = comedi_pci_enable(pci_dev, DRIVER_NAME);
1368 if (ret < 0) {
1369 printk(KERN_ERR
1370 "comedi%d: error! cannot enable PCI device "
1371 "and request regions!\n", dev->minor);
1372 return ret;
1373 }
1374 spin_lock_init(&devpriv->ao_spinlock);
1375
1376 devpriv->iobase1 = pci_resource_start(pci_dev, 2);
1377 dev->iobase = pci_resource_start(pci_dev, 3);
1378 irq = pci_dev->irq;
1379
1380
1381 devpriv->ao_readback = kmalloc(sizeof(devpriv->ao_readback[0]) *
1382 thisboard->ao_chans, GFP_KERNEL);
1383 if (!devpriv->ao_readback) {
1384 return -ENOMEM;
1385 }
1386
1387
1388 devpriv->ao_scan_vals = kmalloc(sizeof(devpriv->ao_scan_vals[0]) *
1389 thisboard->ao_chans, GFP_KERNEL);
1390 if (!devpriv->ao_scan_vals) {
1391 return -ENOMEM;
1392 }
1393
1394
1395 devpriv->ao_scan_order = kmalloc(sizeof(devpriv->ao_scan_order[0]) *
1396 thisboard->ao_chans, GFP_KERNEL);
1397 if (!devpriv->ao_scan_order) {
1398 return -ENOMEM;
1399 }
1400
1401
1402 devpriv->intsce = 0;
1403 outb(0, devpriv->iobase1 + PCI224_INT_SCE);
1404
1405
1406 outw(PCI224_DACCON_GLOBALRESET, dev->iobase + PCI224_DACCON);
1407 outw(0, dev->iobase + PCI224_DACCEN);
1408 outw(0, dev->iobase + PCI224_FIFOSIZ);
1409 devpriv->daccon = (PCI224_DACCON_TRIG_SW | PCI224_DACCON_POLAR_BI |
1410 PCI224_DACCON_FIFOENAB |
1411 PCI224_DACCON_FIFOINTR_EMPTY);
1412 outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
1413 dev->iobase + PCI224_DACCON);
1414
1415
1416 ret = alloc_subdevices(dev, 1);
1417 if (ret < 0) {
1418 printk(KERN_ERR "comedi%d: error! out of memory!\n",
1419 dev->minor);
1420 return ret;
1421 }
1422
1423 s = dev->subdevices + 0;
1424
1425 s->type = COMEDI_SUBD_AO;
1426 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
1427 s->n_chan = thisboard->ao_chans;
1428 s->maxdata = (1 << thisboard->ao_bits) - 1;
1429 s->insn_write = &pci224_ao_insn_write;
1430 s->insn_read = &pci224_ao_insn_read;
1431 s->len_chanlist = s->n_chan;
1432
1433 dev->write_subdev = s;
1434 s->do_cmd = &pci224_ao_cmd;
1435 s->do_cmdtest = &pci224_ao_cmdtest;
1436 s->cancel = &pci224_ao_cancel;
1437 s->munge = &pci224_ao_munge;
1438
1439
1440 if (thisboard->model == pci234_model) {
1441
1442 const struct comedi_lrange **range_table_list;
1443
1444 s->range_table_list = range_table_list =
1445 kmalloc(sizeof(struct comedi_lrange *) * s->n_chan,
1446 GFP_KERNEL);
1447 if (!s->range_table_list) {
1448 return -ENOMEM;
1449 }
1450 for (n = 2; n < 3 + s->n_chan; n++) {
1451 if (it->options[n] < 0 || it->options[n] > 1) {
1452 printk(KERN_WARNING "comedi%d: %s: warning! "
1453 "bad options[%u]=%d\n",
1454 dev->minor, DRIVER_NAME, n,
1455 it->options[n]);
1456 }
1457 }
1458 for (n = 0; n < s->n_chan; n++) {
1459 if (n < COMEDI_NDEVCONFOPTS - 3 &&
1460 it->options[3 + n] == 1) {
1461 if (it->options[2] == 1) {
1462 range_table_list[n] = &range_pci234_ext;
1463 } else {
1464 range_table_list[n] = &range_bipolar5;
1465 }
1466 } else {
1467 if (it->options[2] == 1) {
1468 range_table_list[n] =
1469 &range_pci234_ext2;
1470 } else {
1471 range_table_list[n] = &range_bipolar10;
1472 }
1473 }
1474 }
1475 devpriv->hwrange = hwrange_pci234;
1476 } else {
1477
1478 if (it->options[2] == 1) {
1479 s->range_table = &range_pci224_external;
1480 devpriv->hwrange = hwrange_pci224_external;
1481 } else {
1482 if (it->options[2] != 0) {
1483 printk(KERN_WARNING "comedi%d: %s: warning! "
1484 "bad options[2]=%d\n",
1485 dev->minor, DRIVER_NAME, it->options[2]);
1486 }
1487 s->range_table = &range_pci224_internal;
1488 devpriv->hwrange = hwrange_pci224_internal;
1489 }
1490 }
1491
1492 dev->board_name = thisboard->name;
1493
1494 if (irq) {
1495 ret = request_irq(irq, pci224_interrupt, IRQF_SHARED,
1496 DRIVER_NAME, dev);
1497 if (ret < 0) {
1498 printk(KERN_ERR "comedi%d: error! "
1499 "unable to allocate irq %u\n", dev->minor, irq);
1500 return ret;
1501 } else {
1502 dev->irq = irq;
1503 }
1504 }
1505
1506 printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
1507 printk("(pci %s) ", pci_name(pci_dev));
1508 if (irq) {
1509 printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
1510 } else {
1511 printk("(no irq) ");
1512 }
1513
1514 printk("attached\n");
1515
1516 return 1;
1517}
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527static int pci224_detach(struct comedi_device *dev)
1528{
1529 printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor, DRIVER_NAME);
1530
1531 if (dev->irq) {
1532 free_irq(dev->irq, dev);
1533 }
1534 if (dev->subdevices) {
1535 struct comedi_subdevice *s;
1536
1537 s = dev->subdevices + 0;
1538
1539 if (s->range_table_list) {
1540 kfree(s->range_table_list);
1541 }
1542 }
1543 if (devpriv) {
1544 if (devpriv->ao_readback) {
1545 kfree(devpriv->ao_readback);
1546 }
1547 if (devpriv->ao_scan_vals) {
1548 kfree(devpriv->ao_scan_vals);
1549 }
1550 if (devpriv->ao_scan_order) {
1551 kfree(devpriv->ao_scan_order);
1552 }
1553 if (devpriv->pci_dev) {
1554 if (dev->iobase) {
1555 comedi_pci_disable(devpriv->pci_dev);
1556 }
1557 pci_dev_put(devpriv->pci_dev);
1558 }
1559 }
1560 if (dev->board_name) {
1561 printk(KERN_INFO "comedi%d: %s removed\n",
1562 dev->minor, dev->board_name);
1563 }
1564
1565 return 0;
1566}
1567