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>
110 #include "comedi_fc.h"
113 /* #define PCL818_MODE13_AO 1 */
115 /* boards constants */
117 #define boardPCL818L 0
118 #define boardPCL818H 1
119 #define boardPCL818HD 2
120 #define boardPCL818HG 3
121 #define boardPCL818 4
122 #define boardPCL718 5
125 #define PCLx1x_RANGE 16
126 /* IO space len if we use FIFO */
127 #define PCLx1xFIFO_RANGE 32
129 /* W: clear INT request */
130 #define PCL818_CLRINT 8
131 /* R: return status byte */
132 #define PCL818_STATUS 8
133 /* R: A/D high byte W: A/D range control */
134 #define PCL818_RANGE 1
135 /* R: next mux scan channel W: mux scan channel & range control pointer */
137 /* R/W: operation control register */
138 #define PCL818_CONTROL 9
139 /* W: counter enable */
140 #define PCL818_CNTENABLE 10
142 /* R: low byte of A/D W: soft A/D trigger */
143 #define PCL818_AD_LO 0
144 /* R: high byte of A/D W: A/D range control */
145 #define PCL818_AD_HI 1
146 /* W: D/A low&high byte */
147 #define PCL818_DA_LO 4
148 #define PCL818_DA_HI 5
149 /* R: low&high byte of DI */
150 #define PCL818_DI_LO 3
151 #define PCL818_DI_HI 11
152 /* W: low&high byte of DO */
153 #define PCL818_DO_LO 3
154 #define PCL818_DO_HI 11
155 /* W: PCL718 second D/A */
156 #define PCL718_DA2_LO 6
157 #define PCL718_DA2_HI 7
159 #define PCL818_CTR0 12
160 #define PCL818_CTR1 13
161 #define PCL818_CTR2 14
162 /* W: counter control */
163 #define PCL818_CTRCTL 15
165 /* W: fifo enable/disable */
166 #define PCL818_FI_ENABLE 6
167 /* W: fifo interrupt clear */
168 #define PCL818_FI_INTCLR 20
169 /* W: fifo interrupt clear */
170 #define PCL818_FI_FLUSH 25
172 #define PCL818_FI_STATUS 25
173 /* R: one record from FIFO */
174 #define PCL818_FI_DATALO 23
175 #define PCL818_FI_DATAHI 23
177 /* type of interrupt handler */
178 #define INT_TYPE_AI1_INT 1
179 #define INT_TYPE_AI1_DMA 2
180 #define INT_TYPE_AI1_FIFO 3
181 #define INT_TYPE_AI3_INT 4
182 #define INT_TYPE_AI3_DMA 5
183 #define INT_TYPE_AI3_FIFO 6
184 #ifdef PCL818_MODE13_AO
185 #define INT_TYPE_AO1_INT 7
186 #define INT_TYPE_AO3_INT 8
191 #define INT_TYPE_AI1_DMA_RTC 9
192 #define INT_TYPE_AI3_DMA_RTC 10
195 #define RTC_IO_EXTENT 0x10
198 #define MAGIC_DMA_WORD 0x5a5a
200 static const struct comedi_lrange range_pcl818h_ai
= { 9, {
213 static const struct comedi_lrange range_pcl818hg_ai
= { 10, {
229 static const struct comedi_lrange range_pcl818l_l_ai
= { 4, {
237 static const struct comedi_lrange range_pcl818l_h_ai
= { 4, {
245 static const struct comedi_lrange range718_bipolar1
= { 1, {BIP_RANGE(1),} };
246 static const struct comedi_lrange range718_bipolar0_5
=
247 { 1, {BIP_RANGE(0.5),} };
248 static const struct comedi_lrange range718_unipolar2
= { 1, {UNI_RANGE(2),} };
249 static const struct comedi_lrange range718_unipolar1
= { 1, {BIP_RANGE(1),} };
252 static int RTC_lock
; /* RTC lock */
253 static int RTC_timer_lock
; /* RTC int lock */
256 struct pcl818_board
{
258 const char *name
; /* driver name */
259 int n_ranges
; /* len of range list */
260 int n_aichan_se
; /* num of A/D chans in single ended mode */
261 int n_aichan_diff
; /* num of A/D chans in diferencial mode */
262 unsigned int ns_min
; /* minimal allowed delay between samples (in ns) */
263 int n_aochan
; /* num of D/A chans */
264 int n_dichan
; /* num of DI chans */
265 int n_dochan
; /* num of DO chans */
266 const struct comedi_lrange
*ai_range_type
; /* default A/D rangelist */
267 const struct comedi_lrange
*ao_range_type
; /* default D/A rangelist */
268 unsigned int io_range
; /* len of IO space */
269 unsigned int IRQbits
; /* allowed interrupts */
270 unsigned int DMAbits
; /* allowed DMA chans */
271 int ai_maxdata
; /* maxdata for A/D */
272 int ao_maxdata
; /* maxdata for D/A */
273 unsigned char fifo
; /* 1=board has FIFO */
277 struct pcl818_private
{
279 unsigned int dma
; /* used DMA, 0=don't use DMA */
280 int dma_rtc
; /* 1=RTC used with DMA, 0=no RTC alloc */
281 unsigned int io_range
;
283 unsigned long rtc_iobase
; /* RTC port region */
284 unsigned int rtc_iosize
;
285 unsigned int rtc_irq
;
286 struct timer_list rtc_irq_timer
; /* timer for RTC sanity check */
287 unsigned long rtc_freq
; /* RTC int freq */
288 int rtc_irq_blocked
; /* 1=we now do AI with DMA&RTC */
290 unsigned long dmabuf
[2]; /* pointers to begin of DMA buffers */
291 unsigned int dmapages
[2]; /* len of DMA buffers in PAGE_SIZEs */
292 unsigned int hwdmaptr
[2]; /* hardware address of DMA buffers */
293 unsigned int hwdmasize
[2]; /* len of DMA buffers in Bytes */
294 unsigned int dmasamplsize
; /* size in samples hwdmasize[0]/2 */
295 unsigned int last_top_dma
; /* DMA pointer in last RTC int */
296 int next_dma_buf
; /* which DMA buffer will be used next round */
297 long dma_runs_to_end
; /* how many we must permorm DMA transfer to end of record */
298 unsigned long last_dma_run
; /* how many bytes we must transfer on last DMA page */
299 unsigned char neverending_ai
; /* if=1, then we do neverending record (you must use cancel()) */
300 unsigned int ns_min
; /* manimal allowed delay between samples (in us) for actual card */
301 int i8253_osc_base
; /* 1/frequency of on board oscilator in ns */
302 int irq_free
; /* 1=have allocated IRQ */
303 int irq_blocked
; /* 1=IRQ now uses any subdev */
304 int irq_was_now_closed
; /* when IRQ finish, there's stored int818_mode for last interrupt */
305 int ai_mode
; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
306 struct comedi_subdevice
*last_int_sub
; /* ptr to subdevice which now finish */
307 int ai_act_scan
; /* how many scans we finished */
308 int ai_act_chan
; /* actual position in actual scan */
309 unsigned int act_chanlist
[16]; /* MUX setting for actual AI operations */
310 unsigned int act_chanlist_len
; /* how long is actual MUX list */
311 unsigned int act_chanlist_pos
; /* actual position in MUX list */
312 unsigned int ai_scans
; /* len of scanlist */
313 unsigned int ai_n_chan
; /* how many channels is measured */
314 unsigned int *ai_chanlist
; /* actaul chanlist */
315 unsigned int ai_flags
; /* flaglist */
316 unsigned int ai_data_len
; /* len of data buffer */
317 short *ai_data
; /* data buffer */
318 unsigned int ai_timer1
; /* timers */
319 unsigned int ai_timer2
;
320 struct comedi_subdevice
*sub_ai
; /* ptr to AI subdevice */
321 unsigned char usefifo
; /* 1=use fifo */
322 unsigned int ao_readback
[2];
325 static const unsigned int muxonechan
[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */
326 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
329 #define devpriv ((struct pcl818_private *)dev->private)
332 ==============================================================================
334 static void setup_channel_list(struct comedi_device
*dev
,
335 struct comedi_subdevice
*s
,
336 unsigned int *chanlist
, unsigned int n_chan
,
337 unsigned int seglen
);
338 static int check_channel_list(struct comedi_device
*dev
,
339 struct comedi_subdevice
*s
,
340 unsigned int *chanlist
, unsigned int n_chan
);
342 static int pcl818_ai_cancel(struct comedi_device
*dev
,
343 struct comedi_subdevice
*s
);
344 static void start_pacer(struct comedi_device
*dev
, int mode
,
345 unsigned int divisor1
, unsigned int divisor2
);
348 static int set_rtc_irq_bit(unsigned char bit
);
349 static void rtc_dropped_irq(unsigned long data
);
350 static int rtc_setfreq_irq(int freq
);
354 ==============================================================================
355 ANALOG INPUT MODE0, 818 cards, slow version
357 static int pcl818_ai_insn_read(struct comedi_device
*dev
,
358 struct comedi_subdevice
*s
,
359 struct comedi_insn
*insn
, unsigned int *data
)
364 /* software trigger, DMA and INT off */
365 outb(0, dev
->iobase
+ PCL818_CONTROL
);
368 outb(muxonechan
[CR_CHAN(insn
->chanspec
)], dev
->iobase
+ PCL818_MUX
);
371 outb(CR_RANGE(insn
->chanspec
), dev
->iobase
+ PCL818_RANGE
);
373 for (n
= 0; n
< insn
->n
; n
++) {
375 /* clear INT (conversion end) flag */
376 outb(0, dev
->iobase
+ PCL818_CLRINT
);
378 /* start conversion */
379 outb(0, dev
->iobase
+ PCL818_AD_LO
);
383 if (inb(dev
->iobase
+ PCL818_STATUS
) & 0x10)
387 comedi_error(dev
, "A/D insn timeout");
388 /* clear INT (conversion end) flag */
389 outb(0, dev
->iobase
+ PCL818_CLRINT
);
393 data
[n
] = ((inb(dev
->iobase
+ PCL818_AD_HI
) << 4) |
394 (inb(dev
->iobase
+ PCL818_AD_LO
) >> 4));
401 ==============================================================================
402 ANALOG OUTPUT MODE0, 818 cards
403 only one sample per call is supported
405 static int pcl818_ao_insn_read(struct comedi_device
*dev
,
406 struct comedi_subdevice
*s
,
407 struct comedi_insn
*insn
, unsigned int *data
)
410 int chan
= CR_CHAN(insn
->chanspec
);
412 for (n
= 0; n
< insn
->n
; n
++)
413 data
[n
] = devpriv
->ao_readback
[chan
];
418 static int pcl818_ao_insn_write(struct comedi_device
*dev
,
419 struct comedi_subdevice
*s
,
420 struct comedi_insn
*insn
, unsigned int *data
)
423 int chan
= CR_CHAN(insn
->chanspec
);
425 for (n
= 0; n
< insn
->n
; n
++) {
426 devpriv
->ao_readback
[chan
] = data
[n
];
427 outb((data
[n
] & 0x000f) << 4, dev
->iobase
+
428 (chan
? PCL718_DA2_LO
: PCL818_DA_LO
));
429 outb((data
[n
] & 0x0ff0) >> 4, dev
->iobase
+
430 (chan
? PCL718_DA2_HI
: PCL818_DA_HI
));
437 ==============================================================================
438 DIGITAL INPUT MODE0, 818 cards
440 only one sample per call is supported
442 static int pcl818_di_insn_bits(struct comedi_device
*dev
,
443 struct comedi_subdevice
*s
,
444 struct comedi_insn
*insn
, unsigned int *data
)
446 data
[1] = inb(dev
->iobase
+ PCL818_DI_LO
) |
447 (inb(dev
->iobase
+ PCL818_DI_HI
) << 8);
453 ==============================================================================
454 DIGITAL OUTPUT MODE0, 818 cards
456 only one sample per call is supported
458 static int pcl818_do_insn_bits(struct comedi_device
*dev
,
459 struct comedi_subdevice
*s
,
460 struct comedi_insn
*insn
, unsigned int *data
)
462 s
->state
&= ~data
[0];
463 s
->state
|= (data
[0] & data
[1]);
465 outb(s
->state
& 0xff, dev
->iobase
+ PCL818_DO_LO
);
466 outb((s
->state
>> 8), dev
->iobase
+ PCL818_DO_HI
);
474 ==============================================================================
475 analog input interrupt mode 1 & 3, 818 cards
476 one sample per interrupt version
478 static irqreturn_t
interrupt_pcl818_ai_mode13_int(int irq
, void *d
)
480 struct comedi_device
*dev
= d
;
481 struct comedi_subdevice
*s
= &dev
->subdevices
[0];
483 int timeout
= 50; /* wait max 50us */
486 if (inb(dev
->iobase
+ PCL818_STATUS
) & 0x10)
490 outb(0, dev
->iobase
+ PCL818_STATUS
); /* clear INT request */
491 comedi_error(dev
, "A/D mode1/3 IRQ without DRDY!");
492 pcl818_ai_cancel(dev
, s
);
493 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
494 comedi_event(dev
, s
);
498 low
= inb(dev
->iobase
+ PCL818_AD_LO
);
499 comedi_buf_put(s
->async
, ((inb(dev
->iobase
+ PCL818_AD_HI
) << 4) | (low
>> 4))); /* get one sample */
500 outb(0, dev
->iobase
+ PCL818_CLRINT
); /* clear INT request */
502 if ((low
& 0xf) != devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]) { /* dropout! */
504 ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
506 devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]);
507 pcl818_ai_cancel(dev
, s
);
508 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
509 comedi_event(dev
, s
);
512 devpriv
->act_chanlist_pos
++;
513 if (devpriv
->act_chanlist_pos
>= devpriv
->act_chanlist_len
)
514 devpriv
->act_chanlist_pos
= 0;
516 s
->async
->cur_chan
++;
517 if (s
->async
->cur_chan
>= devpriv
->ai_n_chan
) {
519 s
->async
->cur_chan
= 0;
520 devpriv
->ai_act_scan
--;
523 if (!devpriv
->neverending_ai
) {
524 if (devpriv
->ai_act_scan
== 0) { /* all data sampled */
525 pcl818_ai_cancel(dev
, s
);
526 s
->async
->events
|= COMEDI_CB_EOA
;
529 comedi_event(dev
, s
);
534 ==============================================================================
535 analog input dma mode 1 & 3, 818 cards
537 static irqreturn_t
interrupt_pcl818_ai_mode13_dma(int irq
, void *d
)
539 struct comedi_device
*dev
= d
;
540 struct comedi_subdevice
*s
= &dev
->subdevices
[0];
545 disable_dma(devpriv
->dma
);
546 devpriv
->next_dma_buf
= 1 - devpriv
->next_dma_buf
;
547 if ((devpriv
->dma_runs_to_end
) > -1 || devpriv
->neverending_ai
) { /* switch dma bufs */
548 set_dma_mode(devpriv
->dma
, DMA_MODE_READ
);
549 flags
= claim_dma_lock();
550 set_dma_addr(devpriv
->dma
,
551 devpriv
->hwdmaptr
[devpriv
->next_dma_buf
]);
552 if (devpriv
->dma_runs_to_end
|| devpriv
->neverending_ai
) {
553 set_dma_count(devpriv
->dma
,
554 devpriv
->hwdmasize
[devpriv
->
557 set_dma_count(devpriv
->dma
, devpriv
->last_dma_run
);
559 release_dma_lock(flags
);
560 enable_dma(devpriv
->dma
);
562 printk("comedi: A/D mode1/3 IRQ \n");
564 devpriv
->dma_runs_to_end
--;
565 outb(0, dev
->iobase
+ PCL818_CLRINT
); /* clear INT request */
566 ptr
= (short *)devpriv
->dmabuf
[1 - devpriv
->next_dma_buf
];
568 len
= devpriv
->hwdmasize
[0] >> 1;
571 for (i
= 0; i
< len
; i
++) {
572 if ((ptr
[bufptr
] & 0xf) != devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]) { /* dropout! */
574 ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
576 devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
],
577 devpriv
->act_chanlist_pos
);
578 pcl818_ai_cancel(dev
, s
);
579 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
580 comedi_event(dev
, s
);
584 comedi_buf_put(s
->async
, ptr
[bufptr
++] >> 4); /* get one sample */
586 devpriv
->act_chanlist_pos
++;
587 if (devpriv
->act_chanlist_pos
>= devpriv
->act_chanlist_len
)
588 devpriv
->act_chanlist_pos
= 0;
590 s
->async
->cur_chan
++;
591 if (s
->async
->cur_chan
>= devpriv
->ai_n_chan
) {
592 s
->async
->cur_chan
= 0;
593 devpriv
->ai_act_scan
--;
596 if (!devpriv
->neverending_ai
)
597 if (devpriv
->ai_act_scan
== 0) { /* all data sampled */
598 pcl818_ai_cancel(dev
, s
);
599 s
->async
->events
|= COMEDI_CB_EOA
;
600 comedi_event(dev
, s
);
601 /* printk("done int ai13 dma\n"); */
607 comedi_event(dev
, s
);
613 ==============================================================================
614 analog input dma mode 1 & 3 over RTC, 818 cards
616 static irqreturn_t
interrupt_pcl818_ai_mode13_dma_rtc(int irq
, void *d
)
618 struct comedi_device
*dev
= d
;
619 struct comedi_subdevice
*s
= &dev
->subdevices
[0];
621 unsigned int top1
, top2
, i
, bufptr
;
623 short *dmabuf
= (short *)devpriv
->dmabuf
[0];
626 switch (devpriv
->ai_mode
) {
627 case INT_TYPE_AI1_DMA_RTC
:
628 case INT_TYPE_AI3_DMA_RTC
:
629 tmp
= (CMOS_READ(RTC_INTR_FLAGS
) & 0xF0);
630 mod_timer(&devpriv
->rtc_irq_timer
,
631 jiffies
+ HZ
/ devpriv
->rtc_freq
+ 2 * HZ
/ 100);
633 for (i
= 0; i
< 10; i
++) {
634 top1
= get_dma_residue(devpriv
->dma
);
635 top2
= get_dma_residue(devpriv
->dma
);
642 top1
= devpriv
->hwdmasize
[0] - top1
; /* where is now DMA in buffer */
644 ofs_dats
= top1
- devpriv
->last_top_dma
; /* new samples from last call */
646 ofs_dats
= (devpriv
->dmasamplsize
) + ofs_dats
;
648 return IRQ_HANDLED
; /* exit=no new samples from last call */
650 i
= devpriv
->last_top_dma
- 1;
651 i
&= (devpriv
->dmasamplsize
- 1);
653 if (dmabuf
[i
] != MAGIC_DMA_WORD
) { /* DMA overflow! */
654 comedi_error(dev
, "A/D mode1/3 DMA buffer overflow!");
655 /* printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize); */
656 pcl818_ai_cancel(dev
, s
);
657 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
658 comedi_event(dev
, s
);
661 /* printk("r %ld ",ofs_dats); */
663 bufptr
= devpriv
->last_top_dma
;
665 for (i
= 0; i
< ofs_dats
; i
++) {
666 if ((dmabuf
[bufptr
] & 0xf) != devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]) { /* dropout! */
668 ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",
669 (dmabuf
[bufptr
] & 0xf),
671 act_chanlist
[devpriv
->act_chanlist_pos
]);
672 pcl818_ai_cancel(dev
, s
);
674 COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
675 comedi_event(dev
, s
);
679 comedi_buf_put(s
->async
, dmabuf
[bufptr
++] >> 4); /* get one sample */
680 bufptr
&= (devpriv
->dmasamplsize
- 1);
682 devpriv
->act_chanlist_pos
++;
683 if (devpriv
->act_chanlist_pos
>=
684 devpriv
->act_chanlist_len
) {
685 devpriv
->act_chanlist_pos
= 0;
687 s
->async
->cur_chan
++;
688 if (s
->async
->cur_chan
>= devpriv
->ai_n_chan
) {
689 s
->async
->cur_chan
= 0;
690 devpriv
->ai_act_scan
--;
693 if (!devpriv
->neverending_ai
)
694 if (devpriv
->ai_act_scan
== 0) { /* all data sampled */
695 pcl818_ai_cancel(dev
, s
);
696 s
->async
->events
|= COMEDI_CB_EOA
;
697 comedi_event(dev
, s
);
698 /* printk("done int ai13 dma\n"); */
703 devpriv
->last_top_dma
= bufptr
;
705 bufptr
&= (devpriv
->dmasamplsize
- 1);
706 dmabuf
[bufptr
] = MAGIC_DMA_WORD
;
707 comedi_event(dev
, s
);
718 ==============================================================================
719 analog input interrupt mode 1 & 3, 818HD/HG cards
721 static irqreturn_t
interrupt_pcl818_ai_mode13_fifo(int irq
, void *d
)
723 struct comedi_device
*dev
= d
;
724 struct comedi_subdevice
*s
= &dev
->subdevices
[0];
727 outb(0, dev
->iobase
+ PCL818_FI_INTCLR
); /* clear fifo int request */
729 lo
= inb(dev
->iobase
+ PCL818_FI_STATUS
);
732 comedi_error(dev
, "A/D mode1/3 FIFO overflow!");
733 pcl818_ai_cancel(dev
, s
);
734 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
735 comedi_event(dev
, s
);
740 comedi_error(dev
, "A/D mode1/3 FIFO interrupt without data!");
741 pcl818_ai_cancel(dev
, s
);
742 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
743 comedi_event(dev
, s
);
752 for (i
= 0; i
< len
; i
++) {
753 lo
= inb(dev
->iobase
+ PCL818_FI_DATALO
);
754 if ((lo
& 0xf) != devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]) { /* dropout! */
756 ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
758 devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]);
759 pcl818_ai_cancel(dev
, s
);
760 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
761 comedi_event(dev
, s
);
765 comedi_buf_put(s
->async
, (lo
>> 4) | (inb(dev
->iobase
+ PCL818_FI_DATAHI
) << 4)); /* get one sample */
767 devpriv
->act_chanlist_pos
++;
768 if (devpriv
->act_chanlist_pos
>= devpriv
->act_chanlist_len
)
769 devpriv
->act_chanlist_pos
= 0;
771 s
->async
->cur_chan
++;
772 if (s
->async
->cur_chan
>= devpriv
->ai_n_chan
) {
773 s
->async
->cur_chan
= 0;
774 devpriv
->ai_act_scan
--;
777 if (!devpriv
->neverending_ai
)
778 if (devpriv
->ai_act_scan
== 0) { /* all data sampled */
779 pcl818_ai_cancel(dev
, s
);
780 s
->async
->events
|= COMEDI_CB_EOA
;
781 comedi_event(dev
, s
);
787 comedi_event(dev
, s
);
792 ==============================================================================
795 static irqreturn_t
interrupt_pcl818(int irq
, void *d
)
797 struct comedi_device
*dev
= d
;
799 if (!dev
->attached
) {
800 comedi_error(dev
, "premature interrupt");
805 if (devpriv
->irq_blocked
&& devpriv
->irq_was_now_closed
) {
806 if ((devpriv
->neverending_ai
|| (!devpriv
->neverending_ai
&&
807 devpriv
->ai_act_scan
> 0)) &&
808 (devpriv
->ai_mode
== INT_TYPE_AI1_DMA
||
809 devpriv
->ai_mode
== INT_TYPE_AI3_DMA
)) {
810 /* The cleanup from ai_cancel() has been delayed
811 until now because the card doesn't seem to like
812 being reprogrammed while a DMA transfer is in
815 struct comedi_subdevice
*s
= &dev
->subdevices
[0];
816 devpriv
->ai_act_scan
= 0;
817 devpriv
->neverending_ai
= 0;
818 pcl818_ai_cancel(dev
, s
);
821 outb(0, dev
->iobase
+ PCL818_CLRINT
); /* clear INT request */
826 switch (devpriv
->ai_mode
) {
827 case INT_TYPE_AI1_DMA
:
828 case INT_TYPE_AI3_DMA
:
829 return interrupt_pcl818_ai_mode13_dma(irq
, d
);
830 case INT_TYPE_AI1_INT
:
831 case INT_TYPE_AI3_INT
:
832 return interrupt_pcl818_ai_mode13_int(irq
, d
);
833 case INT_TYPE_AI1_FIFO
:
834 case INT_TYPE_AI3_FIFO
:
835 return interrupt_pcl818_ai_mode13_fifo(irq
, d
);
836 #ifdef PCL818_MODE13_AO
837 case INT_TYPE_AO1_INT
:
838 case INT_TYPE_AO3_INT
:
839 return interrupt_pcl818_ao_mode13_int(irq
, d
);
845 outb(0, dev
->iobase
+ PCL818_CLRINT
); /* clear INT request */
847 if ((!dev
->irq
) || (!devpriv
->irq_free
) || (!devpriv
->irq_blocked
)
848 || (!devpriv
->ai_mode
)) {
849 comedi_error(dev
, "bad IRQ!");
853 comedi_error(dev
, "IRQ from unknown source!");
858 ==============================================================================
859 ANALOG INPUT MODE 1 or 3 DMA , 818 cards
861 static void pcl818_ai_mode13dma_int(int mode
, struct comedi_device
*dev
,
862 struct comedi_subdevice
*s
)
867 printk("mode13dma_int, mode: %d\n", mode
);
868 disable_dma(devpriv
->dma
); /* disable dma */
869 bytes
= devpriv
->hwdmasize
[0];
870 if (!devpriv
->neverending_ai
) {
871 bytes
= devpriv
->ai_n_chan
* devpriv
->ai_scans
* sizeof(short); /* how many */
872 devpriv
->dma_runs_to_end
= bytes
/ devpriv
->hwdmasize
[0]; /* how many DMA pages we must fiil */
873 devpriv
->last_dma_run
= bytes
% devpriv
->hwdmasize
[0]; /* on last dma transfer must be moved */
874 devpriv
->dma_runs_to_end
--;
875 if (devpriv
->dma_runs_to_end
>= 0)
876 bytes
= devpriv
->hwdmasize
[0];
879 devpriv
->next_dma_buf
= 0;
880 set_dma_mode(devpriv
->dma
, DMA_MODE_READ
);
881 flags
= claim_dma_lock();
882 clear_dma_ff(devpriv
->dma
);
883 set_dma_addr(devpriv
->dma
, devpriv
->hwdmaptr
[0]);
884 set_dma_count(devpriv
->dma
, bytes
);
885 release_dma_lock(flags
);
886 enable_dma(devpriv
->dma
);
889 devpriv
->ai_mode
= INT_TYPE_AI1_DMA
;
890 outb(0x87 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Pacer+IRQ+DMA */
892 devpriv
->ai_mode
= INT_TYPE_AI3_DMA
;
893 outb(0x86 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Ext trig+IRQ+DMA */
899 ==============================================================================
900 ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards
902 static void pcl818_ai_mode13dma_rtc(int mode
, struct comedi_device
*dev
,
903 struct comedi_subdevice
*s
)
908 set_dma_mode(devpriv
->dma
, DMA_MODE_READ
| DMA_AUTOINIT
);
909 flags
= claim_dma_lock();
910 clear_dma_ff(devpriv
->dma
);
911 set_dma_addr(devpriv
->dma
, devpriv
->hwdmaptr
[0]);
912 set_dma_count(devpriv
->dma
, devpriv
->hwdmasize
[0]);
913 release_dma_lock(flags
);
914 enable_dma(devpriv
->dma
);
915 devpriv
->last_top_dma
= 0; /* devpriv->hwdmasize[0]; */
916 pole
= (short *)devpriv
->dmabuf
[0];
917 devpriv
->dmasamplsize
= devpriv
->hwdmasize
[0] / 2;
918 pole
[devpriv
->dmasamplsize
- 1] = MAGIC_DMA_WORD
;
920 devpriv
->rtc_freq
= rtc_setfreq_irq(2048);
921 devpriv
->rtc_irq_timer
.expires
=
922 jiffies
+ HZ
/ devpriv
->rtc_freq
+ 2 * HZ
/ 100;
923 devpriv
->rtc_irq_timer
.data
= (unsigned long)dev
;
924 devpriv
->rtc_irq_timer
.function
= rtc_dropped_irq
;
926 add_timer(&devpriv
->rtc_irq_timer
);
930 devpriv
->int818_mode
= INT_TYPE_AI1_DMA_RTC
;
931 outb(0x07 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Pacer+DMA */
933 devpriv
->int818_mode
= INT_TYPE_AI3_DMA_RTC
;
934 outb(0x06 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Ext trig+DMA */
940 ==============================================================================
941 ANALOG INPUT MODE 1 or 3, 818 cards
943 static int pcl818_ai_cmd_mode(int mode
, struct comedi_device
*dev
,
944 struct comedi_subdevice
*s
)
946 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
947 int divisor1
= 0, divisor2
= 0;
950 dev_dbg(dev
->class_dev
, "pcl818_ai_cmd_mode()\n");
951 if ((!dev
->irq
) && (!devpriv
->dma_rtc
)) {
952 comedi_error(dev
, "IRQ not defined!");
956 if (devpriv
->irq_blocked
)
959 start_pacer(dev
, -1, 0, 0); /* stop pacer */
961 seglen
= check_channel_list(dev
, s
, devpriv
->ai_chanlist
,
965 setup_channel_list(dev
, s
, devpriv
->ai_chanlist
,
966 devpriv
->ai_n_chan
, seglen
);
970 devpriv
->ai_act_scan
= devpriv
->ai_scans
;
971 devpriv
->ai_act_chan
= 0;
972 devpriv
->irq_blocked
= 1;
973 devpriv
->irq_was_now_closed
= 0;
974 devpriv
->neverending_ai
= 0;
975 devpriv
->act_chanlist_pos
= 0;
976 devpriv
->dma_runs_to_end
= 0;
978 if ((devpriv
->ai_scans
== 0) || (devpriv
->ai_scans
== -1))
979 devpriv
->neverending_ai
= 1; /* well, user want neverending */
982 i8253_cascade_ns_to_timer(devpriv
->i8253_osc_base
, &divisor1
,
983 &divisor2
, &cmd
->convert_arg
,
985 if (divisor1
== 1) { /* PCL718/818 crash if any divisor is set to 1 */
995 outb(0, dev
->iobase
+ PCL818_CNTENABLE
); /* enable pacer */
997 switch (devpriv
->dma
) {
1000 if (devpriv
->dma_rtc
== 0) {
1001 pcl818_ai_mode13dma_int(mode
, dev
, s
);
1005 pcl818_ai_mode13dma_rtc(mode
, dev
, s
);
1014 if (!devpriv
->usefifo
) {
1016 /* printk("IRQ\n"); */
1018 devpriv
->ai_mode
= INT_TYPE_AI1_INT
;
1020 outb(0x83 | (dev
->irq
<< 4),
1021 dev
->iobase
+ PCL818_CONTROL
);
1023 devpriv
->ai_mode
= INT_TYPE_AI3_INT
;
1025 outb(0x82 | (dev
->irq
<< 4),
1026 dev
->iobase
+ PCL818_CONTROL
);
1031 outb(1, dev
->iobase
+ PCL818_FI_ENABLE
);
1033 devpriv
->ai_mode
= INT_TYPE_AI1_FIFO
;
1035 outb(0x03, dev
->iobase
+ PCL818_CONTROL
);
1037 devpriv
->ai_mode
= INT_TYPE_AI3_FIFO
;
1038 outb(0x02, dev
->iobase
+ PCL818_CONTROL
);
1043 start_pacer(dev
, mode
, divisor1
, divisor2
);
1046 switch (devpriv
->ai_mode
) {
1047 case INT_TYPE_AI1_DMA_RTC
:
1048 case INT_TYPE_AI3_DMA_RTC
:
1049 set_rtc_irq_bit(1); /* start RTC */
1053 dev_dbg(dev
->class_dev
, "pcl818_ai_cmd_mode() end\n");
1059 ==============================================================================
1060 ANALOG OUTPUT MODE 1 or 3, 818 cards
1062 #ifdef PCL818_MODE13_AO
1063 static int pcl818_ao_mode13(int mode
, struct comedi_device
*dev
,
1064 struct comedi_subdevice
*s
, comedi_trig
* it
)
1066 int divisor1
= 0, divisor2
= 0;
1069 comedi_error(dev
, "IRQ not defined!");
1073 if (devpriv
->irq_blocked
)
1076 start_pacer(dev
, -1, 0, 0); /* stop pacer */
1078 devpriv
->int13_act_scan
= it
->n
;
1079 devpriv
->int13_act_chan
= 0;
1080 devpriv
->irq_blocked
= 1;
1081 devpriv
->irq_was_now_closed
= 0;
1082 devpriv
->neverending_ai
= 0;
1083 devpriv
->act_chanlist_pos
= 0;
1086 i8253_cascade_ns_to_timer(devpriv
->i8253_osc_base
, &divisor1
,
1087 &divisor2
, &it
->trigvar
,
1088 TRIG_ROUND_NEAREST
);
1089 if (divisor1
== 1) { /* PCL818 crash if any divisor is set to 1 */
1093 if (divisor2
== 1) {
1099 outb(0, dev
->iobase
+ PCL818_CNTENABLE
); /* enable pacer */
1101 devpriv
->int818_mode
= INT_TYPE_AO1_INT
;
1102 outb(0x83 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Pacer+IRQ */
1104 devpriv
->int818_mode
= INT_TYPE_AO3_INT
;
1105 outb(0x82 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Ext trig+IRQ */
1108 start_pacer(dev
, mode
, divisor1
, divisor2
);
1114 ==============================================================================
1115 ANALOG OUTPUT MODE 1, 818 cards
1117 static int pcl818_ao_mode1(struct comedi_device
*dev
,
1118 struct comedi_subdevice
*s
, comedi_trig
* it
)
1120 return pcl818_ao_mode13(1, dev
, s
, it
);
1124 ==============================================================================
1125 ANALOG OUTPUT MODE 3, 818 cards
1127 static int pcl818_ao_mode3(struct comedi_device
*dev
,
1128 struct comedi_subdevice
*s
, comedi_trig
* it
)
1130 return pcl818_ao_mode13(3, dev
, s
, it
);
1136 ==============================================================================
1137 Start/stop pacer onboard pacer
1139 static void start_pacer(struct comedi_device
*dev
, int mode
,
1140 unsigned int divisor1
, unsigned int divisor2
)
1142 outb(0xb4, dev
->iobase
+ PCL818_CTRCTL
);
1143 outb(0x74, dev
->iobase
+ PCL818_CTRCTL
);
1147 outb(divisor2
& 0xff, dev
->iobase
+ PCL818_CTR2
);
1148 outb((divisor2
>> 8) & 0xff, dev
->iobase
+ PCL818_CTR2
);
1149 outb(divisor1
& 0xff, dev
->iobase
+ PCL818_CTR1
);
1150 outb((divisor1
>> 8) & 0xff, dev
->iobase
+ PCL818_CTR1
);
1155 ==============================================================================
1156 Check if channel list from user is builded correctly
1157 If it's ok, then program scan/gain logic
1159 static int check_channel_list(struct comedi_device
*dev
,
1160 struct comedi_subdevice
*s
,
1161 unsigned int *chanlist
, unsigned int n_chan
)
1163 unsigned int chansegment
[16];
1164 unsigned int i
, nowmustbechan
, seglen
, segpos
;
1166 /* correct channel and range number check itself comedi/range.c */
1168 comedi_error(dev
, "range/channel list is empty!");
1173 /* first channel is every time ok */
1174 chansegment
[0] = chanlist
[0];
1175 /* build part of chanlist */
1176 for (i
= 1, seglen
= 1; i
< n_chan
; i
++, seglen
++) {
1178 /* printk("%d. %d * %d\n",i,
1179 * CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));*/
1181 /* we detect loop, this must by finish */
1183 if (chanlist
[0] == chanlist
[i
])
1186 (CR_CHAN(chansegment
[i
- 1]) + 1) % s
->n_chan
;
1187 if (nowmustbechan
!= CR_CHAN(chanlist
[i
])) { /* channel list isn't continuous :-( */
1189 ("comedi%d: pcl818: channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
1190 dev
->minor
, i
, CR_CHAN(chanlist
[i
]),
1191 nowmustbechan
, CR_CHAN(chanlist
[0]));
1194 /* well, this is next correct channel in list */
1195 chansegment
[i
] = chanlist
[i
];
1198 /* check whole chanlist */
1199 for (i
= 0, segpos
= 0; i
< n_chan
; i
++) {
1200 /* 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])); */
1201 if (chanlist
[i
] != chansegment
[i
% seglen
]) {
1203 ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1204 dev
->minor
, i
, CR_CHAN(chansegment
[i
]),
1205 CR_RANGE(chansegment
[i
]),
1206 CR_AREF(chansegment
[i
]),
1207 CR_CHAN(chanlist
[i
% seglen
]),
1208 CR_RANGE(chanlist
[i
% seglen
]),
1209 CR_AREF(chansegment
[i
% seglen
]));
1210 return 0; /* chan/gain list is strange */
1216 printk("check_channel_list: seglen %d\n", seglen
);
1220 static void setup_channel_list(struct comedi_device
*dev
,
1221 struct comedi_subdevice
*s
,
1222 unsigned int *chanlist
, unsigned int n_chan
,
1223 unsigned int seglen
)
1227 devpriv
->act_chanlist_len
= seglen
;
1228 devpriv
->act_chanlist_pos
= 0;
1230 for (i
= 0; i
< seglen
; i
++) { /* store range list to card */
1231 devpriv
->act_chanlist
[i
] = CR_CHAN(chanlist
[i
]);
1232 outb(muxonechan
[CR_CHAN(chanlist
[i
])], dev
->iobase
+ PCL818_MUX
); /* select channel */
1233 outb(CR_RANGE(chanlist
[i
]), dev
->iobase
+ PCL818_RANGE
); /* select gain */
1238 /* select channel interval to scan */
1239 outb(devpriv
->act_chanlist
[0] | (devpriv
->act_chanlist
[seglen
-
1241 dev
->iobase
+ PCL818_MUX
);
1245 ==============================================================================
1246 Check if board is switched to SE (1) or DIFF(0) mode
1248 static int check_single_ended(unsigned int port
)
1250 if (inb(port
+ PCL818_STATUS
) & 0x20)
1256 ==============================================================================
1258 static int ai_cmdtest(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
1259 struct comedi_cmd
*cmd
)
1261 const struct pcl818_board
*board
= comedi_board(dev
);
1263 int tmp
, divisor1
= 0, divisor2
= 0;
1265 /* Step 1 : check if triggers are trivially valid */
1267 err
|= cfc_check_trigger_src(&cmd
->start_src
, TRIG_NOW
);
1268 err
|= cfc_check_trigger_src(&cmd
->scan_begin_src
, TRIG_FOLLOW
);
1269 err
|= cfc_check_trigger_src(&cmd
->convert_src
, TRIG_TIMER
| TRIG_EXT
);
1270 err
|= cfc_check_trigger_src(&cmd
->scan_end_src
, TRIG_COUNT
);
1271 err
|= cfc_check_trigger_src(&cmd
->stop_src
, TRIG_COUNT
| TRIG_NONE
);
1276 /* Step 2a : make sure trigger sources are unique */
1278 err
|= cfc_check_trigger_is_unique(cmd
->convert_src
);
1279 err
|= cfc_check_trigger_is_unique(cmd
->stop_src
);
1281 /* Step 2b : and mutually compatible */
1286 /* step 3: make sure arguments are trivially compatible */
1288 if (cmd
->start_arg
!= 0) {
1293 if (cmd
->scan_begin_arg
!= 0) {
1294 cmd
->scan_begin_arg
= 0;
1298 if (cmd
->convert_src
== TRIG_TIMER
) {
1299 if (cmd
->convert_arg
< board
->ns_min
) {
1300 cmd
->convert_arg
= board
->ns_min
;
1303 } else { /* TRIG_EXT */
1304 if (cmd
->convert_arg
!= 0) {
1305 cmd
->convert_arg
= 0;
1310 if (cmd
->scan_end_arg
!= cmd
->chanlist_len
) {
1311 cmd
->scan_end_arg
= cmd
->chanlist_len
;
1314 if (cmd
->stop_src
== TRIG_COUNT
) {
1315 if (!cmd
->stop_arg
) {
1319 } else { /* TRIG_NONE */
1320 if (cmd
->stop_arg
!= 0) {
1329 /* step 4: fix up any arguments */
1331 if (cmd
->convert_src
== TRIG_TIMER
) {
1332 tmp
= cmd
->convert_arg
;
1333 i8253_cascade_ns_to_timer(devpriv
->i8253_osc_base
, &divisor1
,
1334 &divisor2
, &cmd
->convert_arg
,
1335 cmd
->flags
& TRIG_ROUND_MASK
);
1336 if (cmd
->convert_arg
< board
->ns_min
)
1337 cmd
->convert_arg
= board
->ns_min
;
1338 if (tmp
!= cmd
->convert_arg
)
1345 /* step 5: complain about special chanlist considerations */
1347 if (cmd
->chanlist
) {
1348 if (!check_channel_list(dev
, s
, cmd
->chanlist
,
1350 return 5; /* incorrect channels list */
1357 ==============================================================================
1359 static int ai_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
1361 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
1364 dev_dbg(dev
->class_dev
, "pcl818_ai_cmd()\n");
1365 devpriv
->ai_n_chan
= cmd
->chanlist_len
;
1366 devpriv
->ai_chanlist
= cmd
->chanlist
;
1367 devpriv
->ai_flags
= cmd
->flags
;
1368 devpriv
->ai_data_len
= s
->async
->prealloc_bufsz
;
1369 devpriv
->ai_data
= s
->async
->prealloc_buf
;
1370 devpriv
->ai_timer1
= 0;
1371 devpriv
->ai_timer2
= 0;
1373 if (cmd
->stop_src
== TRIG_COUNT
)
1374 devpriv
->ai_scans
= cmd
->stop_arg
;
1376 devpriv
->ai_scans
= 0;
1378 if (cmd
->scan_begin_src
== TRIG_FOLLOW
) { /* mode 1, 3 */
1379 if (cmd
->convert_src
== TRIG_TIMER
) { /* mode 1 */
1380 devpriv
->ai_timer1
= cmd
->convert_arg
;
1381 retval
= pcl818_ai_cmd_mode(1, dev
, s
);
1382 dev_dbg(dev
->class_dev
, "pcl818_ai_cmd() end\n");
1385 if (cmd
->convert_src
== TRIG_EXT
) { /* mode 3 */
1386 return pcl818_ai_cmd_mode(3, dev
, s
);
1394 ==============================================================================
1395 cancel any mode 1-4 AI
1397 static int pcl818_ai_cancel(struct comedi_device
*dev
,
1398 struct comedi_subdevice
*s
)
1400 if (devpriv
->irq_blocked
> 0) {
1401 dev_dbg(dev
->class_dev
, "pcl818_ai_cancel()\n");
1402 devpriv
->irq_was_now_closed
= 1;
1404 switch (devpriv
->ai_mode
) {
1406 case INT_TYPE_AI1_DMA_RTC
:
1407 case INT_TYPE_AI3_DMA_RTC
:
1408 set_rtc_irq_bit(0); /* stop RTC */
1409 del_timer(&devpriv
->rtc_irq_timer
);
1411 case INT_TYPE_AI1_DMA
:
1412 case INT_TYPE_AI3_DMA
:
1413 if (devpriv
->neverending_ai
||
1414 (!devpriv
->neverending_ai
&&
1415 devpriv
->ai_act_scan
> 0)) {
1416 /* wait for running dma transfer to end, do cleanup in interrupt */
1419 disable_dma(devpriv
->dma
);
1420 case INT_TYPE_AI1_INT
:
1421 case INT_TYPE_AI3_INT
:
1422 case INT_TYPE_AI1_FIFO
:
1423 case INT_TYPE_AI3_FIFO
:
1424 #ifdef PCL818_MODE13_AO
1425 case INT_TYPE_AO1_INT
:
1426 case INT_TYPE_AO3_INT
:
1428 outb(inb(dev
->iobase
+ PCL818_CONTROL
) & 0x73, dev
->iobase
+ PCL818_CONTROL
); /* Stop A/D */
1430 start_pacer(dev
, -1, 0, 0);
1431 outb(0, dev
->iobase
+ PCL818_AD_LO
);
1432 inb(dev
->iobase
+ PCL818_AD_LO
);
1433 inb(dev
->iobase
+ PCL818_AD_HI
);
1434 outb(0, dev
->iobase
+ PCL818_CLRINT
); /* clear INT request */
1435 outb(0, dev
->iobase
+ PCL818_CONTROL
); /* Stop A/D */
1436 if (devpriv
->usefifo
) { /* FIFO shutdown */
1437 outb(0, dev
->iobase
+ PCL818_FI_INTCLR
);
1438 outb(0, dev
->iobase
+ PCL818_FI_FLUSH
);
1439 outb(0, dev
->iobase
+ PCL818_FI_ENABLE
);
1441 devpriv
->irq_blocked
= 0;
1442 devpriv
->last_int_sub
= s
;
1443 devpriv
->neverending_ai
= 0;
1444 devpriv
->ai_mode
= 0;
1445 devpriv
->irq_was_now_closed
= 0;
1451 dev_dbg(dev
->class_dev
, "pcl818_ai_cancel() end\n");
1456 ==============================================================================
1459 static int pcl818_check(unsigned long iobase
)
1461 outb(0x00, iobase
+ PCL818_MUX
);
1463 if (inb(iobase
+ PCL818_MUX
) != 0x00)
1464 return 1; /* there isn't card */
1465 outb(0x55, iobase
+ PCL818_MUX
);
1467 if (inb(iobase
+ PCL818_MUX
) != 0x55)
1468 return 1; /* there isn't card */
1469 outb(0x00, iobase
+ PCL818_MUX
);
1471 outb(0x18, iobase
+ PCL818_CONTROL
);
1473 if (inb(iobase
+ PCL818_CONTROL
) != 0x18)
1474 return 1; /* there isn't card */
1475 return 0; /* ok, card exist */
1479 ==============================================================================
1480 reset whole PCL-818 cards
1482 static void pcl818_reset(struct comedi_device
*dev
)
1484 const struct pcl818_board
*board
= comedi_board(dev
);
1486 if (devpriv
->usefifo
) { /* FIFO shutdown */
1487 outb(0, dev
->iobase
+ PCL818_FI_INTCLR
);
1488 outb(0, dev
->iobase
+ PCL818_FI_FLUSH
);
1489 outb(0, dev
->iobase
+ PCL818_FI_ENABLE
);
1491 outb(0, dev
->iobase
+ PCL818_DA_LO
); /* DAC=0V */
1492 outb(0, dev
->iobase
+ PCL818_DA_HI
);
1494 outb(0, dev
->iobase
+ PCL818_DO_HI
); /* DO=$0000 */
1495 outb(0, dev
->iobase
+ PCL818_DO_LO
);
1497 outb(0, dev
->iobase
+ PCL818_CONTROL
);
1498 outb(0, dev
->iobase
+ PCL818_CNTENABLE
);
1499 outb(0, dev
->iobase
+ PCL818_MUX
);
1500 outb(0, dev
->iobase
+ PCL818_CLRINT
);
1501 outb(0xb0, dev
->iobase
+ PCL818_CTRCTL
); /* Stop pacer */
1502 outb(0x70, dev
->iobase
+ PCL818_CTRCTL
);
1503 outb(0x30, dev
->iobase
+ PCL818_CTRCTL
);
1504 if (board
->is_818
) {
1505 outb(0, dev
->iobase
+ PCL818_RANGE
);
1507 outb(0, dev
->iobase
+ PCL718_DA2_LO
);
1508 outb(0, dev
->iobase
+ PCL718_DA2_HI
);
1514 ==============================================================================
1515 Enable(1)/disable(0) periodic interrupts from RTC
1517 static int set_rtc_irq_bit(unsigned char bit
)
1520 unsigned long flags
;
1524 if (RTC_timer_lock
> 1)
1528 if (RTC_timer_lock
< 0)
1530 if (RTC_timer_lock
> 0)
1536 val
= CMOS_READ(RTC_CONTROL
);
1542 CMOS_WRITE(val
, RTC_CONTROL
);
1543 CMOS_READ(RTC_INTR_FLAGS
);
1544 restore_flags(flags
);
1549 ==============================================================================
1550 Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers)
1552 static void rtc_dropped_irq(unsigned long data
)
1554 struct comedi_device
*dev
= (void *)data
;
1555 unsigned long flags
, tmp
;
1557 switch (devpriv
->int818_mode
) {
1558 case INT_TYPE_AI1_DMA_RTC
:
1559 case INT_TYPE_AI3_DMA_RTC
:
1560 mod_timer(&devpriv
->rtc_irq_timer
,
1561 jiffies
+ HZ
/ devpriv
->rtc_freq
+ 2 * HZ
/ 100);
1564 tmp
= (CMOS_READ(RTC_INTR_FLAGS
) & 0xF0); /* restart */
1565 restore_flags(flags
);
1571 ==============================================================================
1572 Set frequency of interrupts from RTC
1574 static int rtc_setfreq_irq(int freq
)
1579 unsigned long flags
;
1586 while (freq
> (1 << tmp
))
1589 rtc_freq
= 1 << tmp
;
1593 val
= CMOS_READ(RTC_FREQ_SELECT
) & 0xf0;
1595 CMOS_WRITE(val
, RTC_FREQ_SELECT
);
1596 restore_flags(flags
);
1601 static int pcl818_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
1603 const struct pcl818_board
*board
= comedi_board(dev
);
1605 unsigned long iobase
;
1608 unsigned long pages
;
1609 struct comedi_subdevice
*s
;
1611 ret
= alloc_private(dev
, sizeof(struct pcl818_private
));
1613 return ret
; /* Can't alloc mem */
1615 /* claim our I/O space */
1616 iobase
= it
->options
[0];
1618 ("comedi%d: pcl818: board=%s, ioport=0x%03lx",
1619 dev
->minor
, board
->name
, iobase
);
1620 devpriv
->io_range
= board
->io_range
;
1621 if ((board
->fifo
) && (it
->options
[2] == -1)) {
1622 /* we've board with FIFO and we want to use FIFO */
1623 devpriv
->io_range
= PCLx1xFIFO_RANGE
;
1624 devpriv
->usefifo
= 1;
1626 if (!request_region(iobase
, devpriv
->io_range
, "pcl818")) {
1627 comedi_error(dev
, "I/O port conflict\n");
1631 dev
->iobase
= iobase
;
1633 if (pcl818_check(iobase
)) {
1634 comedi_error(dev
, "I can't detect board. FAIL!\n");
1638 dev
->board_name
= board
->name
;
1642 if (board
->IRQbits
!= 0) { /* board support IRQ */
1643 irq
= it
->options
[1];
1644 if (irq
) { /* we want to use IRQ */
1645 if (((1 << irq
) & board
->IRQbits
) == 0) {
1647 (", IRQ %u is out of allowed range, DISABLING IT",
1649 irq
= 0; /* Bad IRQ */
1652 (irq
, interrupt_pcl818
, 0, "pcl818", dev
)) {
1654 (", unable to allocate IRQ %u, DISABLING IT",
1656 irq
= 0; /* Can't use IRQ */
1658 printk(KERN_DEBUG
"irq=%u", irq
);
1666 devpriv
->irq_free
= 1; /* 1=we have allocated irq */
1668 devpriv
->irq_free
= 0;
1670 devpriv
->irq_blocked
= 0; /* number of subdevice which use IRQ */
1671 devpriv
->ai_mode
= 0; /* mode of irq */
1674 /* grab RTC for DMA operations */
1675 devpriv
->dma_rtc
= 0;
1676 if (it
->options
[2] > 0) { /* we want to use DMA */
1677 if (RTC_lock
== 0) {
1678 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT
,
1682 devpriv
->rtc_iobase
= RTC_PORT(0);
1683 devpriv
->rtc_iosize
= RTC_IO_EXTENT
;
1685 if (!request_irq(RTC_IRQ
, interrupt_pcl818_ai_mode13_dma_rtc
, 0,
1686 "pcl818 DMA (RTC)", dev
)) {
1687 devpriv
->dma_rtc
= 1;
1688 devpriv
->rtc_irq
= RTC_IRQ
;
1689 printk(KERN_DEBUG
"dma_irq=%u", devpriv
->rtc_irq
);
1692 if (RTC_lock
== 0) {
1693 if (devpriv
->rtc_iobase
)
1694 release_region(devpriv
->rtc_iobase
,
1695 devpriv
->rtc_iosize
);
1697 devpriv
->rtc_iobase
= 0;
1698 devpriv
->rtc_iosize
= 0;
1707 if ((devpriv
->irq_free
== 0) && (devpriv
->dma_rtc
== 0))
1708 goto no_dma
; /* if we haven't IRQ, we can't use DMA */
1709 if (board
->DMAbits
!= 0) { /* board support DMA */
1710 dma
= it
->options
[2];
1712 goto no_dma
; /* DMA disabled */
1713 if (((1 << dma
) & board
->DMAbits
) == 0) {
1714 printk(KERN_ERR
"DMA is out of allowed range, FAIL!\n");
1715 return -EINVAL
; /* Bad DMA */
1717 ret
= request_dma(dma
, "pcl818");
1719 return -EBUSY
; /* DMA isn't free */
1721 pages
= 2; /* we need 16KB */
1722 devpriv
->dmabuf
[0] = __get_dma_pages(GFP_KERNEL
, pages
);
1723 if (!devpriv
->dmabuf
[0])
1724 /* maybe experiment with try_to_free_pages() will help .... */
1725 return -EBUSY
; /* no buffer :-( */
1726 devpriv
->dmapages
[0] = pages
;
1727 devpriv
->hwdmaptr
[0] = virt_to_bus((void *)devpriv
->dmabuf
[0]);
1728 devpriv
->hwdmasize
[0] = (1 << pages
) * PAGE_SIZE
;
1729 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
1730 if (devpriv
->dma_rtc
== 0) { /* we must do duble buff :-( */
1731 devpriv
->dmabuf
[1] = __get_dma_pages(GFP_KERNEL
, pages
);
1732 if (!devpriv
->dmabuf
[1])
1734 devpriv
->dmapages
[1] = pages
;
1735 devpriv
->hwdmaptr
[1] =
1736 virt_to_bus((void *)devpriv
->dmabuf
[1]);
1737 devpriv
->hwdmasize
[1] = (1 << pages
) * PAGE_SIZE
;
1743 ret
= comedi_alloc_subdevices(dev
, 4);
1747 s
= &dev
->subdevices
[0];
1748 if (!board
->n_aichan_se
) {
1749 s
->type
= COMEDI_SUBD_UNUSED
;
1751 s
->type
= COMEDI_SUBD_AI
;
1752 devpriv
->sub_ai
= s
;
1753 s
->subdev_flags
= SDF_READABLE
;
1754 if (check_single_ended(dev
->iobase
)) {
1755 s
->n_chan
= board
->n_aichan_se
;
1756 s
->subdev_flags
|= SDF_COMMON
| SDF_GROUND
;
1757 printk(", %dchans S.E. DAC", s
->n_chan
);
1759 s
->n_chan
= board
->n_aichan_diff
;
1760 s
->subdev_flags
|= SDF_DIFF
;
1761 printk(", %dchans DIFF DAC", s
->n_chan
);
1763 s
->maxdata
= board
->ai_maxdata
;
1764 s
->len_chanlist
= s
->n_chan
;
1765 s
->range_table
= board
->ai_range_type
;
1766 s
->cancel
= pcl818_ai_cancel
;
1767 s
->insn_read
= pcl818_ai_insn_read
;
1768 if ((irq
) || (devpriv
->dma_rtc
)) {
1769 dev
->read_subdev
= s
;
1770 s
->subdev_flags
|= SDF_CMD_READ
;
1771 s
->do_cmdtest
= ai_cmdtest
;
1774 if (board
->is_818
) {
1775 if ((it
->options
[4] == 1) || (it
->options
[4] == 10))
1776 s
->range_table
= &range_pcl818l_h_ai
; /* secondary range list jumper selectable */
1778 switch (it
->options
[4]) {
1780 s
->range_table
= &range_bipolar10
;
1783 s
->range_table
= &range_bipolar5
;
1786 s
->range_table
= &range_bipolar2_5
;
1789 s
->range_table
= &range718_bipolar1
;
1792 s
->range_table
= &range718_bipolar0_5
;
1795 s
->range_table
= &range_unipolar10
;
1798 s
->range_table
= &range_unipolar5
;
1801 s
->range_table
= &range718_unipolar2
;
1804 s
->range_table
= &range718_unipolar1
;
1807 s
->range_table
= &range_unknown
;
1813 s
= &dev
->subdevices
[1];
1814 if (!board
->n_aochan
) {
1815 s
->type
= COMEDI_SUBD_UNUSED
;
1817 s
->type
= COMEDI_SUBD_AO
;
1818 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
;
1819 s
->n_chan
= board
->n_aochan
;
1820 s
->maxdata
= board
->ao_maxdata
;
1821 s
->len_chanlist
= board
->n_aochan
;
1822 s
->range_table
= board
->ao_range_type
;
1823 s
->insn_read
= pcl818_ao_insn_read
;
1824 s
->insn_write
= pcl818_ao_insn_write
;
1826 #ifdef PCL818_MODE13_AO
1828 s
->trig
[1] = pcl818_ao_mode1
;
1829 s
->trig
[3] = pcl818_ao_mode3
;
1833 if (board
->is_818
) {
1834 if ((it
->options
[4] == 1) || (it
->options
[4] == 10))
1835 s
->range_table
= &range_unipolar10
;
1836 if (it
->options
[4] == 2)
1837 s
->range_table
= &range_unknown
;
1839 if ((it
->options
[5] == 1) || (it
->options
[5] == 10))
1840 s
->range_table
= &range_unipolar10
;
1841 if (it
->options
[5] == 2)
1842 s
->range_table
= &range_unknown
;
1846 s
= &dev
->subdevices
[2];
1847 if (!board
->n_dichan
) {
1848 s
->type
= COMEDI_SUBD_UNUSED
;
1850 s
->type
= COMEDI_SUBD_DI
;
1851 s
->subdev_flags
= SDF_READABLE
;
1852 s
->n_chan
= board
->n_dichan
;
1854 s
->len_chanlist
= board
->n_dichan
;
1855 s
->range_table
= &range_digital
;
1856 s
->insn_bits
= pcl818_di_insn_bits
;
1859 s
= &dev
->subdevices
[3];
1860 if (!board
->n_dochan
) {
1861 s
->type
= COMEDI_SUBD_UNUSED
;
1863 s
->type
= COMEDI_SUBD_DO
;
1864 s
->subdev_flags
= SDF_WRITABLE
;
1865 s
->n_chan
= board
->n_dochan
;
1867 s
->len_chanlist
= board
->n_dochan
;
1868 s
->range_table
= &range_digital
;
1869 s
->insn_bits
= pcl818_do_insn_bits
;
1872 /* select 1/10MHz oscilator */
1873 if ((it
->options
[3] == 0) || (it
->options
[3] == 10))
1874 devpriv
->i8253_osc_base
= 100;
1876 devpriv
->i8253_osc_base
= 1000;
1878 /* max sampling speed */
1879 devpriv
->ns_min
= board
->ns_min
;
1881 if (!board
->is_818
) {
1882 if ((it
->options
[6] == 1) || (it
->options
[6] == 100))
1883 devpriv
->ns_min
= 10000; /* extended PCL718 to 100kHz DAC */
1893 static void pcl818_detach(struct comedi_device
*dev
)
1896 pcl818_ai_cancel(dev
, devpriv
->sub_ai
);
1899 free_dma(devpriv
->dma
);
1900 if (devpriv
->dmabuf
[0])
1901 free_pages(devpriv
->dmabuf
[0], devpriv
->dmapages
[0]);
1902 if (devpriv
->dmabuf
[1])
1903 free_pages(devpriv
->dmabuf
[1], devpriv
->dmapages
[1]);
1905 if (devpriv
->rtc_irq
)
1906 free_irq(devpriv
->rtc_irq
, dev
);
1907 if ((devpriv
->dma_rtc
) && (RTC_lock
== 1)) {
1908 if (devpriv
->rtc_iobase
)
1909 release_region(devpriv
->rtc_iobase
,
1910 devpriv
->rtc_iosize
);
1912 if (devpriv
->dma_rtc
)
1917 free_irq(dev
->irq
, dev
);
1919 release_region(dev
->iobase
, devpriv
->io_range
);
1922 static const struct pcl818_board boardtypes
[] = {
1923 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai
,
1924 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1925 0x0a, 0xfff, 0xfff, 0, 1},
1926 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai
,
1927 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1928 0x0a, 0xfff, 0xfff, 0, 1},
1929 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai
,
1930 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1931 0x0a, 0xfff, 0xfff, 1, 1},
1932 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai
,
1933 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1934 0x0a, 0xfff, 0xfff, 1, 1},
1935 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai
,
1936 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1937 0x0a, 0xfff, 0xfff, 0, 1},
1938 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5
,
1939 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1940 0x0a, 0xfff, 0xfff, 0, 0},
1942 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai
,
1943 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1944 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
1947 static struct comedi_driver pcl818_driver
= {
1948 .driver_name
= "pcl818",
1949 .module
= THIS_MODULE
,
1950 .attach
= pcl818_attach
,
1951 .detach
= pcl818_detach
,
1952 .board_name
= &boardtypes
[0].name
,
1953 .num_names
= ARRAY_SIZE(boardtypes
),
1954 .offset
= sizeof(struct pcl818_board
),
1956 module_comedi_driver(pcl818_driver
);
1958 MODULE_AUTHOR("Comedi http://www.comedi.org");
1959 MODULE_DESCRIPTION("Comedi low-level driver");
1960 MODULE_LICENSE("GPL");