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