2 comedi/drivers/pcl818.c
4 Author: Michal Dobes <dobes@tesnet.cz>
6 hardware driver for Advantech cards:
7 card: PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818, PCL-718
8 driver: pcl818l, pcl818h, pcl818hd, pcl818hg, pcl818, pcl718
12 Description: Advantech PCL-818 cards, PCL-718
13 Author: Michal Dobes <dobes@tesnet.cz>
14 Devices: [Advantech] PCL-818L (pcl818l), PCL-818H (pcl818h),
15 PCL-818HD (pcl818hd), PCL-818HG (pcl818hg), PCL-818 (pcl818),
19 All cards have 16 SE/8 DIFF ADCs, one or two DACs, 16 DI and 16 DO.
20 Differences are only at maximal sample speed, range list and FIFO
22 The driver support AI mode 0, 1, 3 other subdevices (AO, DI, DO) support
23 only mode 0. If DMA/FIFO/INT are disabled then AI support only mode 0.
24 PCL-818HD and PCL-818HG support 1kword FIFO. Driver support this FIFO
25 but this code is untested.
26 A word or two about DMA. Driver support DMA operations at two ways:
27 1) DMA uses two buffers and after one is filled then is generated
28 INT and DMA restart with second buffer. With this mode I'm unable run
29 more that 80Ksamples/secs without data dropouts on K6/233.
30 2) DMA uses one buffer and run in autoinit mode and the data are
31 from DMA buffer moved on the fly with 2kHz interrupts from RTC.
32 This mode is used if the interrupt 8 is available for allocation.
33 If not, then first DMA mode is used. With this I can run at
34 full speed one card (100ksamples/secs) or two cards with
35 60ksamples/secs each (more is problem on account of ISA limitations).
36 To use this mode you must have compiled kernel with disabled
37 "Enhanced Real Time Clock Support".
38 Maybe you can have problems if you use xntpd or similar.
39 If you've data dropouts with DMA mode 2 then:
41 b) switch text mode console to fb.
45 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
46 [2] - DMA (0=disable, 1, 3)
47 [3] - 0, 10=10MHz clock for 8254
48 1= 1MHz clock for 8254
49 [4] - 0, 5=A/D input -5V.. +5V
50 1, 10=A/D input -10V..+10V
51 [5] - 0, 5=D/A output 0-5V (internal reference -5V)
52 1, 10=D/A output 0-10V (internal reference -10V)
53 2 =D/A output unknown (external reference)
55 Options for PCL-818, PCL-818H:
57 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
58 [2] - DMA (0=disable, 1, 3)
59 [3] - 0, 10=10MHz clock for 8254
60 1= 1MHz clock for 8254
61 [4] - 0, 5=D/A output 0-5V (internal reference -5V)
62 1, 10=D/A output 0-10V (internal reference -10V)
63 2 =D/A output unknown (external reference)
65 Options for PCL-818HD, PCL-818HG:
67 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
68 [2] - DMA/FIFO (-1=use FIFO, 0=disable both FIFO and DMA,
69 1=use DMA ch 1, 3=use DMA ch 3)
70 [3] - 0, 10=10MHz clock for 8254
71 1= 1MHz clock for 8254
72 [4] - 0, 5=D/A output 0-5V (internal reference -5V)
73 1, 10=D/A output 0-10V (internal reference -10V)
74 2 =D/A output unknown (external reference)
78 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
79 [2] - DMA (0=disable, 1, 3)
80 [3] - 0, 10=10MHz clock for 8254
81 1= 1MHz clock for 8254
82 [4] - 0=A/D Range is +/-10V
87 5= user defined bipolar
92 10= user defined unipolar
93 [5] - 0, 5=D/A outputs 0-5V (internal reference -5V)
94 1, 10=D/A outputs 0-10V (internal reference -10V)
95 2=D/A outputs unknown (external reference)
96 [6] - 0, 60=max 60kHz A/D sampling
97 1,100=max 100kHz A/D sampling (PCL-718 with Option 001 installed)
101 #include "../comedidev.h"
103 #include <linux/ioport.h>
104 #include <linux/mc146818rtc.h>
105 #include <linux/gfp.h>
106 #include <linux/delay.h>
107 #include <linux/io.h>
112 /* #define PCL818_MODE13_AO 1 */
114 /* boards constants */
116 #define boardPCL818L 0
117 #define boardPCL818H 1
118 #define boardPCL818HD 2
119 #define boardPCL818HG 3
120 #define boardPCL818 4
121 #define boardPCL718 5
124 #define PCLx1x_RANGE 16
125 /* IO space len if we use FIFO */
126 #define PCLx1xFIFO_RANGE 32
128 /* W: clear INT request */
129 #define PCL818_CLRINT 8
130 /* R: return status byte */
131 #define PCL818_STATUS 8
132 /* R: A/D high byte W: A/D range control */
133 #define PCL818_RANGE 1
134 /* R: next mux scan channel W: mux scan channel & range control pointer */
136 /* R/W: operation control register */
137 #define PCL818_CONTROL 9
138 /* W: counter enable */
139 #define PCL818_CNTENABLE 10
141 /* R: low byte of A/D W: soft A/D trigger */
142 #define PCL818_AD_LO 0
143 /* R: high byte of A/D W: A/D range control */
144 #define PCL818_AD_HI 1
145 /* W: D/A low&high byte */
146 #define PCL818_DA_LO 4
147 #define PCL818_DA_HI 5
148 /* R: low&high byte of DI */
149 #define PCL818_DI_LO 3
150 #define PCL818_DI_HI 11
151 /* W: low&high byte of DO */
152 #define PCL818_DO_LO 3
153 #define PCL818_DO_HI 11
154 /* W: PCL718 second D/A */
155 #define PCL718_DA2_LO 6
156 #define PCL718_DA2_HI 7
158 #define PCL818_CTR0 12
159 #define PCL818_CTR1 13
160 #define PCL818_CTR2 14
161 /* W: counter control */
162 #define PCL818_CTRCTL 15
164 /* W: fifo enable/disable */
165 #define PCL818_FI_ENABLE 6
166 /* W: fifo interrupt clear */
167 #define PCL818_FI_INTCLR 20
168 /* W: fifo interrupt clear */
169 #define PCL818_FI_FLUSH 25
171 #define PCL818_FI_STATUS 25
172 /* R: one record from FIFO */
173 #define PCL818_FI_DATALO 23
174 #define PCL818_FI_DATAHI 23
176 /* type of interrupt handler */
177 #define INT_TYPE_AI1_INT 1
178 #define INT_TYPE_AI1_DMA 2
179 #define INT_TYPE_AI1_FIFO 3
180 #define INT_TYPE_AI3_INT 4
181 #define INT_TYPE_AI3_DMA 5
182 #define INT_TYPE_AI3_FIFO 6
183 #ifdef PCL818_MODE13_AO
184 #define INT_TYPE_AO1_INT 7
185 #define INT_TYPE_AO3_INT 8
190 #define INT_TYPE_AI1_DMA_RTC 9
191 #define INT_TYPE_AI3_DMA_RTC 10
194 #define RTC_IO_EXTENT 0x10
197 #define MAGIC_DMA_WORD 0x5a5a
199 static const struct comedi_lrange range_pcl818h_ai
= { 9, {
212 static const struct comedi_lrange range_pcl818hg_ai
= { 10, {
228 static const struct comedi_lrange range_pcl818l_l_ai
= { 4, {
236 static const struct comedi_lrange range_pcl818l_h_ai
= { 4, {
244 static const struct comedi_lrange range718_bipolar1
= { 1, {BIP_RANGE(1),} };
245 static const struct comedi_lrange range718_bipolar0_5
=
246 { 1, {BIP_RANGE(0.5),} };
247 static const struct comedi_lrange range718_unipolar2
= { 1, {UNI_RANGE(2),} };
248 static const struct comedi_lrange range718_unipolar1
= { 1, {BIP_RANGE(1),} };
251 static int RTC_lock
; /* RTC lock */
252 static int RTC_timer_lock
; /* RTC int lock */
255 struct pcl818_board
{
257 const char *name
; /* driver name */
258 int n_ranges
; /* len of range list */
259 int n_aichan_se
; /* num of A/D chans in single ended mode */
260 int n_aichan_diff
; /* num of A/D chans in diferencial mode */
261 unsigned int ns_min
; /* minimal allowed delay between samples (in ns) */
262 int n_aochan
; /* num of D/A chans */
263 int n_dichan
; /* num of DI chans */
264 int n_dochan
; /* num of DO chans */
265 const struct comedi_lrange
*ai_range_type
; /* default A/D rangelist */
266 const struct comedi_lrange
*ao_range_type
; /* default D/A rangelist */
267 unsigned int io_range
; /* len of IO space */
268 unsigned int IRQbits
; /* allowed interrupts */
269 unsigned int DMAbits
; /* allowed DMA chans */
270 int ai_maxdata
; /* maxdata for A/D */
271 int ao_maxdata
; /* maxdata for D/A */
272 unsigned char fifo
; /* 1=board has FIFO */
276 struct pcl818_private
{
278 unsigned int dma
; /* used DMA, 0=don't use DMA */
279 int dma_rtc
; /* 1=RTC used with DMA, 0=no RTC alloc */
280 unsigned int io_range
;
282 unsigned long rtc_iobase
; /* RTC port region */
283 unsigned int rtc_iosize
;
284 unsigned int rtc_irq
;
285 struct timer_list rtc_irq_timer
; /* timer for RTC sanity check */
286 unsigned long rtc_freq
; /* RTC int freq */
287 int rtc_irq_blocked
; /* 1=we now do AI with DMA&RTC */
289 unsigned long dmabuf
[2]; /* pointers to begin of DMA buffers */
290 unsigned int dmapages
[2]; /* len of DMA buffers in PAGE_SIZEs */
291 unsigned int hwdmaptr
[2]; /* hardware address of DMA buffers */
292 unsigned int hwdmasize
[2]; /* len of DMA buffers in Bytes */
293 unsigned int dmasamplsize
; /* size in samples hwdmasize[0]/2 */
294 unsigned int last_top_dma
; /* DMA pointer in last RTC int */
295 int next_dma_buf
; /* which DMA buffer will be used next round */
296 long dma_runs_to_end
; /* how many we must permorm DMA transfer to end of record */
297 unsigned long last_dma_run
; /* how many bytes we must transfer on last DMA page */
298 unsigned char neverending_ai
; /* if=1, then we do neverending record (you must use cancel()) */
299 unsigned int ns_min
; /* manimal allowed delay between samples (in us) for actual card */
300 int i8253_osc_base
; /* 1/frequency of on board oscilator in ns */
301 int irq_free
; /* 1=have allocated IRQ */
302 int irq_blocked
; /* 1=IRQ now uses any subdev */
303 int irq_was_now_closed
; /* when IRQ finish, there's stored int818_mode for last interrupt */
304 int ai_mode
; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
305 struct comedi_subdevice
*last_int_sub
; /* ptr to subdevice which now finish */
306 int ai_act_scan
; /* how many scans we finished */
307 int ai_act_chan
; /* actual position in actual scan */
308 unsigned int act_chanlist
[16]; /* MUX setting for actual AI operations */
309 unsigned int act_chanlist_len
; /* how long is actual MUX list */
310 unsigned int act_chanlist_pos
; /* actual position in MUX list */
311 unsigned int ai_scans
; /* len of scanlist */
312 unsigned int ai_n_chan
; /* how many channels is measured */
313 unsigned int *ai_chanlist
; /* actaul chanlist */
314 unsigned int ai_flags
; /* flaglist */
315 unsigned int ai_data_len
; /* len of data buffer */
316 short *ai_data
; /* data buffer */
317 unsigned int ai_timer1
; /* timers */
318 unsigned int ai_timer2
;
319 struct comedi_subdevice
*sub_ai
; /* ptr to AI subdevice */
320 unsigned char usefifo
; /* 1=use fifo */
321 unsigned int ao_readback
[2];
324 static const unsigned int muxonechan
[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */
325 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
328 #define devpriv ((struct pcl818_private *)dev->private)
331 ==============================================================================
333 static void setup_channel_list(struct comedi_device
*dev
,
334 struct comedi_subdevice
*s
,
335 unsigned int *chanlist
, unsigned int n_chan
,
336 unsigned int seglen
);
337 static int check_channel_list(struct comedi_device
*dev
,
338 struct comedi_subdevice
*s
,
339 unsigned int *chanlist
, unsigned int n_chan
);
341 static int pcl818_ai_cancel(struct comedi_device
*dev
,
342 struct comedi_subdevice
*s
);
343 static void start_pacer(struct comedi_device
*dev
, int mode
,
344 unsigned int divisor1
, unsigned int divisor2
);
347 static int set_rtc_irq_bit(unsigned char bit
);
348 static void rtc_dropped_irq(unsigned long data
);
349 static int rtc_setfreq_irq(int freq
);
353 ==============================================================================
354 ANALOG INPUT MODE0, 818 cards, slow version
356 static int pcl818_ai_insn_read(struct comedi_device
*dev
,
357 struct comedi_subdevice
*s
,
358 struct comedi_insn
*insn
, unsigned int *data
)
363 /* software trigger, DMA and INT off */
364 outb(0, dev
->iobase
+ PCL818_CONTROL
);
367 outb(muxonechan
[CR_CHAN(insn
->chanspec
)], dev
->iobase
+ PCL818_MUX
);
370 outb(CR_RANGE(insn
->chanspec
), dev
->iobase
+ PCL818_RANGE
);
372 for (n
= 0; n
< insn
->n
; n
++) {
374 /* clear INT (conversion end) flag */
375 outb(0, dev
->iobase
+ PCL818_CLRINT
);
377 /* start conversion */
378 outb(0, dev
->iobase
+ PCL818_AD_LO
);
382 if (inb(dev
->iobase
+ PCL818_STATUS
) & 0x10)
386 comedi_error(dev
, "A/D insn timeout");
387 /* clear INT (conversion end) flag */
388 outb(0, dev
->iobase
+ PCL818_CLRINT
);
392 data
[n
] = ((inb(dev
->iobase
+ PCL818_AD_HI
) << 4) |
393 (inb(dev
->iobase
+ PCL818_AD_LO
) >> 4));
400 ==============================================================================
401 ANALOG OUTPUT MODE0, 818 cards
402 only one sample per call is supported
404 static int pcl818_ao_insn_read(struct comedi_device
*dev
,
405 struct comedi_subdevice
*s
,
406 struct comedi_insn
*insn
, unsigned int *data
)
409 int chan
= CR_CHAN(insn
->chanspec
);
411 for (n
= 0; n
< insn
->n
; n
++)
412 data
[n
] = devpriv
->ao_readback
[chan
];
417 static int pcl818_ao_insn_write(struct comedi_device
*dev
,
418 struct comedi_subdevice
*s
,
419 struct comedi_insn
*insn
, unsigned int *data
)
422 int chan
= CR_CHAN(insn
->chanspec
);
424 for (n
= 0; n
< insn
->n
; n
++) {
425 devpriv
->ao_readback
[chan
] = data
[n
];
426 outb((data
[n
] & 0x000f) << 4, dev
->iobase
+
427 (chan
? PCL718_DA2_LO
: PCL818_DA_LO
));
428 outb((data
[n
] & 0x0ff0) >> 4, dev
->iobase
+
429 (chan
? PCL718_DA2_HI
: PCL818_DA_HI
));
436 ==============================================================================
437 DIGITAL INPUT MODE0, 818 cards
439 only one sample per call is supported
441 static int pcl818_di_insn_bits(struct comedi_device
*dev
,
442 struct comedi_subdevice
*s
,
443 struct comedi_insn
*insn
, unsigned int *data
)
445 data
[1] = inb(dev
->iobase
+ PCL818_DI_LO
) |
446 (inb(dev
->iobase
+ PCL818_DI_HI
) << 8);
452 ==============================================================================
453 DIGITAL OUTPUT MODE0, 818 cards
455 only one sample per call is supported
457 static int pcl818_do_insn_bits(struct comedi_device
*dev
,
458 struct comedi_subdevice
*s
,
459 struct comedi_insn
*insn
, unsigned int *data
)
461 s
->state
&= ~data
[0];
462 s
->state
|= (data
[0] & data
[1]);
464 outb(s
->state
& 0xff, dev
->iobase
+ PCL818_DO_LO
);
465 outb((s
->state
>> 8), dev
->iobase
+ PCL818_DO_HI
);
473 ==============================================================================
474 analog input interrupt mode 1 & 3, 818 cards
475 one sample per interrupt version
477 static irqreturn_t
interrupt_pcl818_ai_mode13_int(int irq
, void *d
)
479 struct comedi_device
*dev
= d
;
480 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
482 int timeout
= 50; /* wait max 50us */
485 if (inb(dev
->iobase
+ PCL818_STATUS
) & 0x10)
489 outb(0, dev
->iobase
+ PCL818_STATUS
); /* clear INT request */
490 comedi_error(dev
, "A/D mode1/3 IRQ without DRDY!");
491 pcl818_ai_cancel(dev
, s
);
492 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
493 comedi_event(dev
, s
);
497 low
= inb(dev
->iobase
+ PCL818_AD_LO
);
498 comedi_buf_put(s
->async
, ((inb(dev
->iobase
+ PCL818_AD_HI
) << 4) | (low
>> 4))); /* get one sample */
499 outb(0, dev
->iobase
+ PCL818_CLRINT
); /* clear INT request */
501 if ((low
& 0xf) != devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]) { /* dropout! */
503 ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
505 devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]);
506 pcl818_ai_cancel(dev
, s
);
507 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
508 comedi_event(dev
, s
);
511 devpriv
->act_chanlist_pos
++;
512 if (devpriv
->act_chanlist_pos
>= devpriv
->act_chanlist_len
)
513 devpriv
->act_chanlist_pos
= 0;
515 s
->async
->cur_chan
++;
516 if (s
->async
->cur_chan
>= devpriv
->ai_n_chan
) {
518 s
->async
->cur_chan
= 0;
519 devpriv
->ai_act_scan
--;
522 if (!devpriv
->neverending_ai
) {
523 if (devpriv
->ai_act_scan
== 0) { /* all data sampled */
524 pcl818_ai_cancel(dev
, s
);
525 s
->async
->events
|= COMEDI_CB_EOA
;
528 comedi_event(dev
, s
);
533 ==============================================================================
534 analog input dma mode 1 & 3, 818 cards
536 static irqreturn_t
interrupt_pcl818_ai_mode13_dma(int irq
, void *d
)
538 struct comedi_device
*dev
= d
;
539 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
544 disable_dma(devpriv
->dma
);
545 devpriv
->next_dma_buf
= 1 - devpriv
->next_dma_buf
;
546 if ((devpriv
->dma_runs_to_end
) > -1 || devpriv
->neverending_ai
) { /* switch dma bufs */
547 set_dma_mode(devpriv
->dma
, DMA_MODE_READ
);
548 flags
= claim_dma_lock();
549 set_dma_addr(devpriv
->dma
,
550 devpriv
->hwdmaptr
[devpriv
->next_dma_buf
]);
551 if (devpriv
->dma_runs_to_end
|| devpriv
->neverending_ai
) {
552 set_dma_count(devpriv
->dma
,
553 devpriv
->hwdmasize
[devpriv
->
556 set_dma_count(devpriv
->dma
, devpriv
->last_dma_run
);
558 release_dma_lock(flags
);
559 enable_dma(devpriv
->dma
);
561 printk("comedi: A/D mode1/3 IRQ \n");
563 devpriv
->dma_runs_to_end
--;
564 outb(0, dev
->iobase
+ PCL818_CLRINT
); /* clear INT request */
565 ptr
= (short *)devpriv
->dmabuf
[1 - devpriv
->next_dma_buf
];
567 len
= devpriv
->hwdmasize
[0] >> 1;
570 for (i
= 0; i
< len
; i
++) {
571 if ((ptr
[bufptr
] & 0xf) != devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]) { /* dropout! */
573 ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
575 devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
],
576 devpriv
->act_chanlist_pos
);
577 pcl818_ai_cancel(dev
, s
);
578 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
579 comedi_event(dev
, s
);
583 comedi_buf_put(s
->async
, ptr
[bufptr
++] >> 4); /* get one sample */
585 devpriv
->act_chanlist_pos
++;
586 if (devpriv
->act_chanlist_pos
>= devpriv
->act_chanlist_len
)
587 devpriv
->act_chanlist_pos
= 0;
589 s
->async
->cur_chan
++;
590 if (s
->async
->cur_chan
>= devpriv
->ai_n_chan
) {
591 s
->async
->cur_chan
= 0;
592 devpriv
->ai_act_scan
--;
595 if (!devpriv
->neverending_ai
)
596 if (devpriv
->ai_act_scan
== 0) { /* all data sampled */
597 pcl818_ai_cancel(dev
, s
);
598 s
->async
->events
|= COMEDI_CB_EOA
;
599 comedi_event(dev
, s
);
600 /* printk("done int ai13 dma\n"); */
606 comedi_event(dev
, s
);
612 ==============================================================================
613 analog input dma mode 1 & 3 over RTC, 818 cards
615 static irqreturn_t
interrupt_pcl818_ai_mode13_dma_rtc(int irq
, void *d
)
617 struct comedi_device
*dev
= d
;
618 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
620 unsigned int top1
, top2
, i
, bufptr
;
622 short *dmabuf
= (short *)devpriv
->dmabuf
[0];
625 switch (devpriv
->ai_mode
) {
626 case INT_TYPE_AI1_DMA_RTC
:
627 case INT_TYPE_AI3_DMA_RTC
:
628 tmp
= (CMOS_READ(RTC_INTR_FLAGS
) & 0xF0);
629 mod_timer(&devpriv
->rtc_irq_timer
,
630 jiffies
+ HZ
/ devpriv
->rtc_freq
+ 2 * HZ
/ 100);
632 for (i
= 0; i
< 10; i
++) {
633 top1
= get_dma_residue(devpriv
->dma
);
634 top2
= get_dma_residue(devpriv
->dma
);
641 top1
= devpriv
->hwdmasize
[0] - top1
; /* where is now DMA in buffer */
643 ofs_dats
= top1
- devpriv
->last_top_dma
; /* new samples from last call */
645 ofs_dats
= (devpriv
->dmasamplsize
) + ofs_dats
;
647 return IRQ_HANDLED
; /* exit=no new samples from last call */
649 i
= devpriv
->last_top_dma
- 1;
650 i
&= (devpriv
->dmasamplsize
- 1);
652 if (dmabuf
[i
] != MAGIC_DMA_WORD
) { /* DMA overflow! */
653 comedi_error(dev
, "A/D mode1/3 DMA buffer overflow!");
654 /* printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize); */
655 pcl818_ai_cancel(dev
, s
);
656 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
657 comedi_event(dev
, s
);
660 /* printk("r %ld ",ofs_dats); */
662 bufptr
= devpriv
->last_top_dma
;
664 for (i
= 0; i
< ofs_dats
; i
++) {
665 if ((dmabuf
[bufptr
] & 0xf) != devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]) { /* dropout! */
667 ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",
668 (dmabuf
[bufptr
] & 0xf),
670 act_chanlist
[devpriv
->act_chanlist_pos
]);
671 pcl818_ai_cancel(dev
, s
);
673 COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
674 comedi_event(dev
, s
);
678 comedi_buf_put(s
->async
, dmabuf
[bufptr
++] >> 4); /* get one sample */
679 bufptr
&= (devpriv
->dmasamplsize
- 1);
681 devpriv
->act_chanlist_pos
++;
682 if (devpriv
->act_chanlist_pos
>=
683 devpriv
->act_chanlist_len
) {
684 devpriv
->act_chanlist_pos
= 0;
686 s
->async
->cur_chan
++;
687 if (s
->async
->cur_chan
>= devpriv
->ai_n_chan
) {
688 s
->async
->cur_chan
= 0;
689 devpriv
->ai_act_scan
--;
692 if (!devpriv
->neverending_ai
)
693 if (devpriv
->ai_act_scan
== 0) { /* all data sampled */
694 pcl818_ai_cancel(dev
, s
);
695 s
->async
->events
|= COMEDI_CB_EOA
;
696 comedi_event(dev
, s
);
697 /* printk("done int ai13 dma\n"); */
702 devpriv
->last_top_dma
= bufptr
;
704 bufptr
&= (devpriv
->dmasamplsize
- 1);
705 dmabuf
[bufptr
] = MAGIC_DMA_WORD
;
706 comedi_event(dev
, s
);
717 ==============================================================================
718 analog input interrupt mode 1 & 3, 818HD/HG cards
720 static irqreturn_t
interrupt_pcl818_ai_mode13_fifo(int irq
, void *d
)
722 struct comedi_device
*dev
= d
;
723 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
726 outb(0, dev
->iobase
+ PCL818_FI_INTCLR
); /* clear fifo int request */
728 lo
= inb(dev
->iobase
+ PCL818_FI_STATUS
);
731 comedi_error(dev
, "A/D mode1/3 FIFO overflow!");
732 pcl818_ai_cancel(dev
, s
);
733 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
734 comedi_event(dev
, s
);
739 comedi_error(dev
, "A/D mode1/3 FIFO interrupt without data!");
740 pcl818_ai_cancel(dev
, s
);
741 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
742 comedi_event(dev
, s
);
751 for (i
= 0; i
< len
; i
++) {
752 lo
= inb(dev
->iobase
+ PCL818_FI_DATALO
);
753 if ((lo
& 0xf) != devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]) { /* dropout! */
755 ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
757 devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]);
758 pcl818_ai_cancel(dev
, s
);
759 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
760 comedi_event(dev
, s
);
764 comedi_buf_put(s
->async
, (lo
>> 4) | (inb(dev
->iobase
+ PCL818_FI_DATAHI
) << 4)); /* get one sample */
766 devpriv
->act_chanlist_pos
++;
767 if (devpriv
->act_chanlist_pos
>= devpriv
->act_chanlist_len
)
768 devpriv
->act_chanlist_pos
= 0;
770 s
->async
->cur_chan
++;
771 if (s
->async
->cur_chan
>= devpriv
->ai_n_chan
) {
772 s
->async
->cur_chan
= 0;
773 devpriv
->ai_act_scan
--;
776 if (!devpriv
->neverending_ai
)
777 if (devpriv
->ai_act_scan
== 0) { /* all data sampled */
778 pcl818_ai_cancel(dev
, s
);
779 s
->async
->events
|= COMEDI_CB_EOA
;
780 comedi_event(dev
, s
);
786 comedi_event(dev
, s
);
791 ==============================================================================
794 static irqreturn_t
interrupt_pcl818(int irq
, void *d
)
796 struct comedi_device
*dev
= d
;
798 if (!dev
->attached
) {
799 comedi_error(dev
, "premature interrupt");
804 if (devpriv
->irq_blocked
&& devpriv
->irq_was_now_closed
) {
805 if ((devpriv
->neverending_ai
|| (!devpriv
->neverending_ai
&&
806 devpriv
->ai_act_scan
> 0)) &&
807 (devpriv
->ai_mode
== INT_TYPE_AI1_DMA
||
808 devpriv
->ai_mode
== INT_TYPE_AI3_DMA
)) {
809 /* The cleanup from ai_cancel() has been delayed
810 until now because the card doesn't seem to like
811 being reprogrammed while a DMA transfer is in
814 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
815 devpriv
->ai_act_scan
= 0;
816 devpriv
->neverending_ai
= 0;
817 pcl818_ai_cancel(dev
, s
);
820 outb(0, dev
->iobase
+ PCL818_CLRINT
); /* clear INT request */
825 switch (devpriv
->ai_mode
) {
826 case INT_TYPE_AI1_DMA
:
827 case INT_TYPE_AI3_DMA
:
828 return interrupt_pcl818_ai_mode13_dma(irq
, d
);
829 case INT_TYPE_AI1_INT
:
830 case INT_TYPE_AI3_INT
:
831 return interrupt_pcl818_ai_mode13_int(irq
, d
);
832 case INT_TYPE_AI1_FIFO
:
833 case INT_TYPE_AI3_FIFO
:
834 return interrupt_pcl818_ai_mode13_fifo(irq
, d
);
835 #ifdef PCL818_MODE13_AO
836 case INT_TYPE_AO1_INT
:
837 case INT_TYPE_AO3_INT
:
838 return interrupt_pcl818_ao_mode13_int(irq
, d
);
844 outb(0, dev
->iobase
+ PCL818_CLRINT
); /* clear INT request */
846 if ((!dev
->irq
) || (!devpriv
->irq_free
) || (!devpriv
->irq_blocked
)
847 || (!devpriv
->ai_mode
)) {
848 comedi_error(dev
, "bad IRQ!");
852 comedi_error(dev
, "IRQ from unknown source!");
857 ==============================================================================
858 ANALOG INPUT MODE 1 or 3 DMA , 818 cards
860 static void pcl818_ai_mode13dma_int(int mode
, struct comedi_device
*dev
,
861 struct comedi_subdevice
*s
)
866 printk("mode13dma_int, mode: %d\n", mode
);
867 disable_dma(devpriv
->dma
); /* disable dma */
868 bytes
= devpriv
->hwdmasize
[0];
869 if (!devpriv
->neverending_ai
) {
870 bytes
= devpriv
->ai_n_chan
* devpriv
->ai_scans
* sizeof(short); /* how many */
871 devpriv
->dma_runs_to_end
= bytes
/ devpriv
->hwdmasize
[0]; /* how many DMA pages we must fiil */
872 devpriv
->last_dma_run
= bytes
% devpriv
->hwdmasize
[0]; /* on last dma transfer must be moved */
873 devpriv
->dma_runs_to_end
--;
874 if (devpriv
->dma_runs_to_end
>= 0)
875 bytes
= devpriv
->hwdmasize
[0];
878 devpriv
->next_dma_buf
= 0;
879 set_dma_mode(devpriv
->dma
, DMA_MODE_READ
);
880 flags
= claim_dma_lock();
881 clear_dma_ff(devpriv
->dma
);
882 set_dma_addr(devpriv
->dma
, devpriv
->hwdmaptr
[0]);
883 set_dma_count(devpriv
->dma
, bytes
);
884 release_dma_lock(flags
);
885 enable_dma(devpriv
->dma
);
888 devpriv
->ai_mode
= INT_TYPE_AI1_DMA
;
889 outb(0x87 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Pacer+IRQ+DMA */
891 devpriv
->ai_mode
= INT_TYPE_AI3_DMA
;
892 outb(0x86 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Ext trig+IRQ+DMA */
898 ==============================================================================
899 ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards
901 static void pcl818_ai_mode13dma_rtc(int mode
, struct comedi_device
*dev
,
902 struct comedi_subdevice
*s
)
907 set_dma_mode(devpriv
->dma
, DMA_MODE_READ
| DMA_AUTOINIT
);
908 flags
= claim_dma_lock();
909 clear_dma_ff(devpriv
->dma
);
910 set_dma_addr(devpriv
->dma
, devpriv
->hwdmaptr
[0]);
911 set_dma_count(devpriv
->dma
, devpriv
->hwdmasize
[0]);
912 release_dma_lock(flags
);
913 enable_dma(devpriv
->dma
);
914 devpriv
->last_top_dma
= 0; /* devpriv->hwdmasize[0]; */
915 pole
= (short *)devpriv
->dmabuf
[0];
916 devpriv
->dmasamplsize
= devpriv
->hwdmasize
[0] / 2;
917 pole
[devpriv
->dmasamplsize
- 1] = MAGIC_DMA_WORD
;
919 devpriv
->rtc_freq
= rtc_setfreq_irq(2048);
920 devpriv
->rtc_irq_timer
.expires
=
921 jiffies
+ HZ
/ devpriv
->rtc_freq
+ 2 * HZ
/ 100;
922 devpriv
->rtc_irq_timer
.data
= (unsigned long)dev
;
923 devpriv
->rtc_irq_timer
.function
= rtc_dropped_irq
;
925 add_timer(&devpriv
->rtc_irq_timer
);
929 devpriv
->int818_mode
= INT_TYPE_AI1_DMA_RTC
;
930 outb(0x07 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Pacer+DMA */
932 devpriv
->int818_mode
= INT_TYPE_AI3_DMA_RTC
;
933 outb(0x06 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Ext trig+DMA */
939 ==============================================================================
940 ANALOG INPUT MODE 1 or 3, 818 cards
942 static int pcl818_ai_cmd_mode(int mode
, struct comedi_device
*dev
,
943 struct comedi_subdevice
*s
)
945 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
946 int divisor1
= 0, divisor2
= 0;
949 dev_dbg(dev
->class_dev
, "pcl818_ai_cmd_mode()\n");
950 if ((!dev
->irq
) && (!devpriv
->dma_rtc
)) {
951 comedi_error(dev
, "IRQ not defined!");
955 if (devpriv
->irq_blocked
)
958 start_pacer(dev
, -1, 0, 0); /* stop pacer */
960 seglen
= check_channel_list(dev
, s
, devpriv
->ai_chanlist
,
964 setup_channel_list(dev
, s
, devpriv
->ai_chanlist
,
965 devpriv
->ai_n_chan
, seglen
);
969 devpriv
->ai_act_scan
= devpriv
->ai_scans
;
970 devpriv
->ai_act_chan
= 0;
971 devpriv
->irq_blocked
= 1;
972 devpriv
->irq_was_now_closed
= 0;
973 devpriv
->neverending_ai
= 0;
974 devpriv
->act_chanlist_pos
= 0;
975 devpriv
->dma_runs_to_end
= 0;
977 if ((devpriv
->ai_scans
== 0) || (devpriv
->ai_scans
== -1))
978 devpriv
->neverending_ai
= 1; /* well, user want neverending */
981 i8253_cascade_ns_to_timer(devpriv
->i8253_osc_base
, &divisor1
,
982 &divisor2
, &cmd
->convert_arg
,
984 if (divisor1
== 1) { /* PCL718/818 crash if any divisor is set to 1 */
994 outb(0, dev
->iobase
+ PCL818_CNTENABLE
); /* enable pacer */
996 switch (devpriv
->dma
) {
999 if (devpriv
->dma_rtc
== 0) {
1000 pcl818_ai_mode13dma_int(mode
, dev
, s
);
1004 pcl818_ai_mode13dma_rtc(mode
, dev
, s
);
1013 if (!devpriv
->usefifo
) {
1015 /* printk("IRQ\n"); */
1017 devpriv
->ai_mode
= INT_TYPE_AI1_INT
;
1019 outb(0x83 | (dev
->irq
<< 4),
1020 dev
->iobase
+ PCL818_CONTROL
);
1022 devpriv
->ai_mode
= INT_TYPE_AI3_INT
;
1024 outb(0x82 | (dev
->irq
<< 4),
1025 dev
->iobase
+ PCL818_CONTROL
);
1030 outb(1, dev
->iobase
+ PCL818_FI_ENABLE
);
1032 devpriv
->ai_mode
= INT_TYPE_AI1_FIFO
;
1034 outb(0x03, dev
->iobase
+ PCL818_CONTROL
);
1036 devpriv
->ai_mode
= INT_TYPE_AI3_FIFO
;
1037 outb(0x02, dev
->iobase
+ PCL818_CONTROL
);
1042 start_pacer(dev
, mode
, divisor1
, divisor2
);
1045 switch (devpriv
->ai_mode
) {
1046 case INT_TYPE_AI1_DMA_RTC
:
1047 case INT_TYPE_AI3_DMA_RTC
:
1048 set_rtc_irq_bit(1); /* start RTC */
1052 dev_dbg(dev
->class_dev
, "pcl818_ai_cmd_mode() end\n");
1058 ==============================================================================
1059 ANALOG OUTPUT MODE 1 or 3, 818 cards
1061 #ifdef PCL818_MODE13_AO
1062 static int pcl818_ao_mode13(int mode
, struct comedi_device
*dev
,
1063 struct comedi_subdevice
*s
, comedi_trig
* it
)
1065 int divisor1
= 0, divisor2
= 0;
1068 comedi_error(dev
, "IRQ not defined!");
1072 if (devpriv
->irq_blocked
)
1075 start_pacer(dev
, -1, 0, 0); /* stop pacer */
1077 devpriv
->int13_act_scan
= it
->n
;
1078 devpriv
->int13_act_chan
= 0;
1079 devpriv
->irq_blocked
= 1;
1080 devpriv
->irq_was_now_closed
= 0;
1081 devpriv
->neverending_ai
= 0;
1082 devpriv
->act_chanlist_pos
= 0;
1085 i8253_cascade_ns_to_timer(devpriv
->i8253_osc_base
, &divisor1
,
1086 &divisor2
, &it
->trigvar
,
1087 TRIG_ROUND_NEAREST
);
1088 if (divisor1
== 1) { /* PCL818 crash if any divisor is set to 1 */
1092 if (divisor2
== 1) {
1098 outb(0, dev
->iobase
+ PCL818_CNTENABLE
); /* enable pacer */
1100 devpriv
->int818_mode
= INT_TYPE_AO1_INT
;
1101 outb(0x83 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Pacer+IRQ */
1103 devpriv
->int818_mode
= INT_TYPE_AO3_INT
;
1104 outb(0x82 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Ext trig+IRQ */
1107 start_pacer(dev
, mode
, divisor1
, divisor2
);
1113 ==============================================================================
1114 ANALOG OUTPUT MODE 1, 818 cards
1116 static int pcl818_ao_mode1(struct comedi_device
*dev
,
1117 struct comedi_subdevice
*s
, comedi_trig
* it
)
1119 return pcl818_ao_mode13(1, dev
, s
, it
);
1123 ==============================================================================
1124 ANALOG OUTPUT MODE 3, 818 cards
1126 static int pcl818_ao_mode3(struct comedi_device
*dev
,
1127 struct comedi_subdevice
*s
, comedi_trig
* it
)
1129 return pcl818_ao_mode13(3, dev
, s
, it
);
1135 ==============================================================================
1136 Start/stop pacer onboard pacer
1138 static void start_pacer(struct comedi_device
*dev
, int mode
,
1139 unsigned int divisor1
, unsigned int divisor2
)
1141 outb(0xb4, dev
->iobase
+ PCL818_CTRCTL
);
1142 outb(0x74, dev
->iobase
+ PCL818_CTRCTL
);
1146 outb(divisor2
& 0xff, dev
->iobase
+ PCL818_CTR2
);
1147 outb((divisor2
>> 8) & 0xff, dev
->iobase
+ PCL818_CTR2
);
1148 outb(divisor1
& 0xff, dev
->iobase
+ PCL818_CTR1
);
1149 outb((divisor1
>> 8) & 0xff, dev
->iobase
+ PCL818_CTR1
);
1154 ==============================================================================
1155 Check if channel list from user is builded correctly
1156 If it's ok, then program scan/gain logic
1158 static int check_channel_list(struct comedi_device
*dev
,
1159 struct comedi_subdevice
*s
,
1160 unsigned int *chanlist
, unsigned int n_chan
)
1162 unsigned int chansegment
[16];
1163 unsigned int i
, nowmustbechan
, seglen
, segpos
;
1165 /* correct channel and range number check itself comedi/range.c */
1167 comedi_error(dev
, "range/channel list is empty!");
1172 /* first channel is every time ok */
1173 chansegment
[0] = chanlist
[0];
1174 /* build part of chanlist */
1175 for (i
= 1, seglen
= 1; i
< n_chan
; i
++, seglen
++) {
1177 /* printk("%d. %d * %d\n",i,
1178 * CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));*/
1180 /* we detect loop, this must by finish */
1182 if (chanlist
[0] == chanlist
[i
])
1185 (CR_CHAN(chansegment
[i
- 1]) + 1) % s
->n_chan
;
1186 if (nowmustbechan
!= CR_CHAN(chanlist
[i
])) { /* channel list isn't continuous :-( */
1188 ("comedi%d: pcl818: channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
1189 dev
->minor
, i
, CR_CHAN(chanlist
[i
]),
1190 nowmustbechan
, CR_CHAN(chanlist
[0]));
1193 /* well, this is next correct channel in list */
1194 chansegment
[i
] = chanlist
[i
];
1197 /* check whole chanlist */
1198 for (i
= 0, segpos
= 0; i
< n_chan
; i
++) {
1199 /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i])); */
1200 if (chanlist
[i
] != chansegment
[i
% seglen
]) {
1202 ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1203 dev
->minor
, i
, CR_CHAN(chansegment
[i
]),
1204 CR_RANGE(chansegment
[i
]),
1205 CR_AREF(chansegment
[i
]),
1206 CR_CHAN(chanlist
[i
% seglen
]),
1207 CR_RANGE(chanlist
[i
% seglen
]),
1208 CR_AREF(chansegment
[i
% seglen
]));
1209 return 0; /* chan/gain list is strange */
1215 printk("check_channel_list: seglen %d\n", seglen
);
1219 static void setup_channel_list(struct comedi_device
*dev
,
1220 struct comedi_subdevice
*s
,
1221 unsigned int *chanlist
, unsigned int n_chan
,
1222 unsigned int seglen
)
1226 devpriv
->act_chanlist_len
= seglen
;
1227 devpriv
->act_chanlist_pos
= 0;
1229 for (i
= 0; i
< seglen
; i
++) { /* store range list to card */
1230 devpriv
->act_chanlist
[i
] = CR_CHAN(chanlist
[i
]);
1231 outb(muxonechan
[CR_CHAN(chanlist
[i
])], dev
->iobase
+ PCL818_MUX
); /* select channel */
1232 outb(CR_RANGE(chanlist
[i
]), dev
->iobase
+ PCL818_RANGE
); /* select gain */
1237 /* select channel interval to scan */
1238 outb(devpriv
->act_chanlist
[0] | (devpriv
->act_chanlist
[seglen
-
1240 dev
->iobase
+ PCL818_MUX
);
1244 ==============================================================================
1245 Check if board is switched to SE (1) or DIFF(0) mode
1247 static int check_single_ended(unsigned int port
)
1249 if (inb(port
+ PCL818_STATUS
) & 0x20)
1255 ==============================================================================
1257 static int ai_cmdtest(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
1258 struct comedi_cmd
*cmd
)
1260 const struct pcl818_board
*board
= comedi_board(dev
);
1262 int tmp
, divisor1
= 0, divisor2
= 0;
1264 /* step 1: make sure trigger sources are trivially valid */
1266 tmp
= cmd
->start_src
;
1267 cmd
->start_src
&= TRIG_NOW
;
1268 if (!cmd
->start_src
|| tmp
!= cmd
->start_src
)
1271 tmp
= cmd
->scan_begin_src
;
1272 cmd
->scan_begin_src
&= TRIG_FOLLOW
;
1273 if (!cmd
->scan_begin_src
|| tmp
!= cmd
->scan_begin_src
)
1276 tmp
= cmd
->convert_src
;
1277 cmd
->convert_src
&= TRIG_TIMER
| TRIG_EXT
;
1278 if (!cmd
->convert_src
|| tmp
!= cmd
->convert_src
)
1281 tmp
= cmd
->scan_end_src
;
1282 cmd
->scan_end_src
&= TRIG_COUNT
;
1283 if (!cmd
->scan_end_src
|| tmp
!= cmd
->scan_end_src
)
1286 tmp
= cmd
->stop_src
;
1287 cmd
->stop_src
&= TRIG_COUNT
| TRIG_NONE
;
1288 if (!cmd
->stop_src
|| tmp
!= cmd
->stop_src
)
1294 /* step 2: make sure trigger sources are unique and mutually compatible */
1296 if (cmd
->convert_src
!= TRIG_TIMER
&& cmd
->convert_src
!= TRIG_EXT
)
1299 if (cmd
->stop_src
!= TRIG_NONE
&& cmd
->stop_src
!= TRIG_COUNT
)
1305 /* step 3: make sure arguments are trivially compatible */
1307 if (cmd
->start_arg
!= 0) {
1312 if (cmd
->scan_begin_arg
!= 0) {
1313 cmd
->scan_begin_arg
= 0;
1317 if (cmd
->convert_src
== TRIG_TIMER
) {
1318 if (cmd
->convert_arg
< board
->ns_min
) {
1319 cmd
->convert_arg
= board
->ns_min
;
1322 } else { /* TRIG_EXT */
1323 if (cmd
->convert_arg
!= 0) {
1324 cmd
->convert_arg
= 0;
1329 if (cmd
->scan_end_arg
!= cmd
->chanlist_len
) {
1330 cmd
->scan_end_arg
= cmd
->chanlist_len
;
1333 if (cmd
->stop_src
== TRIG_COUNT
) {
1334 if (!cmd
->stop_arg
) {
1338 } else { /* TRIG_NONE */
1339 if (cmd
->stop_arg
!= 0) {
1348 /* step 4: fix up any arguments */
1350 if (cmd
->convert_src
== TRIG_TIMER
) {
1351 tmp
= cmd
->convert_arg
;
1352 i8253_cascade_ns_to_timer(devpriv
->i8253_osc_base
, &divisor1
,
1353 &divisor2
, &cmd
->convert_arg
,
1354 cmd
->flags
& TRIG_ROUND_MASK
);
1355 if (cmd
->convert_arg
< board
->ns_min
)
1356 cmd
->convert_arg
= board
->ns_min
;
1357 if (tmp
!= cmd
->convert_arg
)
1364 /* step 5: complain about special chanlist considerations */
1366 if (cmd
->chanlist
) {
1367 if (!check_channel_list(dev
, s
, cmd
->chanlist
,
1369 return 5; /* incorrect channels list */
1376 ==============================================================================
1378 static int ai_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
1380 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
1383 dev_dbg(dev
->class_dev
, "pcl818_ai_cmd()\n");
1384 devpriv
->ai_n_chan
= cmd
->chanlist_len
;
1385 devpriv
->ai_chanlist
= cmd
->chanlist
;
1386 devpriv
->ai_flags
= cmd
->flags
;
1387 devpriv
->ai_data_len
= s
->async
->prealloc_bufsz
;
1388 devpriv
->ai_data
= s
->async
->prealloc_buf
;
1389 devpriv
->ai_timer1
= 0;
1390 devpriv
->ai_timer2
= 0;
1392 if (cmd
->stop_src
== TRIG_COUNT
)
1393 devpriv
->ai_scans
= cmd
->stop_arg
;
1395 devpriv
->ai_scans
= 0;
1397 if (cmd
->scan_begin_src
== TRIG_FOLLOW
) { /* mode 1, 3 */
1398 if (cmd
->convert_src
== TRIG_TIMER
) { /* mode 1 */
1399 devpriv
->ai_timer1
= cmd
->convert_arg
;
1400 retval
= pcl818_ai_cmd_mode(1, dev
, s
);
1401 dev_dbg(dev
->class_dev
, "pcl818_ai_cmd() end\n");
1404 if (cmd
->convert_src
== TRIG_EXT
) { /* mode 3 */
1405 return pcl818_ai_cmd_mode(3, dev
, s
);
1413 ==============================================================================
1414 cancel any mode 1-4 AI
1416 static int pcl818_ai_cancel(struct comedi_device
*dev
,
1417 struct comedi_subdevice
*s
)
1419 if (devpriv
->irq_blocked
> 0) {
1420 dev_dbg(dev
->class_dev
, "pcl818_ai_cancel()\n");
1421 devpriv
->irq_was_now_closed
= 1;
1423 switch (devpriv
->ai_mode
) {
1425 case INT_TYPE_AI1_DMA_RTC
:
1426 case INT_TYPE_AI3_DMA_RTC
:
1427 set_rtc_irq_bit(0); /* stop RTC */
1428 del_timer(&devpriv
->rtc_irq_timer
);
1430 case INT_TYPE_AI1_DMA
:
1431 case INT_TYPE_AI3_DMA
:
1432 if (devpriv
->neverending_ai
||
1433 (!devpriv
->neverending_ai
&&
1434 devpriv
->ai_act_scan
> 0)) {
1435 /* wait for running dma transfer to end, do cleanup in interrupt */
1438 disable_dma(devpriv
->dma
);
1439 case INT_TYPE_AI1_INT
:
1440 case INT_TYPE_AI3_INT
:
1441 case INT_TYPE_AI1_FIFO
:
1442 case INT_TYPE_AI3_FIFO
:
1443 #ifdef PCL818_MODE13_AO
1444 case INT_TYPE_AO1_INT
:
1445 case INT_TYPE_AO3_INT
:
1447 outb(inb(dev
->iobase
+ PCL818_CONTROL
) & 0x73, dev
->iobase
+ PCL818_CONTROL
); /* Stop A/D */
1449 start_pacer(dev
, -1, 0, 0);
1450 outb(0, dev
->iobase
+ PCL818_AD_LO
);
1451 inb(dev
->iobase
+ PCL818_AD_LO
);
1452 inb(dev
->iobase
+ PCL818_AD_HI
);
1453 outb(0, dev
->iobase
+ PCL818_CLRINT
); /* clear INT request */
1454 outb(0, dev
->iobase
+ PCL818_CONTROL
); /* Stop A/D */
1455 if (devpriv
->usefifo
) { /* FIFO shutdown */
1456 outb(0, dev
->iobase
+ PCL818_FI_INTCLR
);
1457 outb(0, dev
->iobase
+ PCL818_FI_FLUSH
);
1458 outb(0, dev
->iobase
+ PCL818_FI_ENABLE
);
1460 devpriv
->irq_blocked
= 0;
1461 devpriv
->last_int_sub
= s
;
1462 devpriv
->neverending_ai
= 0;
1463 devpriv
->ai_mode
= 0;
1464 devpriv
->irq_was_now_closed
= 0;
1470 dev_dbg(dev
->class_dev
, "pcl818_ai_cancel() end\n");
1475 ==============================================================================
1478 static int pcl818_check(unsigned long iobase
)
1480 outb(0x00, iobase
+ PCL818_MUX
);
1482 if (inb(iobase
+ PCL818_MUX
) != 0x00)
1483 return 1; /* there isn't card */
1484 outb(0x55, iobase
+ PCL818_MUX
);
1486 if (inb(iobase
+ PCL818_MUX
) != 0x55)
1487 return 1; /* there isn't card */
1488 outb(0x00, iobase
+ PCL818_MUX
);
1490 outb(0x18, iobase
+ PCL818_CONTROL
);
1492 if (inb(iobase
+ PCL818_CONTROL
) != 0x18)
1493 return 1; /* there isn't card */
1494 return 0; /* ok, card exist */
1498 ==============================================================================
1499 reset whole PCL-818 cards
1501 static void pcl818_reset(struct comedi_device
*dev
)
1503 const struct pcl818_board
*board
= comedi_board(dev
);
1505 if (devpriv
->usefifo
) { /* FIFO shutdown */
1506 outb(0, dev
->iobase
+ PCL818_FI_INTCLR
);
1507 outb(0, dev
->iobase
+ PCL818_FI_FLUSH
);
1508 outb(0, dev
->iobase
+ PCL818_FI_ENABLE
);
1510 outb(0, dev
->iobase
+ PCL818_DA_LO
); /* DAC=0V */
1511 outb(0, dev
->iobase
+ PCL818_DA_HI
);
1513 outb(0, dev
->iobase
+ PCL818_DO_HI
); /* DO=$0000 */
1514 outb(0, dev
->iobase
+ PCL818_DO_LO
);
1516 outb(0, dev
->iobase
+ PCL818_CONTROL
);
1517 outb(0, dev
->iobase
+ PCL818_CNTENABLE
);
1518 outb(0, dev
->iobase
+ PCL818_MUX
);
1519 outb(0, dev
->iobase
+ PCL818_CLRINT
);
1520 outb(0xb0, dev
->iobase
+ PCL818_CTRCTL
); /* Stop pacer */
1521 outb(0x70, dev
->iobase
+ PCL818_CTRCTL
);
1522 outb(0x30, dev
->iobase
+ PCL818_CTRCTL
);
1523 if (board
->is_818
) {
1524 outb(0, dev
->iobase
+ PCL818_RANGE
);
1526 outb(0, dev
->iobase
+ PCL718_DA2_LO
);
1527 outb(0, dev
->iobase
+ PCL718_DA2_HI
);
1533 ==============================================================================
1534 Enable(1)/disable(0) periodic interrupts from RTC
1536 static int set_rtc_irq_bit(unsigned char bit
)
1539 unsigned long flags
;
1543 if (RTC_timer_lock
> 1)
1547 if (RTC_timer_lock
< 0)
1549 if (RTC_timer_lock
> 0)
1555 val
= CMOS_READ(RTC_CONTROL
);
1561 CMOS_WRITE(val
, RTC_CONTROL
);
1562 CMOS_READ(RTC_INTR_FLAGS
);
1563 restore_flags(flags
);
1568 ==============================================================================
1569 Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers)
1571 static void rtc_dropped_irq(unsigned long data
)
1573 struct comedi_device
*dev
= (void *)data
;
1574 unsigned long flags
, tmp
;
1576 switch (devpriv
->int818_mode
) {
1577 case INT_TYPE_AI1_DMA_RTC
:
1578 case INT_TYPE_AI3_DMA_RTC
:
1579 mod_timer(&devpriv
->rtc_irq_timer
,
1580 jiffies
+ HZ
/ devpriv
->rtc_freq
+ 2 * HZ
/ 100);
1583 tmp
= (CMOS_READ(RTC_INTR_FLAGS
) & 0xF0); /* restart */
1584 restore_flags(flags
);
1590 ==============================================================================
1591 Set frequency of interrupts from RTC
1593 static int rtc_setfreq_irq(int freq
)
1598 unsigned long flags
;
1605 while (freq
> (1 << tmp
))
1608 rtc_freq
= 1 << tmp
;
1612 val
= CMOS_READ(RTC_FREQ_SELECT
) & 0xf0;
1614 CMOS_WRITE(val
, RTC_FREQ_SELECT
);
1615 restore_flags(flags
);
1620 static int pcl818_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
1622 const struct pcl818_board
*board
= comedi_board(dev
);
1624 unsigned long iobase
;
1627 unsigned long pages
;
1628 struct comedi_subdevice
*s
;
1630 ret
= alloc_private(dev
, sizeof(struct pcl818_private
));
1632 return ret
; /* Can't alloc mem */
1634 /* claim our I/O space */
1635 iobase
= it
->options
[0];
1637 ("comedi%d: pcl818: board=%s, ioport=0x%03lx",
1638 dev
->minor
, board
->name
, iobase
);
1639 devpriv
->io_range
= board
->io_range
;
1640 if ((board
->fifo
) && (it
->options
[2] == -1)) {
1641 /* we've board with FIFO and we want to use FIFO */
1642 devpriv
->io_range
= PCLx1xFIFO_RANGE
;
1643 devpriv
->usefifo
= 1;
1645 if (!request_region(iobase
, devpriv
->io_range
, "pcl818")) {
1646 comedi_error(dev
, "I/O port conflict\n");
1650 dev
->iobase
= iobase
;
1652 if (pcl818_check(iobase
)) {
1653 comedi_error(dev
, "I can't detect board. FAIL!\n");
1657 dev
->board_name
= board
->name
;
1661 if (board
->IRQbits
!= 0) { /* board support IRQ */
1662 irq
= it
->options
[1];
1663 if (irq
) { /* we want to use IRQ */
1664 if (((1 << irq
) & board
->IRQbits
) == 0) {
1666 (", IRQ %u is out of allowed range, DISABLING IT",
1668 irq
= 0; /* Bad IRQ */
1671 (irq
, interrupt_pcl818
, 0, "pcl818", dev
)) {
1673 (", unable to allocate IRQ %u, DISABLING IT",
1675 irq
= 0; /* Can't use IRQ */
1677 printk(KERN_DEBUG
"irq=%u", irq
);
1685 devpriv
->irq_free
= 1; /* 1=we have allocated irq */
1687 devpriv
->irq_free
= 0;
1689 devpriv
->irq_blocked
= 0; /* number of subdevice which use IRQ */
1690 devpriv
->ai_mode
= 0; /* mode of irq */
1693 /* grab RTC for DMA operations */
1694 devpriv
->dma_rtc
= 0;
1695 if (it
->options
[2] > 0) { /* we want to use DMA */
1696 if (RTC_lock
== 0) {
1697 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT
,
1701 devpriv
->rtc_iobase
= RTC_PORT(0);
1702 devpriv
->rtc_iosize
= RTC_IO_EXTENT
;
1704 if (!request_irq(RTC_IRQ
, interrupt_pcl818_ai_mode13_dma_rtc
, 0,
1705 "pcl818 DMA (RTC)", dev
)) {
1706 devpriv
->dma_rtc
= 1;
1707 devpriv
->rtc_irq
= RTC_IRQ
;
1708 printk(KERN_DEBUG
"dma_irq=%u", devpriv
->rtc_irq
);
1711 if (RTC_lock
== 0) {
1712 if (devpriv
->rtc_iobase
)
1713 release_region(devpriv
->rtc_iobase
,
1714 devpriv
->rtc_iosize
);
1716 devpriv
->rtc_iobase
= 0;
1717 devpriv
->rtc_iosize
= 0;
1726 if ((devpriv
->irq_free
== 0) && (devpriv
->dma_rtc
== 0))
1727 goto no_dma
; /* if we haven't IRQ, we can't use DMA */
1728 if (board
->DMAbits
!= 0) { /* board support DMA */
1729 dma
= it
->options
[2];
1731 goto no_dma
; /* DMA disabled */
1732 if (((1 << dma
) & board
->DMAbits
) == 0) {
1733 printk(KERN_ERR
"DMA is out of allowed range, FAIL!\n");
1734 return -EINVAL
; /* Bad DMA */
1736 ret
= request_dma(dma
, "pcl818");
1738 return -EBUSY
; /* DMA isn't free */
1740 pages
= 2; /* we need 16KB */
1741 devpriv
->dmabuf
[0] = __get_dma_pages(GFP_KERNEL
, pages
);
1742 if (!devpriv
->dmabuf
[0])
1743 /* maybe experiment with try_to_free_pages() will help .... */
1744 return -EBUSY
; /* no buffer :-( */
1745 devpriv
->dmapages
[0] = pages
;
1746 devpriv
->hwdmaptr
[0] = virt_to_bus((void *)devpriv
->dmabuf
[0]);
1747 devpriv
->hwdmasize
[0] = (1 << pages
) * PAGE_SIZE
;
1748 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
1749 if (devpriv
->dma_rtc
== 0) { /* we must do duble buff :-( */
1750 devpriv
->dmabuf
[1] = __get_dma_pages(GFP_KERNEL
, pages
);
1751 if (!devpriv
->dmabuf
[1])
1753 devpriv
->dmapages
[1] = pages
;
1754 devpriv
->hwdmaptr
[1] =
1755 virt_to_bus((void *)devpriv
->dmabuf
[1]);
1756 devpriv
->hwdmasize
[1] = (1 << pages
) * PAGE_SIZE
;
1762 ret
= comedi_alloc_subdevices(dev
, 4);
1766 s
= dev
->subdevices
+ 0;
1767 if (!board
->n_aichan_se
) {
1768 s
->type
= COMEDI_SUBD_UNUSED
;
1770 s
->type
= COMEDI_SUBD_AI
;
1771 devpriv
->sub_ai
= s
;
1772 s
->subdev_flags
= SDF_READABLE
;
1773 if (check_single_ended(dev
->iobase
)) {
1774 s
->n_chan
= board
->n_aichan_se
;
1775 s
->subdev_flags
|= SDF_COMMON
| SDF_GROUND
;
1776 printk(", %dchans S.E. DAC", s
->n_chan
);
1778 s
->n_chan
= board
->n_aichan_diff
;
1779 s
->subdev_flags
|= SDF_DIFF
;
1780 printk(", %dchans DIFF DAC", s
->n_chan
);
1782 s
->maxdata
= board
->ai_maxdata
;
1783 s
->len_chanlist
= s
->n_chan
;
1784 s
->range_table
= board
->ai_range_type
;
1785 s
->cancel
= pcl818_ai_cancel
;
1786 s
->insn_read
= pcl818_ai_insn_read
;
1787 if ((irq
) || (devpriv
->dma_rtc
)) {
1788 dev
->read_subdev
= s
;
1789 s
->subdev_flags
|= SDF_CMD_READ
;
1790 s
->do_cmdtest
= ai_cmdtest
;
1793 if (board
->is_818
) {
1794 if ((it
->options
[4] == 1) || (it
->options
[4] == 10))
1795 s
->range_table
= &range_pcl818l_h_ai
; /* secondary range list jumper selectable */
1797 switch (it
->options
[4]) {
1799 s
->range_table
= &range_bipolar10
;
1802 s
->range_table
= &range_bipolar5
;
1805 s
->range_table
= &range_bipolar2_5
;
1808 s
->range_table
= &range718_bipolar1
;
1811 s
->range_table
= &range718_bipolar0_5
;
1814 s
->range_table
= &range_unipolar10
;
1817 s
->range_table
= &range_unipolar5
;
1820 s
->range_table
= &range718_unipolar2
;
1823 s
->range_table
= &range718_unipolar1
;
1826 s
->range_table
= &range_unknown
;
1832 s
= dev
->subdevices
+ 1;
1833 if (!board
->n_aochan
) {
1834 s
->type
= COMEDI_SUBD_UNUSED
;
1836 s
->type
= COMEDI_SUBD_AO
;
1837 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
;
1838 s
->n_chan
= board
->n_aochan
;
1839 s
->maxdata
= board
->ao_maxdata
;
1840 s
->len_chanlist
= board
->n_aochan
;
1841 s
->range_table
= board
->ao_range_type
;
1842 s
->insn_read
= pcl818_ao_insn_read
;
1843 s
->insn_write
= pcl818_ao_insn_write
;
1845 #ifdef PCL818_MODE13_AO
1847 s
->trig
[1] = pcl818_ao_mode1
;
1848 s
->trig
[3] = pcl818_ao_mode3
;
1852 if (board
->is_818
) {
1853 if ((it
->options
[4] == 1) || (it
->options
[4] == 10))
1854 s
->range_table
= &range_unipolar10
;
1855 if (it
->options
[4] == 2)
1856 s
->range_table
= &range_unknown
;
1858 if ((it
->options
[5] == 1) || (it
->options
[5] == 10))
1859 s
->range_table
= &range_unipolar10
;
1860 if (it
->options
[5] == 2)
1861 s
->range_table
= &range_unknown
;
1865 s
= dev
->subdevices
+ 2;
1866 if (!board
->n_dichan
) {
1867 s
->type
= COMEDI_SUBD_UNUSED
;
1869 s
->type
= COMEDI_SUBD_DI
;
1870 s
->subdev_flags
= SDF_READABLE
;
1871 s
->n_chan
= board
->n_dichan
;
1873 s
->len_chanlist
= board
->n_dichan
;
1874 s
->range_table
= &range_digital
;
1875 s
->insn_bits
= pcl818_di_insn_bits
;
1878 s
= dev
->subdevices
+ 3;
1879 if (!board
->n_dochan
) {
1880 s
->type
= COMEDI_SUBD_UNUSED
;
1882 s
->type
= COMEDI_SUBD_DO
;
1883 s
->subdev_flags
= SDF_WRITABLE
;
1884 s
->n_chan
= board
->n_dochan
;
1886 s
->len_chanlist
= board
->n_dochan
;
1887 s
->range_table
= &range_digital
;
1888 s
->insn_bits
= pcl818_do_insn_bits
;
1891 /* select 1/10MHz oscilator */
1892 if ((it
->options
[3] == 0) || (it
->options
[3] == 10))
1893 devpriv
->i8253_osc_base
= 100;
1895 devpriv
->i8253_osc_base
= 1000;
1897 /* max sampling speed */
1898 devpriv
->ns_min
= board
->ns_min
;
1900 if (!board
->is_818
) {
1901 if ((it
->options
[6] == 1) || (it
->options
[6] == 100))
1902 devpriv
->ns_min
= 10000; /* extended PCL718 to 100kHz DAC */
1912 static void pcl818_detach(struct comedi_device
*dev
)
1915 pcl818_ai_cancel(dev
, devpriv
->sub_ai
);
1918 free_dma(devpriv
->dma
);
1919 if (devpriv
->dmabuf
[0])
1920 free_pages(devpriv
->dmabuf
[0], devpriv
->dmapages
[0]);
1921 if (devpriv
->dmabuf
[1])
1922 free_pages(devpriv
->dmabuf
[1], devpriv
->dmapages
[1]);
1924 if (devpriv
->rtc_irq
)
1925 free_irq(devpriv
->rtc_irq
, dev
);
1926 if ((devpriv
->dma_rtc
) && (RTC_lock
== 1)) {
1927 if (devpriv
->rtc_iobase
)
1928 release_region(devpriv
->rtc_iobase
,
1929 devpriv
->rtc_iosize
);
1931 if (devpriv
->dma_rtc
)
1936 free_irq(dev
->irq
, dev
);
1938 release_region(dev
->iobase
, devpriv
->io_range
);
1941 static const struct pcl818_board boardtypes
[] = {
1942 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai
,
1943 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1944 0x0a, 0xfff, 0xfff, 0, 1},
1945 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai
,
1946 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1947 0x0a, 0xfff, 0xfff, 0, 1},
1948 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai
,
1949 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1950 0x0a, 0xfff, 0xfff, 1, 1},
1951 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai
,
1952 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1953 0x0a, 0xfff, 0xfff, 1, 1},
1954 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai
,
1955 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1956 0x0a, 0xfff, 0xfff, 0, 1},
1957 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5
,
1958 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1959 0x0a, 0xfff, 0xfff, 0, 0},
1961 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai
,
1962 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1963 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
1966 static struct comedi_driver pcl818_driver
= {
1967 .driver_name
= "pcl818",
1968 .module
= THIS_MODULE
,
1969 .attach
= pcl818_attach
,
1970 .detach
= pcl818_detach
,
1971 .board_name
= &boardtypes
[0].name
,
1972 .num_names
= ARRAY_SIZE(boardtypes
),
1973 .offset
= sizeof(struct pcl818_board
),
1975 module_comedi_driver(pcl818_driver
);
1977 MODULE_AUTHOR("Comedi http://www.comedi.org");
1978 MODULE_DESCRIPTION("Comedi low-level driver");
1979 MODULE_LICENSE("GPL");