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