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