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