1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191#include "../comedidev.h"
192
193#include <linux/delay.h>
194#include <linux/interrupt.h>
195
196#include "comedi_fc.h"
197#include "8253.h"
198#include "8255.h"
199
200
201#define PCI_DEVICE_ID_PCI230 0x0000
202#define PCI_DEVICE_ID_PCI260 0x0006
203#define PCI_DEVICE_ID_INVALID 0xffff
204
205#define PCI230_IO1_SIZE 32
206#define PCI230_IO2_SIZE 16
207
208
209#define PCI230_PPI_X_BASE 0x00
210#define PCI230_PPI_X_A 0x00
211#define PCI230_PPI_X_B 0x01
212#define PCI230_PPI_X_C 0x02
213#define PCI230_PPI_X_CMD 0x03
214#define PCI230_Z2_CT_BASE 0x14
215#define PCI230_Z2_CT0 0x14
216#define PCI230_Z2_CT1 0x15
217#define PCI230_Z2_CT2 0x16
218#define PCI230_Z2_CTC 0x17
219#define PCI230_ZCLK_SCE 0x1A
220#define PCI230_ZGAT_SCE 0x1D
221#define PCI230_INT_SCE 0x1E
222#define PCI230_INT_STAT 0x1E
223
224
225#define PCI230_DACCON 0x00
226#define PCI230_DACOUT1 0x02
227#define PCI230_DACOUT2 0x04
228#define PCI230_ADCDATA 0x08
229#define PCI230_ADCSWTRIG 0x08
230#define PCI230_ADCCON 0x0A
231#define PCI230_ADCEN 0x0C
232#define PCI230_ADCG 0x0E
233
234#define PCI230P_ADCTRIG 0x10
235#define PCI230P_ADCTH 0x12
236#define PCI230P_ADCFFTH 0x14
237#define PCI230P_ADCFFLEV 0x16
238#define PCI230P_ADCPTSC 0x18
239#define PCI230P_ADCHYST 0x1A
240#define PCI230P_EXTFUNC 0x1C
241#define PCI230P_HWVER 0x1E
242
243#define PCI230P2_DACDATA 0x02
244#define PCI230P2_DACSWTRIG 0x02
245#define PCI230P2_DACEN 0x06
246
247
248#define PCI230_DAC_SETTLE 5
249
250#define PCI230_ADC_SETTLE 1
251
252
253#define PCI230_MUX_SETTLE 10
254
255
256
257#define PCI230_DAC_OR_UNI (0<<0)
258#define PCI230_DAC_OR_BIP (1<<0)
259#define PCI230_DAC_OR_MASK (1<<0)
260
261
262#define PCI230P2_DAC_FIFO_EN (1<<8)
263
264
265#define PCI230P2_DAC_TRIG_NONE (0<<2)
266#define PCI230P2_DAC_TRIG_SW (1<<2)
267#define PCI230P2_DAC_TRIG_EXTP (2<<2)
268#define PCI230P2_DAC_TRIG_EXTN (3<<2)
269#define PCI230P2_DAC_TRIG_Z2CT0 (4<<2)
270#define PCI230P2_DAC_TRIG_Z2CT1 (5<<2)
271#define PCI230P2_DAC_TRIG_Z2CT2 (6<<2)
272#define PCI230P2_DAC_TRIG_MASK (7<<2)
273#define PCI230P2_DAC_FIFO_WRAP (1<<7)
274#define PCI230P2_DAC_INT_FIFO_EMPTY (0<<9)
275#define PCI230P2_DAC_INT_FIFO_NEMPTY (1<<9)
276#define PCI230P2_DAC_INT_FIFO_NHALF (2<<9)
277#define PCI230P2_DAC_INT_FIFO_HALF (3<<9)
278#define PCI230P2_DAC_INT_FIFO_NFULL (4<<9)
279#define PCI230P2_DAC_INT_FIFO_FULL (5<<9)
280#define PCI230P2_DAC_INT_FIFO_MASK (7<<9)
281
282
283#define PCI230_DAC_BUSY (1<<1)
284
285
286#define PCI230P2_DAC_FIFO_UNDERRUN_LATCHED (1<<5)
287#define PCI230P2_DAC_FIFO_EMPTY (1<<13)
288#define PCI230P2_DAC_FIFO_FULL (1<<14)
289#define PCI230P2_DAC_FIFO_HALF (1<<15)
290
291
292
293
294#define PCI230P2_DAC_FIFO_UNDERRUN_CLEAR (1<<5)
295#define PCI230P2_DAC_FIFO_RESET (1<<12)
296
297
298#define PCI230P2_DAC_FIFOLEVEL_HALF 512
299#define PCI230P2_DAC_FIFOLEVEL_FULL 1024
300
301#define PCI230P2_DAC_FIFOROOM_EMPTY PCI230P2_DAC_FIFOLEVEL_FULL
302#define PCI230P2_DAC_FIFOROOM_ONETOHALF \
303 (PCI230P2_DAC_FIFOLEVEL_FULL - PCI230P2_DAC_FIFOLEVEL_HALF)
304#define PCI230P2_DAC_FIFOROOM_HALFTOFULL 1
305#define PCI230P2_DAC_FIFOROOM_FULL 0
306
307
308#define PCI230_ADC_TRIG_NONE (0<<0)
309#define PCI230_ADC_TRIG_SW (1<<0)
310#define PCI230_ADC_TRIG_EXTP (2<<0)
311#define PCI230_ADC_TRIG_EXTN (3<<0)
312#define PCI230_ADC_TRIG_Z2CT0 (4<<0)
313#define PCI230_ADC_TRIG_Z2CT1 (5<<0)
314#define PCI230_ADC_TRIG_Z2CT2 (6<<0)
315#define PCI230_ADC_TRIG_MASK (7<<0)
316#define PCI230_ADC_IR_UNI (0<<3)
317#define PCI230_ADC_IR_BIP (1<<3)
318#define PCI230_ADC_IR_MASK (1<<3)
319#define PCI230_ADC_IM_SE (0<<4)
320#define PCI230_ADC_IM_DIF (1<<4)
321#define PCI230_ADC_IM_MASK (1<<4)
322#define PCI230_ADC_FIFO_EN (1<<8)
323#define PCI230_ADC_INT_FIFO_EMPTY (0<<9)
324#define PCI230_ADC_INT_FIFO_NEMPTY (1<<9)
325#define PCI230_ADC_INT_FIFO_NHALF (2<<9)
326#define PCI230_ADC_INT_FIFO_HALF (3<<9)
327#define PCI230_ADC_INT_FIFO_NFULL (4<<9)
328#define PCI230_ADC_INT_FIFO_FULL (5<<9)
329#define PCI230P_ADC_INT_FIFO_THRESH (7<<9)
330#define PCI230_ADC_INT_FIFO_MASK (7<<9)
331
332
333#define PCI230_ADC_FIFO_RESET (1<<12)
334#define PCI230_ADC_GLOB_RESET (1<<13)
335
336
337#define PCI230_ADC_BUSY (1<<15)
338#define PCI230_ADC_FIFO_EMPTY (1<<12)
339#define PCI230_ADC_FIFO_FULL (1<<13)
340#define PCI230_ADC_FIFO_HALF (1<<14)
341#define PCI230_ADC_FIFO_FULL_LATCHED (1<<5)
342
343
344#define PCI230_ADC_FIFOLEVEL_HALFFULL 2049
345#define PCI230_ADC_FIFOLEVEL_FULL 4096
346
347
348
349#define PCI230_ADC_CONV 0xffff
350
351
352#define PCI230P_EXTFUNC_GAT_EXTTRIG (1<<0)
353
354
355#define PCI230P2_EXTFUNC_DACFIFO (1<<1)
356
357
358
359
360
361#define CLK_CLK 0
362#define CLK_10MHZ 1
363#define CLK_1MHZ 2
364#define CLK_100KHZ 3
365#define CLK_10KHZ 4
366#define CLK_1KHZ 5
367#define CLK_OUTNM1 6
368#define CLK_EXT 7
369
370#define CLK_CONFIG(chan, src) ((((chan) & 3) << 3) | ((src) & 7))
371
372#define TIMEBASE_10MHZ 100
373#define TIMEBASE_1MHZ 1000
374#define TIMEBASE_100KHZ 10000
375#define TIMEBASE_10KHZ 100000
376#define TIMEBASE_1KHZ 1000000
377
378
379
380
381#define GAT_VCC 0
382#define GAT_GND 1
383#define GAT_EXT 2
384#define GAT_NOUTNM2 3
385
386#define GAT_CONFIG(chan, src) ((((chan) & 3) << 3) | ((src) & 7))
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401#define PCI230_INT_DISABLE 0
402#define PCI230_INT_PPI_C0 (1<<0)
403#define PCI230_INT_PPI_C3 (1<<1)
404#define PCI230_INT_ADC (1<<2)
405#define PCI230_INT_ZCLK_CT1 (1<<5)
406
407#define PCI230P2_INT_DAC (1<<4)
408
409#define PCI230_TEST_BIT(val, n) ((val>>n)&1)
410
411
412
413enum {
414 RES_Z2CT0,
415 RES_Z2CT1,
416 RES_Z2CT2,
417 NUM_RESOURCES
418};
419
420enum {
421 OWNER_NONE,
422 OWNER_AICMD,
423 OWNER_AOCMD
424};
425
426
427
428
429
430
431#define COMBINE(old, new, mask) (((old) & ~(mask)) | ((new) & (mask)))
432
433
434#define THISCPU smp_processor_id()
435
436
437#define AI_CMD_STARTED 0
438#define AO_CMD_STARTED 1
439
440
441
442
443
444struct pci230_board {
445 const char *name;
446 unsigned short id;
447 int ai_chans;
448 int ai_bits;
449 int ao_chans;
450 int ao_bits;
451 int have_dio;
452 unsigned int min_hwver;
453};
454static const struct pci230_board pci230_boards[] = {
455 {
456 .name = "pci230+",
457 .id = PCI_DEVICE_ID_PCI230,
458 .ai_chans = 16,
459 .ai_bits = 16,
460 .ao_chans = 2,
461 .ao_bits = 12,
462 .have_dio = 1,
463 .min_hwver = 1,
464 },
465 {
466 .name = "pci260+",
467 .id = PCI_DEVICE_ID_PCI260,
468 .ai_chans = 16,
469 .ai_bits = 16,
470 .ao_chans = 0,
471 .ao_bits = 0,
472 .have_dio = 0,
473 .min_hwver = 1,
474 },
475 {
476 .name = "pci230",
477 .id = PCI_DEVICE_ID_PCI230,
478 .ai_chans = 16,
479 .ai_bits = 12,
480 .ao_chans = 2,
481 .ao_bits = 12,
482 .have_dio = 1,
483 },
484 {
485 .name = "pci260",
486 .id = PCI_DEVICE_ID_PCI260,
487 .ai_chans = 16,
488 .ai_bits = 12,
489 .ao_chans = 0,
490 .ao_bits = 0,
491 .have_dio = 0,
492 },
493 {
494 .name = "amplc_pci230",
495 .id = PCI_DEVICE_ID_INVALID,
496 },
497};
498
499
500
501
502struct pci230_private {
503 spinlock_t isr_spinlock;
504 spinlock_t res_spinlock;
505 spinlock_t ai_stop_spinlock;
506 spinlock_t ao_stop_spinlock;
507 unsigned long state;
508 unsigned long iobase1;
509 unsigned int ao_readback[2];
510 unsigned int ai_scan_count;
511
512 unsigned int ai_scan_pos;
513
514 unsigned int ao_scan_count;
515
516 int intr_cpuid;
517 unsigned short hwver;
518 unsigned short adccon;
519 unsigned short daccon;
520 unsigned short adcfifothresh;
521
522 unsigned short adcg;
523 unsigned char int_en;
524 unsigned char ai_continuous;
525
526
527
528 unsigned char ao_continuous;
529
530
531
532 unsigned char ai_bipolar;
533
534 unsigned char ao_bipolar;
535
536 unsigned char ier;
537 unsigned char intr_running;
538 unsigned char res_owner[NUM_RESOURCES];
539};
540
541
542static const unsigned int pci230_timebase[8] = {
543 [CLK_10MHZ] = TIMEBASE_10MHZ,
544 [CLK_1MHZ] = TIMEBASE_1MHZ,
545 [CLK_100KHZ] = TIMEBASE_100KHZ,
546 [CLK_10KHZ] = TIMEBASE_10KHZ,
547 [CLK_1KHZ] = TIMEBASE_1KHZ,
548};
549
550
551static const struct comedi_lrange pci230_ai_range = { 7, {
552 BIP_RANGE(10),
553 BIP_RANGE(5),
554 BIP_RANGE(2.5),
555 BIP_RANGE(1.25),
556 UNI_RANGE(10),
557 UNI_RANGE(5),
558 UNI_RANGE(2.5)
559 }
560};
561
562
563static const unsigned char pci230_ai_gain[7] = { 0, 1, 2, 3, 1, 2, 3 };
564
565
566static const unsigned char pci230_ai_bipolar[7] = { 1, 1, 1, 1, 0, 0, 0 };
567
568
569static const struct comedi_lrange pci230_ao_range = { 2, {
570 UNI_RANGE(10),
571 BIP_RANGE(10)
572 }
573};
574
575
576static const unsigned char pci230_ao_bipolar[2] = { 0, 1 };
577
578static short pci230_ai_read(struct comedi_device *dev)
579{
580 const struct pci230_board *thisboard = comedi_board(dev);
581 struct pci230_private *devpriv = dev->private;
582 short data;
583
584
585 data = (short)inw(dev->iobase + PCI230_ADCDATA);
586
587
588
589 data = data >> (16 - thisboard->ai_bits);
590
591
592
593 if (devpriv->ai_bipolar)
594 data ^= 1 << (thisboard->ai_bits - 1);
595
596 return data;
597}
598
599static inline unsigned short pci230_ao_mangle_datum(struct comedi_device *dev,
600 short datum)
601{
602 const struct pci230_board *thisboard = comedi_board(dev);
603 struct pci230_private *devpriv = dev->private;
604
605
606
607 if (devpriv->ao_bipolar)
608 datum ^= 1 << (thisboard->ao_bits - 1);
609
610
611
612
613 datum <<= (16 - thisboard->ao_bits);
614 return (unsigned short)datum;
615}
616
617static inline void pci230_ao_write_nofifo(struct comedi_device *dev,
618 short datum, unsigned int chan)
619{
620 struct pci230_private *devpriv = dev->private;
621
622
623 devpriv->ao_readback[chan] = datum;
624
625
626 outw(pci230_ao_mangle_datum(dev, datum), dev->iobase + (((chan) == 0)
627 ? PCI230_DACOUT1
628 :
629 PCI230_DACOUT2));
630}
631
632static inline void pci230_ao_write_fifo(struct comedi_device *dev, short datum,
633 unsigned int chan)
634{
635 struct pci230_private *devpriv = dev->private;
636
637
638 devpriv->ao_readback[chan] = datum;
639
640
641 outw(pci230_ao_mangle_datum(dev, datum),
642 dev->iobase + PCI230P2_DACDATA);
643}
644
645static int get_resources(struct comedi_device *dev, unsigned int res_mask,
646 unsigned char owner)
647{
648 struct pci230_private *devpriv = dev->private;
649 int ok;
650 unsigned int i;
651 unsigned int b;
652 unsigned int claimed;
653 unsigned long irqflags;
654
655 ok = 1;
656 claimed = 0;
657 spin_lock_irqsave(&devpriv->res_spinlock, irqflags);
658 for (b = 1, i = 0; (i < NUM_RESOURCES)
659 && (res_mask != 0); b <<= 1, i++) {
660 if ((res_mask & b) != 0) {
661 res_mask &= ~b;
662 if (devpriv->res_owner[i] == OWNER_NONE) {
663 devpriv->res_owner[i] = owner;
664 claimed |= b;
665 } else if (devpriv->res_owner[i] != owner) {
666 for (b = 1, i = 0; claimed != 0; b <<= 1, i++) {
667 if ((claimed & b) != 0) {
668 devpriv->res_owner[i]
669 = OWNER_NONE;
670 claimed &= ~b;
671 }
672 }
673 ok = 0;
674 break;
675 }
676 }
677 }
678 spin_unlock_irqrestore(&devpriv->res_spinlock, irqflags);
679 return ok;
680}
681
682static inline int get_one_resource(struct comedi_device *dev,
683 unsigned int resource, unsigned char owner)
684{
685 return get_resources(dev, (1U << resource), owner);
686}
687
688static void put_resources(struct comedi_device *dev, unsigned int res_mask,
689 unsigned char owner)
690{
691 struct pci230_private *devpriv = dev->private;
692 unsigned int i;
693 unsigned int b;
694 unsigned long irqflags;
695
696 spin_lock_irqsave(&devpriv->res_spinlock, irqflags);
697 for (b = 1, i = 0; (i < NUM_RESOURCES)
698 && (res_mask != 0); b <<= 1, i++) {
699 if ((res_mask & b) != 0) {
700 res_mask &= ~b;
701 if (devpriv->res_owner[i] == owner)
702 devpriv->res_owner[i] = OWNER_NONE;
703
704 }
705 }
706 spin_unlock_irqrestore(&devpriv->res_spinlock, irqflags);
707}
708
709static inline void put_one_resource(struct comedi_device *dev,
710 unsigned int resource, unsigned char owner)
711{
712 put_resources(dev, (1U << resource), owner);
713}
714
715static inline void put_all_resources(struct comedi_device *dev,
716 unsigned char owner)
717{
718 put_resources(dev, (1U << NUM_RESOURCES) - 1, owner);
719}
720
721static unsigned int divide_ns(uint64_t ns, unsigned int timebase,
722 unsigned int round_mode)
723{
724 uint64_t div;
725 unsigned int rem;
726
727 div = ns;
728 rem = do_div(div, timebase);
729 round_mode &= TRIG_ROUND_MASK;
730 switch (round_mode) {
731 default:
732 case TRIG_ROUND_NEAREST:
733 div += (rem + (timebase / 2)) / timebase;
734 break;
735 case TRIG_ROUND_DOWN:
736 break;
737 case TRIG_ROUND_UP:
738 div += (rem + timebase - 1) / timebase;
739 break;
740 }
741 return div > UINT_MAX ? UINT_MAX : (unsigned int)div;
742}
743
744
745
746static unsigned int pci230_choose_clk_count(uint64_t ns, unsigned int *count,
747 unsigned int round_mode)
748{
749 unsigned int clk_src, cnt;
750
751 for (clk_src = CLK_10MHZ;; clk_src++) {
752 cnt = divide_ns(ns, pci230_timebase[clk_src], round_mode);
753 if ((cnt <= 65536) || (clk_src == CLK_1KHZ))
754 break;
755
756 }
757 *count = cnt;
758 return clk_src;
759}
760
761static void pci230_ns_to_single_timer(unsigned int *ns, unsigned int round)
762{
763 unsigned int count;
764 unsigned int clk_src;
765
766 clk_src = pci230_choose_clk_count(*ns, &count, round);
767 *ns = count * pci230_timebase[clk_src];
768 return;
769}
770
771static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct,
772 unsigned int mode, uint64_t ns,
773 unsigned int round)
774{
775 struct pci230_private *devpriv = dev->private;
776 unsigned int clk_src;
777 unsigned int count;
778
779
780 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, mode);
781
782 clk_src = pci230_choose_clk_count(ns, &count, round);
783
784 outb(CLK_CONFIG(ct, clk_src), devpriv->iobase1 + PCI230_ZCLK_SCE);
785
786 if (count >= 65536)
787 count = 0;
788
789 i8254_write(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, count);
790}
791
792static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct)
793{
794 struct pci230_private *devpriv = dev->private;
795
796 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct,
797 I8254_MODE1);
798
799}
800
801
802
803
804static int pci230_ai_rinsn(struct comedi_device *dev,
805 struct comedi_subdevice *s, struct comedi_insn *insn,
806 unsigned int *data)
807{
808 struct pci230_private *devpriv = dev->private;
809 unsigned int n, i;
810 unsigned int chan, range, aref;
811 unsigned int gainshift;
812 unsigned int status;
813 unsigned short adccon, adcen;
814
815
816 chan = CR_CHAN(insn->chanspec);
817 range = CR_RANGE(insn->chanspec);
818 aref = CR_AREF(insn->chanspec);
819 if (aref == AREF_DIFF) {
820
821 if (chan >= s->n_chan / 2) {
822 DPRINTK("comedi%d: amplc_pci230: ai_rinsn: "
823 "differential channel number out of range "
824 "0 to %u\n", dev->minor, (s->n_chan / 2) - 1);
825 return -EINVAL;
826 }
827 }
828
829
830
831
832
833
834 adccon = PCI230_ADC_TRIG_Z2CT2 | PCI230_ADC_FIFO_EN;
835
836 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE0);
837 devpriv->ai_bipolar = pci230_ai_bipolar[range];
838 if (aref == AREF_DIFF) {
839
840 gainshift = chan * 2;
841 if (devpriv->hwver == 0) {
842
843
844 adcen = 3 << gainshift;
845 } else {
846
847
848 adcen = 1 << gainshift;
849 }
850 adccon |= PCI230_ADC_IM_DIF;
851 } else {
852
853 adcen = 1 << chan;
854 gainshift = chan & ~1;
855 adccon |= PCI230_ADC_IM_SE;
856 }
857 devpriv->adcg = (devpriv->adcg & ~(3 << gainshift))
858 | (pci230_ai_gain[range] << gainshift);
859 if (devpriv->ai_bipolar)
860 adccon |= PCI230_ADC_IR_BIP;
861 else
862 adccon |= PCI230_ADC_IR_UNI;
863
864
865
866
867 outw(adcen, dev->iobase + PCI230_ADCEN);
868
869
870 outw(devpriv->adcg, dev->iobase + PCI230_ADCG);
871
872
873 devpriv->adccon = adccon;
874 outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON);
875
876
877 for (n = 0; n < insn->n; n++) {
878
879
880 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
881 I8254_MODE0);
882 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
883 I8254_MODE1);
884
885#define TIMEOUT 100
886
887 for (i = 0; i < TIMEOUT; i++) {
888 status = inw(dev->iobase + PCI230_ADCCON);
889 if (!(status & PCI230_ADC_FIFO_EMPTY))
890 break;
891 udelay(1);
892 }
893 if (i == TIMEOUT) {
894 dev_err(dev->class_dev, "timeout\n");
895 return -ETIMEDOUT;
896 }
897
898
899 data[n] = pci230_ai_read(dev);
900 }
901
902
903 return n;
904}
905
906
907
908
909static int pci230_ao_winsn(struct comedi_device *dev,
910 struct comedi_subdevice *s, struct comedi_insn *insn,
911 unsigned int *data)
912{
913 struct pci230_private *devpriv = dev->private;
914 int i;
915 int chan, range;
916
917
918 chan = CR_CHAN(insn->chanspec);
919 range = CR_RANGE(insn->chanspec);
920
921
922
923 devpriv->ao_bipolar = pci230_ao_bipolar[range];
924 outw(range, dev->iobase + PCI230_DACCON);
925
926
927
928 for (i = 0; i < insn->n; i++) {
929
930 pci230_ao_write_nofifo(dev, data[i], chan);
931 }
932
933
934 return i;
935}
936
937
938
939static int pci230_ao_rinsn(struct comedi_device *dev,
940 struct comedi_subdevice *s, struct comedi_insn *insn,
941 unsigned int *data)
942{
943 struct pci230_private *devpriv = dev->private;
944 int i;
945 int chan = CR_CHAN(insn->chanspec);
946
947 for (i = 0; i < insn->n; i++)
948 data[i] = devpriv->ao_readback[chan];
949
950 return i;
951}
952
953static int pci230_ao_cmdtest(struct comedi_device *dev,
954 struct comedi_subdevice *s, struct comedi_cmd *cmd)
955{
956 const struct pci230_board *thisboard = comedi_board(dev);
957 struct pci230_private *devpriv = dev->private;
958 int err = 0;
959 unsigned int tmp;
960
961
962
963 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
964
965 tmp = TRIG_TIMER | TRIG_INT;
966 if ((thisboard->min_hwver > 0) && (devpriv->hwver >= 2)) {
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981 tmp |= TRIG_EXT;
982 }
983 err |= cfc_check_trigger_src(&cmd->scan_begin_src, tmp);
984
985 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
986 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
987 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
988
989 if (err)
990 return 1;
991
992
993
994 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
995 err |= cfc_check_trigger_is_unique(cmd->stop_src);
996
997
998
999 if (err)
1000 return 2;
1001
1002
1003
1004 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
1005
1006#define MAX_SPEED_AO 8000
1007#define MIN_SPEED_AO 4294967295u
1008
1009
1010
1011
1012 switch (cmd->scan_begin_src) {
1013 case TRIG_TIMER:
1014 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
1015 MAX_SPEED_AO);
1016 err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
1017 MIN_SPEED_AO);
1018 break;
1019 case TRIG_EXT:
1020
1021
1022 if ((cmd->scan_begin_arg & ~CR_FLAGS_MASK) != 0) {
1023 cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
1024 ~CR_FLAGS_MASK);
1025 err |= -EINVAL;
1026 }
1027
1028
1029 if ((cmd->scan_begin_arg
1030 & (CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT))) != 0) {
1031 cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
1032 CR_FLAGS_MASK &
1033 ~(CR_EDGE | CR_INVERT));
1034 err |= -EINVAL;
1035 }
1036 break;
1037 default:
1038 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
1039 break;
1040 }
1041
1042 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1043
1044 if (cmd->stop_src == TRIG_NONE)
1045 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
1046
1047 if (err)
1048 return 3;
1049
1050
1051
1052
1053
1054 if (cmd->scan_begin_src == TRIG_TIMER) {
1055 tmp = cmd->scan_begin_arg;
1056 pci230_ns_to_single_timer(&cmd->scan_begin_arg,
1057 cmd->flags & TRIG_ROUND_MASK);
1058 if (tmp != cmd->scan_begin_arg)
1059 err++;
1060 }
1061
1062 if (err)
1063 return 4;
1064
1065
1066
1067 if (cmd->chanlist && cmd->chanlist_len > 0) {
1068 enum {
1069 seq_err = (1 << 0),
1070 range_err = (1 << 1)
1071 };
1072 unsigned int errors;
1073 unsigned int n;
1074 unsigned int chan, prev_chan;
1075 unsigned int range, first_range;
1076
1077 prev_chan = CR_CHAN(cmd->chanlist[0]);
1078 first_range = CR_RANGE(cmd->chanlist[0]);
1079 errors = 0;
1080 for (n = 1; n < cmd->chanlist_len; n++) {
1081 chan = CR_CHAN(cmd->chanlist[n]);
1082 range = CR_RANGE(cmd->chanlist[n]);
1083
1084 if (chan < prev_chan)
1085 errors |= seq_err;
1086
1087
1088 if (range != first_range)
1089 errors |= range_err;
1090
1091 prev_chan = chan;
1092 }
1093 if (errors != 0) {
1094 err++;
1095 if ((errors & seq_err) != 0) {
1096 DPRINTK("comedi%d: amplc_pci230: ao_cmdtest: "
1097 "channel numbers must increase\n",
1098 dev->minor);
1099 }
1100 if ((errors & range_err) != 0) {
1101 DPRINTK("comedi%d: amplc_pci230: ao_cmdtest: "
1102 "channels must have the same range\n",
1103 dev->minor);
1104 }
1105 }
1106 }
1107
1108 if (err)
1109 return 5;
1110
1111 return 0;
1112}
1113
1114static void pci230_ao_stop(struct comedi_device *dev,
1115 struct comedi_subdevice *s)
1116{
1117 struct pci230_private *devpriv = dev->private;
1118 unsigned long irqflags;
1119 unsigned char intsrc;
1120 int started;
1121 struct comedi_cmd *cmd;
1122
1123 spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags);
1124 started = test_and_clear_bit(AO_CMD_STARTED, &devpriv->state);
1125 spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags);
1126 if (!started)
1127 return;
1128 cmd = &s->async->cmd;
1129 if (cmd->scan_begin_src == TRIG_TIMER) {
1130
1131 pci230_cancel_ct(dev, 1);
1132 }
1133
1134 if (devpriv->hwver < 2) {
1135
1136 intsrc = PCI230_INT_ZCLK_CT1;
1137 } else {
1138
1139 intsrc = PCI230P2_INT_DAC;
1140 }
1141
1142
1143 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
1144 devpriv->int_en &= ~intsrc;
1145 while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
1146 spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
1147 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
1148 }
1149 if (devpriv->ier != devpriv->int_en) {
1150 devpriv->ier = devpriv->int_en;
1151 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
1152 }
1153 spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
1154 if (devpriv->hwver >= 2) {
1155
1156
1157 devpriv->daccon &= PCI230_DAC_OR_MASK;
1158 outw(devpriv->daccon | PCI230P2_DAC_FIFO_RESET
1159 | PCI230P2_DAC_FIFO_UNDERRUN_CLEAR,
1160 dev->iobase + PCI230_DACCON);
1161 }
1162
1163 put_all_resources(dev, OWNER_AOCMD);
1164}
1165
1166static void pci230_handle_ao_nofifo(struct comedi_device *dev,
1167 struct comedi_subdevice *s)
1168{
1169 struct pci230_private *devpriv = dev->private;
1170 short data;
1171 int i, ret;
1172 struct comedi_async *async = s->async;
1173 struct comedi_cmd *cmd = &async->cmd;
1174
1175 if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0))
1176 return;
1177 for (i = 0; i < cmd->chanlist_len; i++) {
1178
1179 ret = comedi_buf_get(s->async, &data);
1180 if (ret == 0) {
1181 s->async->events |= COMEDI_CB_OVERFLOW;
1182 pci230_ao_stop(dev, s);
1183 comedi_error(dev, "AO buffer underrun");
1184 return;
1185 }
1186
1187 pci230_ao_write_nofifo(dev, data, CR_CHAN(cmd->chanlist[i]));
1188 }
1189 async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
1190 if (!devpriv->ao_continuous) {
1191 devpriv->ao_scan_count--;
1192 if (devpriv->ao_scan_count == 0) {
1193
1194 async->events |= COMEDI_CB_EOA;
1195 pci230_ao_stop(dev, s);
1196 }
1197 }
1198}
1199
1200
1201
1202static int pci230_handle_ao_fifo(struct comedi_device *dev,
1203 struct comedi_subdevice *s)
1204{
1205 struct pci230_private *devpriv = dev->private;
1206 struct comedi_async *async = s->async;
1207 struct comedi_cmd *cmd = &async->cmd;
1208 unsigned int num_scans;
1209 unsigned int room;
1210 unsigned short dacstat;
1211 unsigned int i, n;
1212 unsigned int bytes_per_scan;
1213 unsigned int events = 0;
1214 int running;
1215
1216
1217 dacstat = inw(dev->iobase + PCI230_DACCON);
1218
1219 bytes_per_scan = cmd->chanlist_len * sizeof(short);
1220 num_scans = comedi_buf_read_n_available(async) / bytes_per_scan;
1221 if (!devpriv->ao_continuous) {
1222
1223 if (num_scans > devpriv->ao_scan_count)
1224 num_scans = devpriv->ao_scan_count;
1225 if (devpriv->ao_scan_count == 0) {
1226
1227 events |= COMEDI_CB_EOA;
1228 }
1229 }
1230 if (events == 0) {
1231
1232 if ((dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) != 0) {
1233 comedi_error(dev, "AO FIFO underrun");
1234 events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
1235 }
1236
1237
1238
1239 if ((num_scans == 0)
1240 && ((dacstat & PCI230P2_DAC_FIFO_HALF) == 0)) {
1241 comedi_error(dev, "AO buffer underrun");
1242 events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
1243 }
1244 }
1245 if (events == 0) {
1246
1247 if ((dacstat & PCI230P2_DAC_FIFO_FULL) != 0)
1248 room = PCI230P2_DAC_FIFOROOM_FULL;
1249 else if ((dacstat & PCI230P2_DAC_FIFO_HALF) != 0)
1250 room = PCI230P2_DAC_FIFOROOM_HALFTOFULL;
1251 else if ((dacstat & PCI230P2_DAC_FIFO_EMPTY) != 0)
1252 room = PCI230P2_DAC_FIFOROOM_EMPTY;
1253 else
1254 room = PCI230P2_DAC_FIFOROOM_ONETOHALF;
1255
1256 room /= cmd->chanlist_len;
1257
1258 if (num_scans > room)
1259 num_scans = room;
1260
1261 for (n = 0; n < num_scans; n++) {
1262 for (i = 0; i < cmd->chanlist_len; i++) {
1263 short datum;
1264
1265 comedi_buf_get(async, &datum);
1266 pci230_ao_write_fifo(dev, datum,
1267 CR_CHAN(cmd->chanlist[i]));
1268 }
1269 }
1270 events |= COMEDI_CB_EOS | COMEDI_CB_BLOCK;
1271 if (!devpriv->ao_continuous) {
1272 devpriv->ao_scan_count -= num_scans;
1273 if (devpriv->ao_scan_count == 0) {
1274
1275
1276
1277 devpriv->daccon = (devpriv->daccon
1278 &
1279 ~PCI230P2_DAC_INT_FIFO_MASK)
1280 | PCI230P2_DAC_INT_FIFO_EMPTY;
1281 outw(devpriv->daccon,
1282 dev->iobase + PCI230_DACCON);
1283 }
1284 }
1285
1286 dacstat = inw(dev->iobase + PCI230_DACCON);
1287 if ((dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) != 0) {
1288 comedi_error(dev, "AO FIFO underrun");
1289 events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
1290 }
1291 }
1292 if ((events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW))
1293 != 0) {
1294
1295 pci230_ao_stop(dev, s);
1296 running = 0;
1297 } else {
1298 running = 1;
1299 }
1300 async->events |= events;
1301 return running;
1302}
1303
1304static int pci230_ao_inttrig_scan_begin(struct comedi_device *dev,
1305 struct comedi_subdevice *s,
1306 unsigned int trig_num)
1307{
1308 struct pci230_private *devpriv = dev->private;
1309 unsigned long irqflags;
1310
1311 if (trig_num != 0)
1312 return -EINVAL;
1313
1314 spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags);
1315 if (test_bit(AO_CMD_STARTED, &devpriv->state)) {
1316
1317 if (devpriv->hwver < 2) {
1318
1319 spin_unlock_irqrestore(&devpriv->ao_stop_spinlock,
1320 irqflags);
1321 pci230_handle_ao_nofifo(dev, s);
1322 comedi_event(dev, s);
1323 } else {
1324
1325
1326 inw(dev->iobase + PCI230P2_DACSWTRIG);
1327 spin_unlock_irqrestore(&devpriv->ao_stop_spinlock,
1328 irqflags);
1329 }
1330
1331
1332 udelay(8);
1333 } else {
1334 spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags);
1335 }
1336
1337 return 1;
1338}
1339
1340static void pci230_ao_start(struct comedi_device *dev,
1341 struct comedi_subdevice *s)
1342{
1343 struct pci230_private *devpriv = dev->private;
1344 struct comedi_async *async = s->async;
1345 struct comedi_cmd *cmd = &async->cmd;
1346 unsigned long irqflags;
1347
1348 set_bit(AO_CMD_STARTED, &devpriv->state);
1349 if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0)) {
1350
1351 async->events |= COMEDI_CB_EOA;
1352 pci230_ao_stop(dev, s);
1353 comedi_event(dev, s);
1354 } else {
1355 if (devpriv->hwver >= 2) {
1356
1357 unsigned short scantrig;
1358 int run;
1359
1360
1361 run = pci230_handle_ao_fifo(dev, s);
1362 comedi_event(dev, s);
1363 if (!run) {
1364
1365 return;
1366 }
1367
1368 switch (cmd->scan_begin_src) {
1369 case TRIG_TIMER:
1370 scantrig = PCI230P2_DAC_TRIG_Z2CT1;
1371 break;
1372 case TRIG_EXT:
1373
1374 if ((cmd->scan_begin_arg & CR_INVERT) == 0) {
1375
1376 scantrig = PCI230P2_DAC_TRIG_EXTP;
1377 } else {
1378
1379 scantrig = PCI230P2_DAC_TRIG_EXTN;
1380 }
1381 break;
1382 case TRIG_INT:
1383 scantrig = PCI230P2_DAC_TRIG_SW;
1384 break;
1385 default:
1386
1387 scantrig = PCI230P2_DAC_TRIG_NONE;
1388 break;
1389 }
1390 devpriv->daccon = (devpriv->daccon
1391 & ~PCI230P2_DAC_TRIG_MASK) |
1392 scantrig;
1393 outw(devpriv->daccon, dev->iobase + PCI230_DACCON);
1394
1395 }
1396 switch (cmd->scan_begin_src) {
1397 case TRIG_TIMER:
1398 if (devpriv->hwver < 2) {
1399
1400
1401 spin_lock_irqsave(&devpriv->isr_spinlock,
1402 irqflags);
1403 devpriv->int_en |= PCI230_INT_ZCLK_CT1;
1404 devpriv->ier |= PCI230_INT_ZCLK_CT1;
1405 outb(devpriv->ier,
1406 devpriv->iobase1 + PCI230_INT_SCE);
1407 spin_unlock_irqrestore(&devpriv->isr_spinlock,
1408 irqflags);
1409 }
1410
1411 outb(GAT_CONFIG(1, GAT_VCC),
1412 devpriv->iobase1 + PCI230_ZGAT_SCE);
1413 break;
1414 case TRIG_INT:
1415 async->inttrig = pci230_ao_inttrig_scan_begin;
1416 break;
1417 }
1418 if (devpriv->hwver >= 2) {
1419
1420 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
1421 devpriv->int_en |= PCI230P2_INT_DAC;
1422 devpriv->ier |= PCI230P2_INT_DAC;
1423 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
1424 spin_unlock_irqrestore(&devpriv->isr_spinlock,
1425 irqflags);
1426 }
1427 }
1428}
1429
1430static int pci230_ao_inttrig_start(struct comedi_device *dev,
1431 struct comedi_subdevice *s,
1432 unsigned int trig_num)
1433{
1434 if (trig_num != 0)
1435 return -EINVAL;
1436
1437 s->async->inttrig = NULL;
1438 pci230_ao_start(dev, s);
1439
1440 return 1;
1441}
1442
1443static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1444{
1445 struct pci230_private *devpriv = dev->private;
1446 unsigned short daccon;
1447 unsigned int range;
1448
1449
1450 struct comedi_cmd *cmd = &s->async->cmd;
1451
1452 if (cmd->scan_begin_src == TRIG_TIMER) {
1453
1454 if (!get_one_resource(dev, RES_Z2CT1, OWNER_AOCMD))
1455 return -EBUSY;
1456
1457 }
1458
1459
1460 if (cmd->stop_src == TRIG_COUNT) {
1461 devpriv->ao_scan_count = cmd->stop_arg;
1462 devpriv->ao_continuous = 0;
1463 } else {
1464
1465 devpriv->ao_scan_count = 0;
1466 devpriv->ao_continuous = 1;
1467 }
1468
1469
1470
1471 range = CR_RANGE(cmd->chanlist[0]);
1472 devpriv->ao_bipolar = pci230_ao_bipolar[range];
1473 daccon = devpriv->ao_bipolar ? PCI230_DAC_OR_BIP : PCI230_DAC_OR_UNI;
1474
1475 if (devpriv->hwver >= 2) {
1476 unsigned short dacen;
1477 unsigned int i;
1478
1479 dacen = 0;
1480 for (i = 0; i < cmd->chanlist_len; i++)
1481 dacen |= 1 << CR_CHAN(cmd->chanlist[i]);
1482
1483
1484 outw(dacen, dev->iobase + PCI230P2_DACEN);
1485
1486
1487
1488
1489
1490
1491
1492
1493 daccon |= PCI230P2_DAC_FIFO_EN | PCI230P2_DAC_FIFO_RESET
1494 | PCI230P2_DAC_FIFO_UNDERRUN_CLEAR
1495 | PCI230P2_DAC_TRIG_NONE | PCI230P2_DAC_INT_FIFO_NHALF;
1496 }
1497
1498
1499 outw(daccon, dev->iobase + PCI230_DACCON);
1500
1501 devpriv->daccon = daccon
1502 & ~(PCI230P2_DAC_FIFO_RESET | PCI230P2_DAC_FIFO_UNDERRUN_CLEAR);
1503
1504 if (cmd->scan_begin_src == TRIG_TIMER) {
1505
1506
1507
1508 outb(GAT_CONFIG(1, GAT_GND),
1509 devpriv->iobase1 + PCI230_ZGAT_SCE);
1510 pci230_ct_setup_ns_mode(dev, 1, I8254_MODE3,
1511 cmd->scan_begin_arg,
1512 cmd->flags & TRIG_ROUND_MASK);
1513 }
1514
1515
1516 s->async->inttrig = pci230_ao_inttrig_start;
1517
1518 return 0;
1519}
1520
1521static int pci230_ao_cancel(struct comedi_device *dev,
1522 struct comedi_subdevice *s)
1523{
1524 pci230_ao_stop(dev, s);
1525 return 0;
1526}
1527
1528static int pci230_ai_check_scan_period(struct comedi_cmd *cmd)
1529{
1530 unsigned int min_scan_period, chanlist_len;
1531 int err = 0;
1532
1533 chanlist_len = cmd->chanlist_len;
1534 if (cmd->chanlist_len == 0)
1535 chanlist_len = 1;
1536
1537 min_scan_period = chanlist_len * cmd->convert_arg;
1538 if ((min_scan_period < chanlist_len)
1539 || (min_scan_period < cmd->convert_arg)) {
1540
1541 min_scan_period = UINT_MAX;
1542 err++;
1543 }
1544 if (cmd->scan_begin_arg < min_scan_period) {
1545 cmd->scan_begin_arg = min_scan_period;
1546 err++;
1547 }
1548
1549 return !err;
1550}
1551
1552static int pci230_ai_cmdtest(struct comedi_device *dev,
1553 struct comedi_subdevice *s, struct comedi_cmd *cmd)
1554{
1555 const struct pci230_board *thisboard = comedi_board(dev);
1556 struct pci230_private *devpriv = dev->private;
1557 int err = 0;
1558 unsigned int tmp;
1559
1560
1561
1562 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
1563
1564 tmp = TRIG_FOLLOW | TRIG_TIMER | TRIG_INT;
1565 if ((thisboard->have_dio) || (thisboard->min_hwver > 0)) {
1566
1567
1568
1569
1570
1571
1572 tmp |= TRIG_EXT;
1573 }
1574 err |= cfc_check_trigger_src(&cmd->scan_begin_src, tmp);
1575 err |= cfc_check_trigger_src(&cmd->convert_src,
1576 TRIG_TIMER | TRIG_INT | TRIG_EXT);
1577 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1578 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
1579
1580 if (err)
1581 return 1;
1582
1583
1584
1585 err |= cfc_check_trigger_is_unique(cmd->start_src);
1586 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
1587 err |= cfc_check_trigger_is_unique(cmd->convert_src);
1588 err |= cfc_check_trigger_is_unique(cmd->stop_src);
1589
1590
1591
1592
1593
1594
1595
1596 if ((cmd->scan_begin_src != TRIG_FOLLOW)
1597 && (cmd->convert_src != TRIG_TIMER))
1598 err |= -EINVAL;
1599
1600 if (err)
1601 return 2;
1602
1603
1604
1605 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
1606
1607#define MAX_SPEED_AI_SE 3200
1608#define MAX_SPEED_AI_DIFF 8000
1609#define MAX_SPEED_AI_PLUS 4000
1610#define MIN_SPEED_AI 4294967295u
1611
1612
1613
1614
1615 if (cmd->convert_src == TRIG_TIMER) {
1616 unsigned int max_speed_ai;
1617
1618 if (devpriv->hwver == 0) {
1619
1620
1621 if (cmd->chanlist && (cmd->chanlist_len > 0)) {
1622
1623 if (CR_AREF(cmd->chanlist[0]) == AREF_DIFF)
1624 max_speed_ai = MAX_SPEED_AI_DIFF;
1625 else
1626 max_speed_ai = MAX_SPEED_AI_SE;
1627
1628 } else {
1629
1630 max_speed_ai = MAX_SPEED_AI_SE;
1631 }
1632 } else {
1633
1634 max_speed_ai = MAX_SPEED_AI_PLUS;
1635 }
1636
1637 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
1638 max_speed_ai);
1639 err |= cfc_check_trigger_arg_max(&cmd->convert_arg,
1640 MIN_SPEED_AI);
1641 } else if (cmd->convert_src == TRIG_EXT) {
1642
1643
1644
1645
1646
1647
1648
1649
1650 if ((cmd->convert_arg & CR_FLAGS_MASK) != 0) {
1651
1652 if ((cmd->convert_arg & ~CR_FLAGS_MASK) != 0) {
1653 cmd->convert_arg = COMBINE(cmd->convert_arg, 0,
1654 ~CR_FLAGS_MASK);
1655 err |= -EINVAL;
1656 }
1657
1658
1659 if ((cmd->convert_arg & (CR_FLAGS_MASK & ~CR_INVERT))
1660 != CR_EDGE) {
1661
1662 cmd->convert_arg = COMBINE(cmd->start_arg,
1663 (CR_EDGE | 0),
1664 CR_FLAGS_MASK &
1665 ~CR_INVERT);
1666 err |= -EINVAL;
1667 }
1668 } else {
1669
1670
1671
1672 err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 1);
1673 }
1674 } else {
1675 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
1676 }
1677
1678 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1679
1680 if (cmd->stop_src == TRIG_NONE)
1681 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
1682
1683 if (cmd->scan_begin_src == TRIG_EXT) {
1684
1685
1686
1687 if ((cmd->scan_begin_arg & ~CR_FLAGS_MASK) != 0) {
1688 cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
1689 ~CR_FLAGS_MASK);
1690 err |= -EINVAL;
1691 }
1692
1693 if ((cmd->scan_begin_arg & CR_FLAGS_MASK & ~CR_EDGE) != 0) {
1694 cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
1695 CR_FLAGS_MASK & ~CR_EDGE);
1696 err |= -EINVAL;
1697 }
1698 } else if (cmd->scan_begin_src == TRIG_TIMER) {
1699
1700 if (!pci230_ai_check_scan_period(cmd))
1701 err |= -EINVAL;
1702
1703 } else {
1704 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
1705 }
1706
1707 if (err)
1708 return 3;
1709
1710
1711
1712
1713
1714 if (cmd->convert_src == TRIG_TIMER) {
1715 tmp = cmd->convert_arg;
1716 pci230_ns_to_single_timer(&cmd->convert_arg,
1717 cmd->flags & TRIG_ROUND_MASK);
1718 if (tmp != cmd->convert_arg)
1719 err++;
1720 }
1721
1722 if (cmd->scan_begin_src == TRIG_TIMER) {
1723
1724 tmp = cmd->scan_begin_arg;
1725 pci230_ns_to_single_timer(&cmd->scan_begin_arg,
1726 cmd->flags & TRIG_ROUND_MASK);
1727 if (!pci230_ai_check_scan_period(cmd)) {
1728
1729 pci230_ns_to_single_timer(&cmd->scan_begin_arg,
1730 TRIG_ROUND_UP);
1731 pci230_ai_check_scan_period(cmd);
1732 }
1733 if (tmp != cmd->scan_begin_arg)
1734 err++;
1735 }
1736
1737 if (err)
1738 return 4;
1739
1740
1741
1742 if (cmd->chanlist && cmd->chanlist_len > 0) {
1743 enum {
1744 seq_err = 1 << 0,
1745 rangepair_err = 1 << 1,
1746 polarity_err = 1 << 2,
1747 aref_err = 1 << 3,
1748 diffchan_err = 1 << 4,
1749 buggy_chan0_err = 1 << 5
1750 };
1751 unsigned int errors;
1752 unsigned int chan, prev_chan;
1753 unsigned int range, prev_range;
1754 unsigned int polarity, prev_polarity;
1755 unsigned int aref, prev_aref;
1756 unsigned int subseq_len;
1757 unsigned int n;
1758
1759 subseq_len = 0;
1760 errors = 0;
1761 prev_chan = prev_aref = prev_range = prev_polarity = 0;
1762 for (n = 0; n < cmd->chanlist_len; n++) {
1763 chan = CR_CHAN(cmd->chanlist[n]);
1764 range = CR_RANGE(cmd->chanlist[n]);
1765 aref = CR_AREF(cmd->chanlist[n]);
1766 polarity = pci230_ai_bipolar[range];
1767
1768
1769
1770 if ((aref == AREF_DIFF)
1771 && (chan >= (s->n_chan / 2))) {
1772 errors |= diffchan_err;
1773 }
1774 if (n > 0) {
1775
1776
1777 if ((chan <= prev_chan)
1778 && (subseq_len == 0)) {
1779 subseq_len = n;
1780 }
1781 if ((subseq_len > 0)
1782 && (cmd->chanlist[n] !=
1783 cmd->chanlist[n % subseq_len])) {
1784 errors |= seq_err;
1785 }
1786
1787 if (aref != prev_aref)
1788 errors |= aref_err;
1789
1790
1791 if (polarity != prev_polarity)
1792 errors |= polarity_err;
1793
1794
1795
1796 if ((aref != AREF_DIFF)
1797 && (((chan ^ prev_chan) & ~1) == 0)
1798 && (range != prev_range)) {
1799 errors |= rangepair_err;
1800 }
1801 }
1802 prev_chan = chan;
1803 prev_range = range;
1804 prev_aref = aref;
1805 prev_polarity = polarity;
1806 }
1807 if (subseq_len == 0) {
1808
1809 subseq_len = n;
1810 }
1811
1812
1813 if ((n % subseq_len) != 0)
1814 errors |= seq_err;
1815
1816 if ((devpriv->hwver > 0) && (devpriv->hwver < 4)) {
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831 if ((subseq_len > 1)
1832 && (CR_CHAN(cmd->chanlist[0]) != 0)) {
1833 errors |= buggy_chan0_err;
1834 }
1835 }
1836 if (errors != 0) {
1837 err++;
1838 if ((errors & seq_err) != 0) {
1839 DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
1840 "channel numbers must increase or "
1841 "sequence must repeat exactly\n",
1842 dev->minor);
1843 }
1844 if ((errors & rangepair_err) != 0) {
1845 DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
1846 "single-ended channel pairs must "
1847 "have the same range\n", dev->minor);
1848 }
1849 if ((errors & polarity_err) != 0) {
1850 DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
1851 "channel sequence ranges must be all "
1852 "bipolar or all unipolar\n",
1853 dev->minor);
1854 }
1855 if ((errors & aref_err) != 0) {
1856 DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
1857 "channel sequence analogue references "
1858 "must be all the same (single-ended "
1859 "or differential)\n", dev->minor);
1860 }
1861 if ((errors & diffchan_err) != 0) {
1862 DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
1863 "differential channel number out of "
1864 "range 0 to %u\n", dev->minor,
1865 (s->n_chan / 2) - 1);
1866 }
1867 if ((errors & buggy_chan0_err) != 0) {
1868 dev_info(dev->class_dev,
1869 "amplc_pci230: ai_cmdtest: Buggy PCI230+/260+ h/w version %u requires first channel of multi-channel sequence to be 0 (corrected in h/w version 4)\n",
1870 devpriv->hwver);
1871 }
1872 }
1873 }
1874
1875 if (err)
1876 return 5;
1877
1878 return 0;
1879}
1880
1881static void pci230_ai_update_fifo_trigger_level(struct comedi_device *dev,
1882 struct comedi_subdevice *s)
1883{
1884 struct pci230_private *devpriv = dev->private;
1885 struct comedi_cmd *cmd = &s->async->cmd;
1886 unsigned int scanlen = cmd->scan_end_arg;
1887 unsigned int wake;
1888 unsigned short triglev;
1889 unsigned short adccon;
1890
1891 if ((cmd->flags & TRIG_WAKE_EOS) != 0) {
1892
1893 wake = scanlen - devpriv->ai_scan_pos;
1894 } else {
1895 if (devpriv->ai_continuous
1896 || (devpriv->ai_scan_count >= PCI230_ADC_FIFOLEVEL_HALFFULL)
1897 || (scanlen >= PCI230_ADC_FIFOLEVEL_HALFFULL)) {
1898 wake = PCI230_ADC_FIFOLEVEL_HALFFULL;
1899 } else {
1900 wake = (devpriv->ai_scan_count * scanlen)
1901 - devpriv->ai_scan_pos;
1902 }
1903 }
1904 if (wake >= PCI230_ADC_FIFOLEVEL_HALFFULL) {
1905 triglev = PCI230_ADC_INT_FIFO_HALF;
1906 } else {
1907 if ((wake > 1) && (devpriv->hwver > 0)) {
1908
1909 if (devpriv->adcfifothresh != wake) {
1910 devpriv->adcfifothresh = wake;
1911 outw(wake, dev->iobase + PCI230P_ADCFFTH);
1912 }
1913 triglev = PCI230P_ADC_INT_FIFO_THRESH;
1914 } else {
1915 triglev = PCI230_ADC_INT_FIFO_NEMPTY;
1916 }
1917 }
1918 adccon = (devpriv->adccon & ~PCI230_ADC_INT_FIFO_MASK) | triglev;
1919 if (adccon != devpriv->adccon) {
1920 devpriv->adccon = adccon;
1921 outw(adccon, dev->iobase + PCI230_ADCCON);
1922 }
1923}
1924
1925static int pci230_ai_inttrig_convert(struct comedi_device *dev,
1926 struct comedi_subdevice *s,
1927 unsigned int trig_num)
1928{
1929 struct pci230_private *devpriv = dev->private;
1930 unsigned long irqflags;
1931
1932 if (trig_num != 0)
1933 return -EINVAL;
1934
1935 spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags);
1936 if (test_bit(AI_CMD_STARTED, &devpriv->state)) {
1937 unsigned int delayus;
1938
1939
1940
1941 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
1942 I8254_MODE0);
1943 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
1944 I8254_MODE1);
1945
1946
1947
1948
1949
1950 if (((devpriv->adccon & PCI230_ADC_IM_MASK)
1951 == PCI230_ADC_IM_DIF)
1952 && (devpriv->hwver == 0)) {
1953
1954 delayus = 8;
1955 } else {
1956
1957 delayus = 4;
1958 }
1959 spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags);
1960 udelay(delayus);
1961 } else {
1962 spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags);
1963 }
1964
1965 return 1;
1966}
1967
1968static int pci230_ai_inttrig_scan_begin(struct comedi_device *dev,
1969 struct comedi_subdevice *s,
1970 unsigned int trig_num)
1971{
1972 struct pci230_private *devpriv = dev->private;
1973 unsigned long irqflags;
1974 unsigned char zgat;
1975
1976 if (trig_num != 0)
1977 return -EINVAL;
1978
1979 spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags);
1980 if (test_bit(AI_CMD_STARTED, &devpriv->state)) {
1981
1982 zgat = GAT_CONFIG(0, GAT_GND);
1983 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
1984 zgat = GAT_CONFIG(0, GAT_VCC);
1985 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
1986 }
1987 spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags);
1988
1989 return 1;
1990}
1991
1992static void pci230_ai_stop(struct comedi_device *dev,
1993 struct comedi_subdevice *s)
1994{
1995 struct pci230_private *devpriv = dev->private;
1996 unsigned long irqflags;
1997 struct comedi_cmd *cmd;
1998 int started;
1999
2000 spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags);
2001 started = test_and_clear_bit(AI_CMD_STARTED, &devpriv->state);
2002 spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags);
2003 if (!started)
2004 return;
2005 cmd = &s->async->cmd;
2006 if (cmd->convert_src == TRIG_TIMER) {
2007
2008 pci230_cancel_ct(dev, 2);
2009 }
2010 if (cmd->scan_begin_src != TRIG_FOLLOW) {
2011
2012 pci230_cancel_ct(dev, 0);
2013 }
2014 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2015
2016
2017 devpriv->int_en &= ~PCI230_INT_ADC;
2018 while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
2019 spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
2020 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2021 }
2022 if (devpriv->ier != devpriv->int_en) {
2023 devpriv->ier = devpriv->int_en;
2024 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
2025 }
2026 spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
2027
2028
2029 devpriv->adccon = (devpriv->adccon & (PCI230_ADC_IR_MASK
2030 | PCI230_ADC_IM_MASK)) |
2031 PCI230_ADC_TRIG_NONE;
2032 outw(devpriv->adccon | PCI230_ADC_FIFO_RESET,
2033 dev->iobase + PCI230_ADCCON);
2034
2035 put_all_resources(dev, OWNER_AICMD);
2036}
2037
2038static void pci230_ai_start(struct comedi_device *dev,
2039 struct comedi_subdevice *s)
2040{
2041 struct pci230_private *devpriv = dev->private;
2042 unsigned long irqflags;
2043 unsigned short conv;
2044 struct comedi_async *async = s->async;
2045 struct comedi_cmd *cmd = &async->cmd;
2046
2047 set_bit(AI_CMD_STARTED, &devpriv->state);
2048 if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) {
2049
2050 async->events |= COMEDI_CB_EOA;
2051 pci230_ai_stop(dev, s);
2052 comedi_event(dev, s);
2053 } else {
2054
2055 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2056 devpriv->int_en |= PCI230_INT_ADC;
2057 devpriv->ier |= PCI230_INT_ADC;
2058 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
2059 spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
2060
2061
2062
2063 switch (cmd->convert_src) {
2064 default:
2065 conv = PCI230_ADC_TRIG_NONE;
2066 break;
2067 case TRIG_TIMER:
2068
2069 conv = PCI230_ADC_TRIG_Z2CT2;
2070 break;
2071 case TRIG_EXT:
2072 if ((cmd->convert_arg & CR_EDGE) != 0) {
2073 if ((cmd->convert_arg & CR_INVERT) == 0) {
2074
2075 conv = PCI230_ADC_TRIG_EXTP;
2076 } else {
2077
2078 conv = PCI230_ADC_TRIG_EXTN;
2079 }
2080 } else {
2081
2082 if (cmd->convert_arg != 0) {
2083
2084 conv = PCI230_ADC_TRIG_EXTP;
2085 } else {
2086
2087 conv = PCI230_ADC_TRIG_EXTN;
2088 }
2089 }
2090 break;
2091 case TRIG_INT:
2092
2093
2094 conv = PCI230_ADC_TRIG_Z2CT2;
2095 break;
2096 }
2097 devpriv->adccon = (devpriv->adccon & ~PCI230_ADC_TRIG_MASK)
2098 | conv;
2099 outw(devpriv->adccon, dev->iobase + PCI230_ADCCON);
2100 if (cmd->convert_src == TRIG_INT)
2101 async->inttrig = pci230_ai_inttrig_convert;
2102
2103
2104
2105 pci230_ai_update_fifo_trigger_level(dev, s);
2106 if (cmd->convert_src == TRIG_TIMER) {
2107
2108 unsigned char zgat;
2109
2110 if (cmd->scan_begin_src != TRIG_FOLLOW) {
2111
2112
2113 zgat = GAT_CONFIG(2, GAT_NOUTNM2);
2114 } else {
2115
2116
2117 zgat = GAT_CONFIG(2, GAT_VCC);
2118 }
2119 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2120 if (cmd->scan_begin_src != TRIG_FOLLOW) {
2121
2122 switch (cmd->scan_begin_src) {
2123 default:
2124 zgat = GAT_CONFIG(0, GAT_VCC);
2125 break;
2126 case TRIG_EXT:
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136 zgat = GAT_CONFIG(0, GAT_EXT);
2137 break;
2138 case TRIG_TIMER:
2139
2140
2141
2142
2143
2144 zgat = GAT_CONFIG(0, GAT_NOUTNM2);
2145 break;
2146 case TRIG_INT:
2147
2148
2149
2150
2151
2152 zgat = GAT_CONFIG(0, GAT_VCC);
2153 break;
2154 }
2155 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2156 switch (cmd->scan_begin_src) {
2157 case TRIG_TIMER:
2158
2159
2160 zgat = GAT_CONFIG(1, GAT_VCC);
2161 outb(zgat, devpriv->iobase1
2162 + PCI230_ZGAT_SCE);
2163 break;
2164 case TRIG_INT:
2165 async->inttrig =
2166 pci230_ai_inttrig_scan_begin;
2167 break;
2168 }
2169 }
2170 } else if (cmd->convert_src != TRIG_INT) {
2171
2172 put_one_resource(dev, RES_Z2CT2, OWNER_AICMD);
2173 }
2174 }
2175}
2176
2177static int pci230_ai_inttrig_start(struct comedi_device *dev,
2178 struct comedi_subdevice *s,
2179 unsigned int trig_num)
2180{
2181 if (trig_num != 0)
2182 return -EINVAL;
2183
2184 s->async->inttrig = NULL;
2185 pci230_ai_start(dev, s);
2186
2187 return 1;
2188}
2189
2190static void pci230_handle_ai(struct comedi_device *dev,
2191 struct comedi_subdevice *s)
2192{
2193 struct pci230_private *devpriv = dev->private;
2194 unsigned int events = 0;
2195 unsigned int status_fifo;
2196 unsigned int i;
2197 unsigned int todo;
2198 unsigned int fifoamount;
2199 struct comedi_async *async = s->async;
2200 unsigned int scanlen = async->cmd.scan_end_arg;
2201
2202
2203 if (devpriv->ai_continuous) {
2204 todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
2205 } else if (devpriv->ai_scan_count == 0) {
2206 todo = 0;
2207 } else if ((devpriv->ai_scan_count > PCI230_ADC_FIFOLEVEL_HALFFULL)
2208 || (scanlen > PCI230_ADC_FIFOLEVEL_HALFFULL)) {
2209 todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
2210 } else {
2211 todo = (devpriv->ai_scan_count * scanlen)
2212 - devpriv->ai_scan_pos;
2213 if (todo > PCI230_ADC_FIFOLEVEL_HALFFULL)
2214 todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
2215 }
2216 if (todo == 0)
2217 return;
2218 fifoamount = 0;
2219 for (i = 0; i < todo; i++) {
2220 if (fifoamount == 0) {
2221
2222 status_fifo = inw(dev->iobase + PCI230_ADCCON);
2223 if ((status_fifo & PCI230_ADC_FIFO_FULL_LATCHED) != 0) {
2224
2225
2226 comedi_error(dev, "AI FIFO overrun");
2227 events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
2228 break;
2229 } else if ((status_fifo & PCI230_ADC_FIFO_EMPTY) != 0) {
2230
2231 break;
2232 } else if ((status_fifo & PCI230_ADC_FIFO_HALF) != 0) {
2233
2234 fifoamount = PCI230_ADC_FIFOLEVEL_HALFFULL;
2235 } else {
2236
2237 if (devpriv->hwver > 0) {
2238
2239 fifoamount = inw(dev->iobase
2240 + PCI230P_ADCFFLEV);
2241 if (fifoamount == 0) {
2242
2243 break;
2244 }
2245 } else {
2246 fifoamount = 1;
2247 }
2248 }
2249 }
2250
2251 if (comedi_buf_put(async, pci230_ai_read(dev)) == 0) {
2252 events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
2253 comedi_error(dev, "AI buffer overflow");
2254 break;
2255 }
2256 fifoamount--;
2257 devpriv->ai_scan_pos++;
2258 if (devpriv->ai_scan_pos == scanlen) {
2259
2260 devpriv->ai_scan_pos = 0;
2261 devpriv->ai_scan_count--;
2262 async->events |= COMEDI_CB_EOS;
2263 }
2264 }
2265 if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) {
2266
2267 events |= COMEDI_CB_EOA;
2268 } else {
2269
2270 events |= COMEDI_CB_BLOCK;
2271 }
2272 async->events |= events;
2273 if ((async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
2274 COMEDI_CB_OVERFLOW)) != 0) {
2275
2276 pci230_ai_stop(dev, s);
2277 } else {
2278
2279 pci230_ai_update_fifo_trigger_level(dev, s);
2280 }
2281}
2282
2283static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
2284{
2285 struct pci230_private *devpriv = dev->private;
2286 unsigned int i, chan, range, diff;
2287 unsigned int res_mask;
2288 unsigned short adccon, adcen;
2289 unsigned char zgat;
2290
2291
2292 struct comedi_async *async = s->async;
2293 struct comedi_cmd *cmd = &async->cmd;
2294
2295
2296
2297
2298 res_mask = 0;
2299
2300
2301 res_mask |= (1U << RES_Z2CT2);
2302 if (cmd->scan_begin_src != TRIG_FOLLOW) {
2303
2304 res_mask |= (1U << RES_Z2CT0);
2305 if (cmd->scan_begin_src == TRIG_TIMER) {
2306
2307 res_mask |= (1U << RES_Z2CT1);
2308 }
2309 }
2310
2311 if (!get_resources(dev, res_mask, OWNER_AICMD))
2312 return -EBUSY;
2313
2314
2315
2316 if (cmd->stop_src == TRIG_COUNT) {
2317 devpriv->ai_scan_count = cmd->stop_arg;
2318 devpriv->ai_continuous = 0;
2319 } else {
2320
2321 devpriv->ai_scan_count = 0;
2322 devpriv->ai_continuous = 1;
2323 }
2324 devpriv->ai_scan_pos = 0;
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343 adccon = PCI230_ADC_FIFO_EN;
2344 adcen = 0;
2345
2346 if (CR_AREF(cmd->chanlist[0]) == AREF_DIFF) {
2347
2348 diff = 1;
2349 adccon |= PCI230_ADC_IM_DIF;
2350 } else {
2351
2352 diff = 0;
2353 adccon |= PCI230_ADC_IM_SE;
2354 }
2355
2356 range = CR_RANGE(cmd->chanlist[0]);
2357 devpriv->ai_bipolar = pci230_ai_bipolar[range];
2358 if (devpriv->ai_bipolar)
2359 adccon |= PCI230_ADC_IR_BIP;
2360 else
2361 adccon |= PCI230_ADC_IR_UNI;
2362
2363 for (i = 0; i < cmd->chanlist_len; i++) {
2364 unsigned int gainshift;
2365
2366 chan = CR_CHAN(cmd->chanlist[i]);
2367 range = CR_RANGE(cmd->chanlist[i]);
2368 if (diff) {
2369 gainshift = 2 * chan;
2370 if (devpriv->hwver == 0) {
2371
2372
2373 adcen |= 3 << gainshift;
2374 } else {
2375
2376
2377 adcen |= 1 << gainshift;
2378 }
2379 } else {
2380 gainshift = (chan & ~1);
2381 adcen |= 1 << chan;
2382 }
2383 devpriv->adcg = (devpriv->adcg & ~(3 << gainshift))
2384 | (pci230_ai_gain[range] << gainshift);
2385 }
2386
2387
2388 outw(adcen, dev->iobase + PCI230_ADCEN);
2389
2390
2391 outw(devpriv->adcg, dev->iobase + PCI230_ADCG);
2392
2393
2394
2395 i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1);
2396
2397
2398
2399 adccon |= PCI230_ADC_INT_FIFO_FULL | PCI230_ADC_TRIG_Z2CT2;
2400
2401
2402
2403
2404
2405
2406 devpriv->adccon = adccon;
2407 outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON);
2408
2409
2410
2411
2412
2413
2414
2415
2416 udelay(25);
2417
2418
2419 outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON);
2420
2421 if (cmd->convert_src == TRIG_TIMER) {
2422
2423
2424
2425 zgat = GAT_CONFIG(2, GAT_GND);
2426 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2427
2428 pci230_ct_setup_ns_mode(dev, 2, I8254_MODE3, cmd->convert_arg,
2429 cmd->flags & TRIG_ROUND_MASK);
2430 if (cmd->scan_begin_src != TRIG_FOLLOW) {
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443 zgat = GAT_CONFIG(0, GAT_VCC);
2444 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2445 pci230_ct_setup_ns_mode(dev, 0, I8254_MODE1,
2446 ((uint64_t) cmd->convert_arg
2447 * cmd->scan_end_arg),
2448 TRIG_ROUND_UP);
2449 if (cmd->scan_begin_src == TRIG_TIMER) {
2450
2451
2452
2453
2454
2455
2456 zgat = GAT_CONFIG(1, GAT_GND);
2457 outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
2458 pci230_ct_setup_ns_mode(dev, 1, I8254_MODE3,
2459 cmd->scan_begin_arg,
2460 cmd->
2461 flags &
2462 TRIG_ROUND_MASK);
2463 }
2464 }
2465 }
2466
2467 if (cmd->start_src == TRIG_INT) {
2468 s->async->inttrig = pci230_ai_inttrig_start;
2469 } else {
2470
2471 pci230_ai_start(dev, s);
2472 }
2473
2474 return 0;
2475}
2476
2477static int pci230_ai_cancel(struct comedi_device *dev,
2478 struct comedi_subdevice *s)
2479{
2480 pci230_ai_stop(dev, s);
2481 return 0;
2482}
2483
2484
2485static irqreturn_t pci230_interrupt(int irq, void *d)
2486{
2487 unsigned char status_int, valid_status_int;
2488 struct comedi_device *dev = (struct comedi_device *)d;
2489 struct pci230_private *devpriv = dev->private;
2490 struct comedi_subdevice *s;
2491 unsigned long irqflags;
2492
2493
2494 status_int = inb(devpriv->iobase1 + PCI230_INT_STAT);
2495
2496 if (status_int == PCI230_INT_DISABLE)
2497 return IRQ_NONE;
2498
2499
2500 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2501 valid_status_int = devpriv->int_en & status_int;
2502
2503
2504
2505 devpriv->ier = devpriv->int_en & ~status_int;
2506 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
2507 devpriv->intr_running = 1;
2508 devpriv->intr_cpuid = THISCPU;
2509 spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519 if ((valid_status_int & PCI230_INT_ZCLK_CT1) != 0) {
2520 s = dev->write_subdev;
2521 pci230_handle_ao_nofifo(dev, s);
2522 comedi_event(dev, s);
2523 }
2524
2525 if ((valid_status_int & PCI230P2_INT_DAC) != 0) {
2526 s = dev->write_subdev;
2527 pci230_handle_ao_fifo(dev, s);
2528 comedi_event(dev, s);
2529 }
2530
2531 if ((valid_status_int & PCI230_INT_ADC) != 0) {
2532 s = dev->read_subdev;
2533 pci230_handle_ai(dev, s);
2534 comedi_event(dev, s);
2535 }
2536
2537
2538 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2539 if (devpriv->ier != devpriv->int_en) {
2540 devpriv->ier = devpriv->int_en;
2541 outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
2542 }
2543 devpriv->intr_running = 0;
2544 spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
2545
2546 return IRQ_HANDLED;
2547}
2548
2549
2550static bool pci230_match_pci_board(const struct pci230_board *board,
2551 struct pci_dev *pci_dev)
2552{
2553
2554 if (board->id != pci_dev->device)
2555 return false;
2556 if (board->min_hwver == 0)
2557 return true;
2558
2559 if (pci_resource_len(pci_dev, 3) < 32)
2560 return false;
2561
2562
2563 return true;
2564}
2565
2566
2567static const struct pci230_board *pci230_find_pci_board(struct pci_dev *pci_dev)
2568{
2569 unsigned int i;
2570
2571 for (i = 0; i < ARRAY_SIZE(pci230_boards); i++)
2572 if (pci230_match_pci_board(&pci230_boards[i], pci_dev))
2573 return &pci230_boards[i];
2574 return NULL;
2575}
2576
2577
2578static struct pci_dev *pci230_find_pci_dev(struct comedi_device *dev,
2579 struct comedi_devconfig *it)
2580{
2581 const struct pci230_board *thisboard = comedi_board(dev);
2582 struct pci_dev *pci_dev = NULL;
2583 int bus = it->options[0];
2584 int slot = it->options[1];
2585
2586 for_each_pci_dev(pci_dev) {
2587
2588 if (pci_dev->vendor != PCI_VENDOR_ID_AMPLICON)
2589 continue;
2590
2591 if ((bus || slot) &&
2592 (bus != pci_dev->bus->number ||
2593 slot != PCI_SLOT(pci_dev->devfn)))
2594 continue;
2595 if (thisboard->id == PCI_DEVICE_ID_INVALID) {
2596
2597 const struct pci230_board *foundboard;
2598
2599 foundboard = pci230_find_pci_board(pci_dev);
2600 if (foundboard == NULL)
2601 continue;
2602
2603 dev->board_ptr = foundboard;
2604 } else {
2605
2606 if (!pci230_match_pci_board(thisboard, pci_dev))
2607 continue;
2608 }
2609 return pci_dev;
2610 }
2611 dev_err(dev->class_dev,
2612 "No supported board found! (req. bus %d, slot %d)\n",
2613 bus, slot);
2614 return NULL;
2615}
2616
2617static int pci230_alloc_private(struct comedi_device *dev)
2618{
2619 struct pci230_private *devpriv;
2620
2621 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
2622 if (!devpriv)
2623 return -ENOMEM;
2624 dev->private = devpriv;
2625
2626 spin_lock_init(&devpriv->isr_spinlock);
2627 spin_lock_init(&devpriv->res_spinlock);
2628 spin_lock_init(&devpriv->ai_stop_spinlock);
2629 spin_lock_init(&devpriv->ao_stop_spinlock);
2630 return 0;
2631}
2632
2633
2634static int pci230_attach_common(struct comedi_device *dev,
2635 struct pci_dev *pci_dev)
2636{
2637 const struct pci230_board *thisboard = comedi_board(dev);
2638 struct pci230_private *devpriv = dev->private;
2639 struct comedi_subdevice *s;
2640 unsigned long iobase1, iobase2;
2641
2642 int irq_hdl, rc;
2643
2644 comedi_set_hw_dev(dev, &pci_dev->dev);
2645
2646 dev->board_name = thisboard->name;
2647
2648 if (comedi_pci_enable(pci_dev, "amplc_pci230") < 0) {
2649 dev_err(dev->class_dev,
2650 "failed to enable PCI device and request regions\n");
2651 return -EIO;
2652 }
2653
2654
2655 iobase1 = pci_resource_start(pci_dev, 2);
2656 iobase2 = pci_resource_start(pci_dev, 3);
2657 dev_dbg(dev->class_dev,
2658 "%s I/O region 1 0x%04lx I/O region 2 0x%04lx\n",
2659 dev->board_name, iobase1, iobase2);
2660 devpriv->iobase1 = iobase1;
2661 dev->iobase = iobase2;
2662
2663 devpriv->daccon = inw(dev->iobase + PCI230_DACCON) & PCI230_DAC_OR_MASK;
2664
2665
2666 if (pci_resource_len(pci_dev, 3) >= 32) {
2667 unsigned short extfunc = 0;
2668
2669 devpriv->hwver = inw(dev->iobase + PCI230P_HWVER);
2670 if (devpriv->hwver < thisboard->min_hwver) {
2671 dev_err(dev->class_dev,
2672 "%s - bad hardware version - got %u, need %u\n",
2673 dev->board_name, devpriv->hwver,
2674 thisboard->min_hwver);
2675 return -EIO;
2676 }
2677 if (devpriv->hwver > 0) {
2678 if (!thisboard->have_dio) {
2679
2680
2681
2682
2683
2684 extfunc |= PCI230P_EXTFUNC_GAT_EXTTRIG;
2685 }
2686 if ((thisboard->ao_chans > 0)
2687 && (devpriv->hwver >= 2)) {
2688
2689 extfunc |= PCI230P2_EXTFUNC_DACFIFO;
2690 }
2691 }
2692 outw(extfunc, dev->iobase + PCI230P_EXTFUNC);
2693 if ((extfunc & PCI230P2_EXTFUNC_DACFIFO) != 0) {
2694
2695
2696 outw(devpriv->daccon | PCI230P2_DAC_FIFO_EN
2697 | PCI230P2_DAC_FIFO_RESET,
2698 dev->iobase + PCI230_DACCON);
2699
2700 outw(0, dev->iobase + PCI230P2_DACEN);
2701
2702 outw(devpriv->daccon, dev->iobase + PCI230_DACCON);
2703 }
2704 }
2705
2706 outb(0, devpriv->iobase1 + PCI230_INT_SCE);
2707
2708 devpriv->adcg = 0;
2709 devpriv->adccon = PCI230_ADC_TRIG_NONE | PCI230_ADC_IM_SE
2710 | PCI230_ADC_IR_BIP;
2711 outw(1 << 0, dev->iobase + PCI230_ADCEN);
2712 outw(devpriv->adcg, dev->iobase + PCI230_ADCG);
2713 outw(devpriv->adccon | PCI230_ADC_FIFO_RESET,
2714 dev->iobase + PCI230_ADCCON);
2715
2716 irq_hdl = request_irq(pci_dev->irq, pci230_interrupt,
2717 IRQF_SHARED, "amplc_pci230", dev);
2718 if (irq_hdl < 0) {
2719 dev_warn(dev->class_dev,
2720 "unable to register irq %u, commands will not be available\n",
2721 pci_dev->irq);
2722 } else {
2723 dev->irq = pci_dev->irq;
2724 dev_dbg(dev->class_dev, "registered irq %u\n", pci_dev->irq);
2725 }
2726
2727 rc = comedi_alloc_subdevices(dev, 3);
2728 if (rc)
2729 return rc;
2730
2731 s = &dev->subdevices[0];
2732
2733 s->type = COMEDI_SUBD_AI;
2734 s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND;
2735 s->n_chan = thisboard->ai_chans;
2736 s->maxdata = (1 << thisboard->ai_bits) - 1;
2737 s->range_table = &pci230_ai_range;
2738 s->insn_read = &pci230_ai_rinsn;
2739 s->len_chanlist = 256;
2740
2741 if (irq_hdl == 0) {
2742 dev->read_subdev = s;
2743 s->subdev_flags |= SDF_CMD_READ;
2744 s->do_cmd = &pci230_ai_cmd;
2745 s->do_cmdtest = &pci230_ai_cmdtest;
2746 s->cancel = pci230_ai_cancel;
2747 }
2748 s = &dev->subdevices[1];
2749
2750 if (thisboard->ao_chans > 0) {
2751 s->type = COMEDI_SUBD_AO;
2752 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
2753 s->n_chan = thisboard->ao_chans;
2754 s->maxdata = (1 << thisboard->ao_bits) - 1;
2755 s->range_table = &pci230_ao_range;
2756 s->insn_write = &pci230_ao_winsn;
2757 s->insn_read = &pci230_ao_rinsn;
2758 s->len_chanlist = thisboard->ao_chans;
2759
2760
2761 if (irq_hdl == 0) {
2762 dev->write_subdev = s;
2763 s->subdev_flags |= SDF_CMD_WRITE;
2764 s->do_cmd = &pci230_ao_cmd;
2765 s->do_cmdtest = &pci230_ao_cmdtest;
2766 s->cancel = pci230_ao_cancel;
2767 }
2768 } else {
2769 s->type = COMEDI_SUBD_UNUSED;
2770 }
2771 s = &dev->subdevices[2];
2772
2773 if (thisboard->have_dio) {
2774 rc = subdev_8255_init(dev, s, NULL,
2775 (devpriv->iobase1 + PCI230_PPI_X_BASE));
2776 if (rc < 0)
2777 return rc;
2778 } else {
2779 s->type = COMEDI_SUBD_UNUSED;
2780 }
2781 dev_info(dev->class_dev, "attached\n");
2782 return 1;
2783}
2784
2785static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it)
2786{
2787 const struct pci230_board *thisboard = comedi_board(dev);
2788 struct pci_dev *pci_dev;
2789 int rc;
2790
2791 dev_info(dev->class_dev, "amplc_pci230: attach %s %d,%d\n",
2792 thisboard->name, it->options[0], it->options[1]);
2793
2794 rc = pci230_alloc_private(dev);
2795 if (rc)
2796 return rc;
2797
2798 pci_dev = pci230_find_pci_dev(dev, it);
2799 if (!pci_dev)
2800 return -EIO;
2801 return pci230_attach_common(dev, pci_dev);
2802}
2803
2804static int pci230_auto_attach(struct comedi_device *dev,
2805 unsigned long context_unused)
2806{
2807 struct pci_dev *pci_dev = comedi_to_pci_dev(dev);
2808 int rc;
2809
2810 dev_info(dev->class_dev, "amplc_pci230: attach pci %s\n",
2811 pci_name(pci_dev));
2812
2813 rc = pci230_alloc_private(dev);
2814 if (rc)
2815 return rc;
2816
2817 dev->board_ptr = pci230_find_pci_board(pci_dev);
2818 if (dev->board_ptr == NULL) {
2819 dev_err(dev->class_dev,
2820 "amplc_pci230: BUG! cannot determine board type!\n");
2821 return -EINVAL;
2822 }
2823
2824
2825
2826
2827
2828
2829 pci_dev_get(pci_dev);
2830 return pci230_attach_common(dev, pci_dev);
2831}
2832
2833static void pci230_detach(struct comedi_device *dev)
2834{
2835 const struct pci230_board *thisboard = comedi_board(dev);
2836 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
2837
2838 if (dev->subdevices && thisboard->have_dio)
2839 subdev_8255_cleanup(dev, &dev->subdevices[2]);
2840 if (dev->irq)
2841 free_irq(dev->irq, dev);
2842 if (pcidev) {
2843 if (dev->iobase)
2844 comedi_pci_disable(pcidev);
2845 pci_dev_put(pcidev);
2846 }
2847}
2848
2849static struct comedi_driver amplc_pci230_driver = {
2850 .driver_name = "amplc_pci230",
2851 .module = THIS_MODULE,
2852 .attach = pci230_attach,
2853 .auto_attach = pci230_auto_attach,
2854 .detach = pci230_detach,
2855 .board_name = &pci230_boards[0].name,
2856 .offset = sizeof(pci230_boards[0]),
2857 .num_names = ARRAY_SIZE(pci230_boards),
2858};
2859
2860static int amplc_pci230_pci_probe(struct pci_dev *dev,
2861 const struct pci_device_id *ent)
2862{
2863 return comedi_pci_auto_config(dev, &lc_pci230_driver);
2864}
2865
2866static void amplc_pci230_pci_remove(struct pci_dev *dev)
2867{
2868 comedi_pci_auto_unconfig(dev);
2869}
2870
2871static DEFINE_PCI_DEVICE_TABLE(amplc_pci230_pci_table) = {
2872 { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230) },
2873 { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260) },
2874 { 0 }
2875};
2876MODULE_DEVICE_TABLE(pci, amplc_pci230_pci_table);
2877
2878static struct pci_driver amplc_pci230_pci_driver = {
2879 .name = "amplc_pci230",
2880 .id_table = amplc_pci230_pci_table,
2881 .probe = amplc_pci230_pci_probe,
2882 .remove = amplc_pci230_pci_remove
2883};
2884module_comedi_pci_driver(amplc_pci230_driver, amplc_pci230_pci_driver);
2885
2886MODULE_AUTHOR("Comedi http://www.comedi.org");
2887MODULE_DESCRIPTION("Comedi low-level driver");
2888MODULE_LICENSE("GPL");
2889