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