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