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