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
330 ==============================================================================
332 static void setup_channel_list(struct comedi_device
*dev
,
333 struct comedi_subdevice
*s
,
334 unsigned int *chanlist
, unsigned int n_chan
,
335 unsigned int seglen
);
336 static int check_channel_list(struct comedi_device
*dev
,
337 struct comedi_subdevice
*s
,
338 unsigned int *chanlist
, unsigned int n_chan
);
340 static int pcl818_ai_cancel(struct comedi_device
*dev
,
341 struct comedi_subdevice
*s
);
342 static void start_pacer(struct comedi_device
*dev
, int mode
,
343 unsigned int divisor1
, unsigned int divisor2
);
346 static int set_rtc_irq_bit(unsigned char bit
);
347 static void rtc_dropped_irq(unsigned long data
);
348 static int rtc_setfreq_irq(int freq
);
352 ==============================================================================
353 ANALOG INPUT MODE0, 818 cards, slow version
355 static int pcl818_ai_insn_read(struct comedi_device
*dev
,
356 struct comedi_subdevice
*s
,
357 struct comedi_insn
*insn
, unsigned int *data
)
362 /* software trigger, DMA and INT off */
363 outb(0, dev
->iobase
+ PCL818_CONTROL
);
366 outb(muxonechan
[CR_CHAN(insn
->chanspec
)], dev
->iobase
+ PCL818_MUX
);
369 outb(CR_RANGE(insn
->chanspec
), dev
->iobase
+ PCL818_RANGE
);
371 for (n
= 0; n
< insn
->n
; n
++) {
373 /* clear INT (conversion end) flag */
374 outb(0, dev
->iobase
+ PCL818_CLRINT
);
376 /* start conversion */
377 outb(0, dev
->iobase
+ PCL818_AD_LO
);
381 if (inb(dev
->iobase
+ PCL818_STATUS
) & 0x10)
385 comedi_error(dev
, "A/D insn timeout");
386 /* clear INT (conversion end) flag */
387 outb(0, dev
->iobase
+ PCL818_CLRINT
);
391 data
[n
] = ((inb(dev
->iobase
+ PCL818_AD_HI
) << 4) |
392 (inb(dev
->iobase
+ PCL818_AD_LO
) >> 4));
399 ==============================================================================
400 ANALOG OUTPUT MODE0, 818 cards
401 only one sample per call is supported
403 static int pcl818_ao_insn_read(struct comedi_device
*dev
,
404 struct comedi_subdevice
*s
,
405 struct comedi_insn
*insn
, unsigned int *data
)
407 struct pcl818_private
*devpriv
= dev
->private;
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
)
421 struct pcl818_private
*devpriv
= dev
->private;
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 pcl818_private
*devpriv
= dev
->private;
482 struct comedi_subdevice
*s
= &dev
->subdevices
[0];
484 int timeout
= 50; /* wait max 50us */
487 if (inb(dev
->iobase
+ PCL818_STATUS
) & 0x10)
491 outb(0, dev
->iobase
+ PCL818_STATUS
); /* clear INT request */
492 comedi_error(dev
, "A/D mode1/3 IRQ without DRDY!");
493 pcl818_ai_cancel(dev
, s
);
494 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
495 comedi_event(dev
, s
);
499 low
= inb(dev
->iobase
+ PCL818_AD_LO
);
500 comedi_buf_put(s
->async
, ((inb(dev
->iobase
+ PCL818_AD_HI
) << 4) | (low
>> 4))); /* get one sample */
501 outb(0, dev
->iobase
+ PCL818_CLRINT
); /* clear INT request */
503 if ((low
& 0xf) != devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]) { /* dropout! */
505 ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
507 devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]);
508 pcl818_ai_cancel(dev
, s
);
509 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
510 comedi_event(dev
, s
);
513 devpriv
->act_chanlist_pos
++;
514 if (devpriv
->act_chanlist_pos
>= devpriv
->act_chanlist_len
)
515 devpriv
->act_chanlist_pos
= 0;
517 s
->async
->cur_chan
++;
518 if (s
->async
->cur_chan
>= devpriv
->ai_n_chan
) {
520 s
->async
->cur_chan
= 0;
521 devpriv
->ai_act_scan
--;
524 if (!devpriv
->neverending_ai
) {
525 if (devpriv
->ai_act_scan
== 0) { /* all data sampled */
526 pcl818_ai_cancel(dev
, s
);
527 s
->async
->events
|= COMEDI_CB_EOA
;
530 comedi_event(dev
, s
);
535 ==============================================================================
536 analog input dma mode 1 & 3, 818 cards
538 static irqreturn_t
interrupt_pcl818_ai_mode13_dma(int irq
, void *d
)
540 struct comedi_device
*dev
= d
;
541 struct pcl818_private
*devpriv
= dev
->private;
542 struct comedi_subdevice
*s
= &dev
->subdevices
[0];
547 disable_dma(devpriv
->dma
);
548 devpriv
->next_dma_buf
= 1 - devpriv
->next_dma_buf
;
549 if ((devpriv
->dma_runs_to_end
) > -1 || devpriv
->neverending_ai
) { /* switch dma bufs */
550 set_dma_mode(devpriv
->dma
, DMA_MODE_READ
);
551 flags
= claim_dma_lock();
552 set_dma_addr(devpriv
->dma
,
553 devpriv
->hwdmaptr
[devpriv
->next_dma_buf
]);
554 if (devpriv
->dma_runs_to_end
|| devpriv
->neverending_ai
) {
555 set_dma_count(devpriv
->dma
,
556 devpriv
->hwdmasize
[devpriv
->
559 set_dma_count(devpriv
->dma
, devpriv
->last_dma_run
);
561 release_dma_lock(flags
);
562 enable_dma(devpriv
->dma
);
564 printk("comedi: A/D mode1/3 IRQ \n");
566 devpriv
->dma_runs_to_end
--;
567 outb(0, dev
->iobase
+ PCL818_CLRINT
); /* clear INT request */
568 ptr
= (short *)devpriv
->dmabuf
[1 - devpriv
->next_dma_buf
];
570 len
= devpriv
->hwdmasize
[0] >> 1;
573 for (i
= 0; i
< len
; i
++) {
574 if ((ptr
[bufptr
] & 0xf) != devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]) { /* dropout! */
576 ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
578 devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
],
579 devpriv
->act_chanlist_pos
);
580 pcl818_ai_cancel(dev
, s
);
581 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
582 comedi_event(dev
, s
);
586 comedi_buf_put(s
->async
, ptr
[bufptr
++] >> 4); /* get one sample */
588 devpriv
->act_chanlist_pos
++;
589 if (devpriv
->act_chanlist_pos
>= devpriv
->act_chanlist_len
)
590 devpriv
->act_chanlist_pos
= 0;
592 s
->async
->cur_chan
++;
593 if (s
->async
->cur_chan
>= devpriv
->ai_n_chan
) {
594 s
->async
->cur_chan
= 0;
595 devpriv
->ai_act_scan
--;
598 if (!devpriv
->neverending_ai
)
599 if (devpriv
->ai_act_scan
== 0) { /* all data sampled */
600 pcl818_ai_cancel(dev
, s
);
601 s
->async
->events
|= COMEDI_CB_EOA
;
602 comedi_event(dev
, s
);
603 /* printk("done int ai13 dma\n"); */
609 comedi_event(dev
, s
);
615 ==============================================================================
616 analog input dma mode 1 & 3 over RTC, 818 cards
618 static irqreturn_t
interrupt_pcl818_ai_mode13_dma_rtc(int irq
, void *d
)
620 struct comedi_device
*dev
= d
;
621 struct pcl818_private
*devpriv
= dev
->private;
622 struct comedi_subdevice
*s
= &dev
->subdevices
[0];
624 unsigned int top1
, top2
, i
, bufptr
;
626 short *dmabuf
= (short *)devpriv
->dmabuf
[0];
629 switch (devpriv
->ai_mode
) {
630 case INT_TYPE_AI1_DMA_RTC
:
631 case INT_TYPE_AI3_DMA_RTC
:
632 tmp
= (CMOS_READ(RTC_INTR_FLAGS
) & 0xF0);
633 mod_timer(&devpriv
->rtc_irq_timer
,
634 jiffies
+ HZ
/ devpriv
->rtc_freq
+ 2 * HZ
/ 100);
636 for (i
= 0; i
< 10; i
++) {
637 top1
= get_dma_residue(devpriv
->dma
);
638 top2
= get_dma_residue(devpriv
->dma
);
645 top1
= devpriv
->hwdmasize
[0] - top1
; /* where is now DMA in buffer */
647 ofs_dats
= top1
- devpriv
->last_top_dma
; /* new samples from last call */
649 ofs_dats
= (devpriv
->dmasamplsize
) + ofs_dats
;
651 return IRQ_HANDLED
; /* exit=no new samples from last call */
653 i
= devpriv
->last_top_dma
- 1;
654 i
&= (devpriv
->dmasamplsize
- 1);
656 if (dmabuf
[i
] != MAGIC_DMA_WORD
) { /* DMA overflow! */
657 comedi_error(dev
, "A/D mode1/3 DMA buffer overflow!");
658 /* printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize); */
659 pcl818_ai_cancel(dev
, s
);
660 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
661 comedi_event(dev
, s
);
664 /* printk("r %ld ",ofs_dats); */
666 bufptr
= devpriv
->last_top_dma
;
668 for (i
= 0; i
< ofs_dats
; i
++) {
669 if ((dmabuf
[bufptr
] & 0xf) != devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]) { /* dropout! */
671 ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",
672 (dmabuf
[bufptr
] & 0xf),
674 act_chanlist
[devpriv
->act_chanlist_pos
]);
675 pcl818_ai_cancel(dev
, s
);
677 COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
678 comedi_event(dev
, s
);
682 comedi_buf_put(s
->async
, dmabuf
[bufptr
++] >> 4); /* get one sample */
683 bufptr
&= (devpriv
->dmasamplsize
- 1);
685 devpriv
->act_chanlist_pos
++;
686 if (devpriv
->act_chanlist_pos
>=
687 devpriv
->act_chanlist_len
) {
688 devpriv
->act_chanlist_pos
= 0;
690 s
->async
->cur_chan
++;
691 if (s
->async
->cur_chan
>= devpriv
->ai_n_chan
) {
692 s
->async
->cur_chan
= 0;
693 devpriv
->ai_act_scan
--;
696 if (!devpriv
->neverending_ai
)
697 if (devpriv
->ai_act_scan
== 0) { /* all data sampled */
698 pcl818_ai_cancel(dev
, s
);
699 s
->async
->events
|= COMEDI_CB_EOA
;
700 comedi_event(dev
, s
);
701 /* printk("done int ai13 dma\n"); */
706 devpriv
->last_top_dma
= bufptr
;
708 bufptr
&= (devpriv
->dmasamplsize
- 1);
709 dmabuf
[bufptr
] = MAGIC_DMA_WORD
;
710 comedi_event(dev
, s
);
721 ==============================================================================
722 analog input interrupt mode 1 & 3, 818HD/HG cards
724 static irqreturn_t
interrupt_pcl818_ai_mode13_fifo(int irq
, void *d
)
726 struct comedi_device
*dev
= d
;
727 struct pcl818_private
*devpriv
= dev
->private;
728 struct comedi_subdevice
*s
= &dev
->subdevices
[0];
731 outb(0, dev
->iobase
+ PCL818_FI_INTCLR
); /* clear fifo int request */
733 lo
= inb(dev
->iobase
+ PCL818_FI_STATUS
);
736 comedi_error(dev
, "A/D mode1/3 FIFO overflow!");
737 pcl818_ai_cancel(dev
, s
);
738 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
739 comedi_event(dev
, s
);
744 comedi_error(dev
, "A/D mode1/3 FIFO interrupt without data!");
745 pcl818_ai_cancel(dev
, s
);
746 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
747 comedi_event(dev
, s
);
756 for (i
= 0; i
< len
; i
++) {
757 lo
= inb(dev
->iobase
+ PCL818_FI_DATALO
);
758 if ((lo
& 0xf) != devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]) { /* dropout! */
760 ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
762 devpriv
->act_chanlist
[devpriv
->act_chanlist_pos
]);
763 pcl818_ai_cancel(dev
, s
);
764 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
765 comedi_event(dev
, s
);
769 comedi_buf_put(s
->async
, (lo
>> 4) | (inb(dev
->iobase
+ PCL818_FI_DATAHI
) << 4)); /* get one sample */
771 devpriv
->act_chanlist_pos
++;
772 if (devpriv
->act_chanlist_pos
>= devpriv
->act_chanlist_len
)
773 devpriv
->act_chanlist_pos
= 0;
775 s
->async
->cur_chan
++;
776 if (s
->async
->cur_chan
>= devpriv
->ai_n_chan
) {
777 s
->async
->cur_chan
= 0;
778 devpriv
->ai_act_scan
--;
781 if (!devpriv
->neverending_ai
)
782 if (devpriv
->ai_act_scan
== 0) { /* all data sampled */
783 pcl818_ai_cancel(dev
, s
);
784 s
->async
->events
|= COMEDI_CB_EOA
;
785 comedi_event(dev
, s
);
791 comedi_event(dev
, s
);
796 ==============================================================================
799 static irqreturn_t
interrupt_pcl818(int irq
, void *d
)
801 struct comedi_device
*dev
= d
;
802 struct pcl818_private
*devpriv
= dev
->private;
804 if (!dev
->attached
) {
805 comedi_error(dev
, "premature interrupt");
810 if (devpriv
->irq_blocked
&& devpriv
->irq_was_now_closed
) {
811 if ((devpriv
->neverending_ai
|| (!devpriv
->neverending_ai
&&
812 devpriv
->ai_act_scan
> 0)) &&
813 (devpriv
->ai_mode
== INT_TYPE_AI1_DMA
||
814 devpriv
->ai_mode
== INT_TYPE_AI3_DMA
)) {
815 /* The cleanup from ai_cancel() has been delayed
816 until now because the card doesn't seem to like
817 being reprogrammed while a DMA transfer is in
820 struct comedi_subdevice
*s
= &dev
->subdevices
[0];
821 devpriv
->ai_act_scan
= 0;
822 devpriv
->neverending_ai
= 0;
823 pcl818_ai_cancel(dev
, s
);
826 outb(0, dev
->iobase
+ PCL818_CLRINT
); /* clear INT request */
831 switch (devpriv
->ai_mode
) {
832 case INT_TYPE_AI1_DMA
:
833 case INT_TYPE_AI3_DMA
:
834 return interrupt_pcl818_ai_mode13_dma(irq
, d
);
835 case INT_TYPE_AI1_INT
:
836 case INT_TYPE_AI3_INT
:
837 return interrupt_pcl818_ai_mode13_int(irq
, d
);
838 case INT_TYPE_AI1_FIFO
:
839 case INT_TYPE_AI3_FIFO
:
840 return interrupt_pcl818_ai_mode13_fifo(irq
, d
);
841 #ifdef PCL818_MODE13_AO
842 case INT_TYPE_AO1_INT
:
843 case INT_TYPE_AO3_INT
:
844 return interrupt_pcl818_ao_mode13_int(irq
, d
);
850 outb(0, dev
->iobase
+ PCL818_CLRINT
); /* clear INT request */
852 if ((!dev
->irq
) || (!devpriv
->irq_free
) || (!devpriv
->irq_blocked
)
853 || (!devpriv
->ai_mode
)) {
854 comedi_error(dev
, "bad IRQ!");
858 comedi_error(dev
, "IRQ from unknown source!");
863 ==============================================================================
864 ANALOG INPUT MODE 1 or 3 DMA , 818 cards
866 static void pcl818_ai_mode13dma_int(int mode
, struct comedi_device
*dev
,
867 struct comedi_subdevice
*s
)
869 struct pcl818_private
*devpriv
= dev
->private;
873 printk("mode13dma_int, mode: %d\n", mode
);
874 disable_dma(devpriv
->dma
); /* disable dma */
875 bytes
= devpriv
->hwdmasize
[0];
876 if (!devpriv
->neverending_ai
) {
877 bytes
= devpriv
->ai_n_chan
* devpriv
->ai_scans
* sizeof(short); /* how many */
878 devpriv
->dma_runs_to_end
= bytes
/ devpriv
->hwdmasize
[0]; /* how many DMA pages we must fiil */
879 devpriv
->last_dma_run
= bytes
% devpriv
->hwdmasize
[0]; /* on last dma transfer must be moved */
880 devpriv
->dma_runs_to_end
--;
881 if (devpriv
->dma_runs_to_end
>= 0)
882 bytes
= devpriv
->hwdmasize
[0];
885 devpriv
->next_dma_buf
= 0;
886 set_dma_mode(devpriv
->dma
, DMA_MODE_READ
);
887 flags
= claim_dma_lock();
888 clear_dma_ff(devpriv
->dma
);
889 set_dma_addr(devpriv
->dma
, devpriv
->hwdmaptr
[0]);
890 set_dma_count(devpriv
->dma
, bytes
);
891 release_dma_lock(flags
);
892 enable_dma(devpriv
->dma
);
895 devpriv
->ai_mode
= INT_TYPE_AI1_DMA
;
896 outb(0x87 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Pacer+IRQ+DMA */
898 devpriv
->ai_mode
= INT_TYPE_AI3_DMA
;
899 outb(0x86 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Ext trig+IRQ+DMA */
905 ==============================================================================
906 ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards
908 static void pcl818_ai_mode13dma_rtc(int mode
, struct comedi_device
*dev
,
909 struct comedi_subdevice
*s
)
911 struct pcl818_private
*devpriv
= dev
->private;
915 set_dma_mode(devpriv
->dma
, DMA_MODE_READ
| DMA_AUTOINIT
);
916 flags
= claim_dma_lock();
917 clear_dma_ff(devpriv
->dma
);
918 set_dma_addr(devpriv
->dma
, devpriv
->hwdmaptr
[0]);
919 set_dma_count(devpriv
->dma
, devpriv
->hwdmasize
[0]);
920 release_dma_lock(flags
);
921 enable_dma(devpriv
->dma
);
922 devpriv
->last_top_dma
= 0; /* devpriv->hwdmasize[0]; */
923 pole
= (short *)devpriv
->dmabuf
[0];
924 devpriv
->dmasamplsize
= devpriv
->hwdmasize
[0] / 2;
925 pole
[devpriv
->dmasamplsize
- 1] = MAGIC_DMA_WORD
;
927 devpriv
->rtc_freq
= rtc_setfreq_irq(2048);
928 devpriv
->rtc_irq_timer
.expires
=
929 jiffies
+ HZ
/ devpriv
->rtc_freq
+ 2 * HZ
/ 100;
930 devpriv
->rtc_irq_timer
.data
= (unsigned long)dev
;
931 devpriv
->rtc_irq_timer
.function
= rtc_dropped_irq
;
933 add_timer(&devpriv
->rtc_irq_timer
);
937 devpriv
->int818_mode
= INT_TYPE_AI1_DMA_RTC
;
938 outb(0x07 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Pacer+DMA */
940 devpriv
->int818_mode
= INT_TYPE_AI3_DMA_RTC
;
941 outb(0x06 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Ext trig+DMA */
947 ==============================================================================
948 ANALOG INPUT MODE 1 or 3, 818 cards
950 static int pcl818_ai_cmd_mode(int mode
, struct comedi_device
*dev
,
951 struct comedi_subdevice
*s
)
953 struct pcl818_private
*devpriv
= dev
->private;
954 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
955 int divisor1
= 0, divisor2
= 0;
958 dev_dbg(dev
->class_dev
, "pcl818_ai_cmd_mode()\n");
959 if ((!dev
->irq
) && (!devpriv
->dma_rtc
)) {
960 comedi_error(dev
, "IRQ not defined!");
964 if (devpriv
->irq_blocked
)
967 start_pacer(dev
, -1, 0, 0); /* stop pacer */
969 seglen
= check_channel_list(dev
, s
, devpriv
->ai_chanlist
,
973 setup_channel_list(dev
, s
, devpriv
->ai_chanlist
,
974 devpriv
->ai_n_chan
, seglen
);
978 devpriv
->ai_act_scan
= devpriv
->ai_scans
;
979 devpriv
->ai_act_chan
= 0;
980 devpriv
->irq_blocked
= 1;
981 devpriv
->irq_was_now_closed
= 0;
982 devpriv
->neverending_ai
= 0;
983 devpriv
->act_chanlist_pos
= 0;
984 devpriv
->dma_runs_to_end
= 0;
986 if ((devpriv
->ai_scans
== 0) || (devpriv
->ai_scans
== -1))
987 devpriv
->neverending_ai
= 1; /* well, user want neverending */
990 i8253_cascade_ns_to_timer(devpriv
->i8253_osc_base
, &divisor1
,
991 &divisor2
, &cmd
->convert_arg
,
993 if (divisor1
== 1) { /* PCL718/818 crash if any divisor is set to 1 */
1003 outb(0, dev
->iobase
+ PCL818_CNTENABLE
); /* enable pacer */
1005 switch (devpriv
->dma
) {
1008 if (devpriv
->dma_rtc
== 0) {
1009 pcl818_ai_mode13dma_int(mode
, dev
, s
);
1013 pcl818_ai_mode13dma_rtc(mode
, dev
, s
);
1022 if (!devpriv
->usefifo
) {
1024 /* printk("IRQ\n"); */
1026 devpriv
->ai_mode
= INT_TYPE_AI1_INT
;
1028 outb(0x83 | (dev
->irq
<< 4),
1029 dev
->iobase
+ PCL818_CONTROL
);
1031 devpriv
->ai_mode
= INT_TYPE_AI3_INT
;
1033 outb(0x82 | (dev
->irq
<< 4),
1034 dev
->iobase
+ PCL818_CONTROL
);
1039 outb(1, dev
->iobase
+ PCL818_FI_ENABLE
);
1041 devpriv
->ai_mode
= INT_TYPE_AI1_FIFO
;
1043 outb(0x03, dev
->iobase
+ PCL818_CONTROL
);
1045 devpriv
->ai_mode
= INT_TYPE_AI3_FIFO
;
1046 outb(0x02, dev
->iobase
+ PCL818_CONTROL
);
1051 start_pacer(dev
, mode
, divisor1
, divisor2
);
1054 switch (devpriv
->ai_mode
) {
1055 case INT_TYPE_AI1_DMA_RTC
:
1056 case INT_TYPE_AI3_DMA_RTC
:
1057 set_rtc_irq_bit(1); /* start RTC */
1061 dev_dbg(dev
->class_dev
, "pcl818_ai_cmd_mode() end\n");
1067 ==============================================================================
1068 ANALOG OUTPUT MODE 1 or 3, 818 cards
1070 #ifdef PCL818_MODE13_AO
1071 static int pcl818_ao_mode13(int mode
, struct comedi_device
*dev
,
1072 struct comedi_subdevice
*s
, comedi_trig
* it
)
1074 struct pcl818_private
*devpriv
= dev
->private;
1075 int divisor1
= 0, divisor2
= 0;
1078 comedi_error(dev
, "IRQ not defined!");
1082 if (devpriv
->irq_blocked
)
1085 start_pacer(dev
, -1, 0, 0); /* stop pacer */
1087 devpriv
->int13_act_scan
= it
->n
;
1088 devpriv
->int13_act_chan
= 0;
1089 devpriv
->irq_blocked
= 1;
1090 devpriv
->irq_was_now_closed
= 0;
1091 devpriv
->neverending_ai
= 0;
1092 devpriv
->act_chanlist_pos
= 0;
1095 i8253_cascade_ns_to_timer(devpriv
->i8253_osc_base
, &divisor1
,
1096 &divisor2
, &it
->trigvar
,
1097 TRIG_ROUND_NEAREST
);
1098 if (divisor1
== 1) { /* PCL818 crash if any divisor is set to 1 */
1102 if (divisor2
== 1) {
1108 outb(0, dev
->iobase
+ PCL818_CNTENABLE
); /* enable pacer */
1110 devpriv
->int818_mode
= INT_TYPE_AO1_INT
;
1111 outb(0x83 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Pacer+IRQ */
1113 devpriv
->int818_mode
= INT_TYPE_AO3_INT
;
1114 outb(0x82 | (dev
->irq
<< 4), dev
->iobase
+ PCL818_CONTROL
); /* Ext trig+IRQ */
1117 start_pacer(dev
, mode
, divisor1
, divisor2
);
1123 ==============================================================================
1124 ANALOG OUTPUT MODE 1, 818 cards
1126 static int pcl818_ao_mode1(struct comedi_device
*dev
,
1127 struct comedi_subdevice
*s
, comedi_trig
* it
)
1129 return pcl818_ao_mode13(1, dev
, s
, it
);
1133 ==============================================================================
1134 ANALOG OUTPUT MODE 3, 818 cards
1136 static int pcl818_ao_mode3(struct comedi_device
*dev
,
1137 struct comedi_subdevice
*s
, comedi_trig
* it
)
1139 return pcl818_ao_mode13(3, dev
, s
, it
);
1145 ==============================================================================
1146 Start/stop pacer onboard pacer
1148 static void start_pacer(struct comedi_device
*dev
, int mode
,
1149 unsigned int divisor1
, unsigned int divisor2
)
1151 outb(0xb4, dev
->iobase
+ PCL818_CTRCTL
);
1152 outb(0x74, dev
->iobase
+ PCL818_CTRCTL
);
1156 outb(divisor2
& 0xff, dev
->iobase
+ PCL818_CTR2
);
1157 outb((divisor2
>> 8) & 0xff, dev
->iobase
+ PCL818_CTR2
);
1158 outb(divisor1
& 0xff, dev
->iobase
+ PCL818_CTR1
);
1159 outb((divisor1
>> 8) & 0xff, dev
->iobase
+ PCL818_CTR1
);
1164 ==============================================================================
1165 Check if channel list from user is builded correctly
1166 If it's ok, then program scan/gain logic
1168 static int check_channel_list(struct comedi_device
*dev
,
1169 struct comedi_subdevice
*s
,
1170 unsigned int *chanlist
, unsigned int n_chan
)
1172 unsigned int chansegment
[16];
1173 unsigned int i
, nowmustbechan
, seglen
, segpos
;
1175 /* correct channel and range number check itself comedi/range.c */
1177 comedi_error(dev
, "range/channel list is empty!");
1182 /* first channel is every time ok */
1183 chansegment
[0] = chanlist
[0];
1184 /* build part of chanlist */
1185 for (i
= 1, seglen
= 1; i
< n_chan
; i
++, seglen
++) {
1187 /* printk("%d. %d * %d\n",i,
1188 * CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));*/
1190 /* we detect loop, this must by finish */
1192 if (chanlist
[0] == chanlist
[i
])
1195 (CR_CHAN(chansegment
[i
- 1]) + 1) % s
->n_chan
;
1196 if (nowmustbechan
!= CR_CHAN(chanlist
[i
])) { /* channel list isn't continuous :-( */
1198 ("comedi%d: pcl818: channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
1199 dev
->minor
, i
, CR_CHAN(chanlist
[i
]),
1200 nowmustbechan
, CR_CHAN(chanlist
[0]));
1203 /* well, this is next correct channel in list */
1204 chansegment
[i
] = chanlist
[i
];
1207 /* check whole chanlist */
1208 for (i
= 0, segpos
= 0; i
< n_chan
; i
++) {
1209 /* 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])); */
1210 if (chanlist
[i
] != chansegment
[i
% seglen
]) {
1212 ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1213 dev
->minor
, i
, CR_CHAN(chansegment
[i
]),
1214 CR_RANGE(chansegment
[i
]),
1215 CR_AREF(chansegment
[i
]),
1216 CR_CHAN(chanlist
[i
% seglen
]),
1217 CR_RANGE(chanlist
[i
% seglen
]),
1218 CR_AREF(chansegment
[i
% seglen
]));
1219 return 0; /* chan/gain list is strange */
1225 printk("check_channel_list: seglen %d\n", seglen
);
1229 static void setup_channel_list(struct comedi_device
*dev
,
1230 struct comedi_subdevice
*s
,
1231 unsigned int *chanlist
, unsigned int n_chan
,
1232 unsigned int seglen
)
1234 struct pcl818_private
*devpriv
= dev
->private;
1237 devpriv
->act_chanlist_len
= seglen
;
1238 devpriv
->act_chanlist_pos
= 0;
1240 for (i
= 0; i
< seglen
; i
++) { /* store range list to card */
1241 devpriv
->act_chanlist
[i
] = CR_CHAN(chanlist
[i
]);
1242 outb(muxonechan
[CR_CHAN(chanlist
[i
])], dev
->iobase
+ PCL818_MUX
); /* select channel */
1243 outb(CR_RANGE(chanlist
[i
]), dev
->iobase
+ PCL818_RANGE
); /* select gain */
1248 /* select channel interval to scan */
1249 outb(devpriv
->act_chanlist
[0] | (devpriv
->act_chanlist
[seglen
-
1251 dev
->iobase
+ PCL818_MUX
);
1255 ==============================================================================
1256 Check if board is switched to SE (1) or DIFF(0) mode
1258 static int check_single_ended(unsigned int port
)
1260 if (inb(port
+ PCL818_STATUS
) & 0x20)
1266 ==============================================================================
1268 static int ai_cmdtest(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
1269 struct comedi_cmd
*cmd
)
1271 const struct pcl818_board
*board
= comedi_board(dev
);
1272 struct pcl818_private
*devpriv
= dev
->private;
1274 int tmp
, divisor1
= 0, divisor2
= 0;
1276 /* Step 1 : check if triggers are trivially valid */
1278 err
|= cfc_check_trigger_src(&cmd
->start_src
, TRIG_NOW
);
1279 err
|= cfc_check_trigger_src(&cmd
->scan_begin_src
, TRIG_FOLLOW
);
1280 err
|= cfc_check_trigger_src(&cmd
->convert_src
, TRIG_TIMER
| TRIG_EXT
);
1281 err
|= cfc_check_trigger_src(&cmd
->scan_end_src
, TRIG_COUNT
);
1282 err
|= cfc_check_trigger_src(&cmd
->stop_src
, TRIG_COUNT
| TRIG_NONE
);
1287 /* Step 2a : make sure trigger sources are unique */
1289 err
|= cfc_check_trigger_is_unique(cmd
->convert_src
);
1290 err
|= cfc_check_trigger_is_unique(cmd
->stop_src
);
1292 /* Step 2b : and mutually compatible */
1297 /* step 3: make sure arguments are trivially compatible */
1299 if (cmd
->start_arg
!= 0) {
1304 if (cmd
->scan_begin_arg
!= 0) {
1305 cmd
->scan_begin_arg
= 0;
1309 if (cmd
->convert_src
== TRIG_TIMER
) {
1310 if (cmd
->convert_arg
< board
->ns_min
) {
1311 cmd
->convert_arg
= board
->ns_min
;
1314 } else { /* TRIG_EXT */
1315 if (cmd
->convert_arg
!= 0) {
1316 cmd
->convert_arg
= 0;
1321 if (cmd
->scan_end_arg
!= cmd
->chanlist_len
) {
1322 cmd
->scan_end_arg
= cmd
->chanlist_len
;
1325 if (cmd
->stop_src
== TRIG_COUNT
) {
1326 if (!cmd
->stop_arg
) {
1330 } else { /* TRIG_NONE */
1331 if (cmd
->stop_arg
!= 0) {
1340 /* step 4: fix up any arguments */
1342 if (cmd
->convert_src
== TRIG_TIMER
) {
1343 tmp
= cmd
->convert_arg
;
1344 i8253_cascade_ns_to_timer(devpriv
->i8253_osc_base
, &divisor1
,
1345 &divisor2
, &cmd
->convert_arg
,
1346 cmd
->flags
& TRIG_ROUND_MASK
);
1347 if (cmd
->convert_arg
< board
->ns_min
)
1348 cmd
->convert_arg
= board
->ns_min
;
1349 if (tmp
!= cmd
->convert_arg
)
1356 /* step 5: complain about special chanlist considerations */
1358 if (cmd
->chanlist
) {
1359 if (!check_channel_list(dev
, s
, cmd
->chanlist
,
1361 return 5; /* incorrect channels list */
1368 ==============================================================================
1370 static int ai_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
1372 struct pcl818_private
*devpriv
= dev
->private;
1373 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
1376 dev_dbg(dev
->class_dev
, "pcl818_ai_cmd()\n");
1377 devpriv
->ai_n_chan
= cmd
->chanlist_len
;
1378 devpriv
->ai_chanlist
= cmd
->chanlist
;
1379 devpriv
->ai_flags
= cmd
->flags
;
1380 devpriv
->ai_data_len
= s
->async
->prealloc_bufsz
;
1381 devpriv
->ai_data
= s
->async
->prealloc_buf
;
1382 devpriv
->ai_timer1
= 0;
1383 devpriv
->ai_timer2
= 0;
1385 if (cmd
->stop_src
== TRIG_COUNT
)
1386 devpriv
->ai_scans
= cmd
->stop_arg
;
1388 devpriv
->ai_scans
= 0;
1390 if (cmd
->scan_begin_src
== TRIG_FOLLOW
) { /* mode 1, 3 */
1391 if (cmd
->convert_src
== TRIG_TIMER
) { /* mode 1 */
1392 devpriv
->ai_timer1
= cmd
->convert_arg
;
1393 retval
= pcl818_ai_cmd_mode(1, dev
, s
);
1394 dev_dbg(dev
->class_dev
, "pcl818_ai_cmd() end\n");
1397 if (cmd
->convert_src
== TRIG_EXT
) { /* mode 3 */
1398 return pcl818_ai_cmd_mode(3, dev
, s
);
1406 ==============================================================================
1407 cancel any mode 1-4 AI
1409 static int pcl818_ai_cancel(struct comedi_device
*dev
,
1410 struct comedi_subdevice
*s
)
1412 struct pcl818_private
*devpriv
= dev
->private;
1414 if (devpriv
->irq_blocked
> 0) {
1415 dev_dbg(dev
->class_dev
, "pcl818_ai_cancel()\n");
1416 devpriv
->irq_was_now_closed
= 1;
1418 switch (devpriv
->ai_mode
) {
1420 case INT_TYPE_AI1_DMA_RTC
:
1421 case INT_TYPE_AI3_DMA_RTC
:
1422 set_rtc_irq_bit(0); /* stop RTC */
1423 del_timer(&devpriv
->rtc_irq_timer
);
1425 case INT_TYPE_AI1_DMA
:
1426 case INT_TYPE_AI3_DMA
:
1427 if (devpriv
->neverending_ai
||
1428 (!devpriv
->neverending_ai
&&
1429 devpriv
->ai_act_scan
> 0)) {
1430 /* wait for running dma transfer to end, do cleanup in interrupt */
1433 disable_dma(devpriv
->dma
);
1434 case INT_TYPE_AI1_INT
:
1435 case INT_TYPE_AI3_INT
:
1436 case INT_TYPE_AI1_FIFO
:
1437 case INT_TYPE_AI3_FIFO
:
1438 #ifdef PCL818_MODE13_AO
1439 case INT_TYPE_AO1_INT
:
1440 case INT_TYPE_AO3_INT
:
1442 outb(inb(dev
->iobase
+ PCL818_CONTROL
) & 0x73, dev
->iobase
+ PCL818_CONTROL
); /* Stop A/D */
1444 start_pacer(dev
, -1, 0, 0);
1445 outb(0, dev
->iobase
+ PCL818_AD_LO
);
1446 inb(dev
->iobase
+ PCL818_AD_LO
);
1447 inb(dev
->iobase
+ PCL818_AD_HI
);
1448 outb(0, dev
->iobase
+ PCL818_CLRINT
); /* clear INT request */
1449 outb(0, dev
->iobase
+ PCL818_CONTROL
); /* Stop A/D */
1450 if (devpriv
->usefifo
) { /* FIFO shutdown */
1451 outb(0, dev
->iobase
+ PCL818_FI_INTCLR
);
1452 outb(0, dev
->iobase
+ PCL818_FI_FLUSH
);
1453 outb(0, dev
->iobase
+ PCL818_FI_ENABLE
);
1455 devpriv
->irq_blocked
= 0;
1456 devpriv
->last_int_sub
= s
;
1457 devpriv
->neverending_ai
= 0;
1458 devpriv
->ai_mode
= 0;
1459 devpriv
->irq_was_now_closed
= 0;
1465 dev_dbg(dev
->class_dev
, "pcl818_ai_cancel() end\n");
1470 ==============================================================================
1473 static int pcl818_check(unsigned long iobase
)
1475 outb(0x00, iobase
+ PCL818_MUX
);
1477 if (inb(iobase
+ PCL818_MUX
) != 0x00)
1478 return 1; /* there isn't card */
1479 outb(0x55, iobase
+ PCL818_MUX
);
1481 if (inb(iobase
+ PCL818_MUX
) != 0x55)
1482 return 1; /* there isn't card */
1483 outb(0x00, iobase
+ PCL818_MUX
);
1485 outb(0x18, iobase
+ PCL818_CONTROL
);
1487 if (inb(iobase
+ PCL818_CONTROL
) != 0x18)
1488 return 1; /* there isn't card */
1489 return 0; /* ok, card exist */
1493 ==============================================================================
1494 reset whole PCL-818 cards
1496 static void pcl818_reset(struct comedi_device
*dev
)
1498 const struct pcl818_board
*board
= comedi_board(dev
);
1499 struct pcl818_private
*devpriv
= dev
->private;
1501 if (devpriv
->usefifo
) { /* FIFO shutdown */
1502 outb(0, dev
->iobase
+ PCL818_FI_INTCLR
);
1503 outb(0, dev
->iobase
+ PCL818_FI_FLUSH
);
1504 outb(0, dev
->iobase
+ PCL818_FI_ENABLE
);
1506 outb(0, dev
->iobase
+ PCL818_DA_LO
); /* DAC=0V */
1507 outb(0, dev
->iobase
+ PCL818_DA_HI
);
1509 outb(0, dev
->iobase
+ PCL818_DO_HI
); /* DO=$0000 */
1510 outb(0, dev
->iobase
+ PCL818_DO_LO
);
1512 outb(0, dev
->iobase
+ PCL818_CONTROL
);
1513 outb(0, dev
->iobase
+ PCL818_CNTENABLE
);
1514 outb(0, dev
->iobase
+ PCL818_MUX
);
1515 outb(0, dev
->iobase
+ PCL818_CLRINT
);
1516 outb(0xb0, dev
->iobase
+ PCL818_CTRCTL
); /* Stop pacer */
1517 outb(0x70, dev
->iobase
+ PCL818_CTRCTL
);
1518 outb(0x30, dev
->iobase
+ PCL818_CTRCTL
);
1519 if (board
->is_818
) {
1520 outb(0, dev
->iobase
+ PCL818_RANGE
);
1522 outb(0, dev
->iobase
+ PCL718_DA2_LO
);
1523 outb(0, dev
->iobase
+ PCL718_DA2_HI
);
1529 ==============================================================================
1530 Enable(1)/disable(0) periodic interrupts from RTC
1532 static int set_rtc_irq_bit(unsigned char bit
)
1535 unsigned long flags
;
1539 if (RTC_timer_lock
> 1)
1543 if (RTC_timer_lock
< 0)
1545 if (RTC_timer_lock
> 0)
1551 val
= CMOS_READ(RTC_CONTROL
);
1557 CMOS_WRITE(val
, RTC_CONTROL
);
1558 CMOS_READ(RTC_INTR_FLAGS
);
1559 restore_flags(flags
);
1564 ==============================================================================
1565 Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers)
1567 static void rtc_dropped_irq(unsigned long data
)
1569 struct comedi_device
*dev
= (void *)data
;
1570 struct pcl818_private
*devpriv
= dev
->private;
1571 unsigned long flags
, tmp
;
1573 switch (devpriv
->int818_mode
) {
1574 case INT_TYPE_AI1_DMA_RTC
:
1575 case INT_TYPE_AI3_DMA_RTC
:
1576 mod_timer(&devpriv
->rtc_irq_timer
,
1577 jiffies
+ HZ
/ devpriv
->rtc_freq
+ 2 * HZ
/ 100);
1580 tmp
= (CMOS_READ(RTC_INTR_FLAGS
) & 0xF0); /* restart */
1581 restore_flags(flags
);
1587 ==============================================================================
1588 Set frequency of interrupts from RTC
1590 static int rtc_setfreq_irq(int freq
)
1595 unsigned long flags
;
1602 while (freq
> (1 << tmp
))
1605 rtc_freq
= 1 << tmp
;
1609 val
= CMOS_READ(RTC_FREQ_SELECT
) & 0xf0;
1611 CMOS_WRITE(val
, RTC_FREQ_SELECT
);
1612 restore_flags(flags
);
1617 static int pcl818_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
1619 const struct pcl818_board
*board
= comedi_board(dev
);
1620 struct pcl818_private
*devpriv
;
1622 unsigned long iobase
;
1625 unsigned long pages
;
1626 struct comedi_subdevice
*s
;
1628 devpriv
= kzalloc(sizeof(*devpriv
), GFP_KERNEL
);
1631 dev
->private = devpriv
;
1633 /* claim our I/O space */
1634 iobase
= it
->options
[0];
1636 ("comedi%d: pcl818: board=%s, ioport=0x%03lx",
1637 dev
->minor
, board
->name
, iobase
);
1638 devpriv
->io_range
= board
->io_range
;
1639 if ((board
->fifo
) && (it
->options
[2] == -1)) {
1640 /* we've board with FIFO and we want to use FIFO */
1641 devpriv
->io_range
= PCLx1xFIFO_RANGE
;
1642 devpriv
->usefifo
= 1;
1644 if (!request_region(iobase
, devpriv
->io_range
, "pcl818")) {
1645 comedi_error(dev
, "I/O port conflict\n");
1649 dev
->iobase
= iobase
;
1651 if (pcl818_check(iobase
)) {
1652 comedi_error(dev
, "I can't detect board. FAIL!\n");
1656 dev
->board_name
= board
->name
;
1660 if (board
->IRQbits
!= 0) { /* board support IRQ */
1661 irq
= it
->options
[1];
1662 if (irq
) { /* we want to use IRQ */
1663 if (((1 << irq
) & board
->IRQbits
) == 0) {
1665 (", IRQ %u is out of allowed range, DISABLING IT",
1667 irq
= 0; /* Bad IRQ */
1670 (irq
, interrupt_pcl818
, 0, "pcl818", dev
)) {
1672 (", unable to allocate IRQ %u, DISABLING IT",
1674 irq
= 0; /* Can't use IRQ */
1676 printk(KERN_DEBUG
"irq=%u", irq
);
1684 devpriv
->irq_free
= 1; /* 1=we have allocated irq */
1686 devpriv
->irq_free
= 0;
1688 devpriv
->irq_blocked
= 0; /* number of subdevice which use IRQ */
1689 devpriv
->ai_mode
= 0; /* mode of irq */
1692 /* grab RTC for DMA operations */
1693 devpriv
->dma_rtc
= 0;
1694 if (it
->options
[2] > 0) { /* we want to use DMA */
1695 if (RTC_lock
== 0) {
1696 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT
,
1700 devpriv
->rtc_iobase
= RTC_PORT(0);
1701 devpriv
->rtc_iosize
= RTC_IO_EXTENT
;
1703 if (!request_irq(RTC_IRQ
, interrupt_pcl818_ai_mode13_dma_rtc
, 0,
1704 "pcl818 DMA (RTC)", dev
)) {
1705 devpriv
->dma_rtc
= 1;
1706 devpriv
->rtc_irq
= RTC_IRQ
;
1707 printk(KERN_DEBUG
"dma_irq=%u", devpriv
->rtc_irq
);
1710 if (RTC_lock
== 0) {
1711 if (devpriv
->rtc_iobase
)
1712 release_region(devpriv
->rtc_iobase
,
1713 devpriv
->rtc_iosize
);
1715 devpriv
->rtc_iobase
= 0;
1716 devpriv
->rtc_iosize
= 0;
1725 if ((devpriv
->irq_free
== 0) && (devpriv
->dma_rtc
== 0))
1726 goto no_dma
; /* if we haven't IRQ, we can't use DMA */
1727 if (board
->DMAbits
!= 0) { /* board support DMA */
1728 dma
= it
->options
[2];
1730 goto no_dma
; /* DMA disabled */
1731 if (((1 << dma
) & board
->DMAbits
) == 0) {
1732 printk(KERN_ERR
"DMA is out of allowed range, FAIL!\n");
1733 return -EINVAL
; /* Bad DMA */
1735 ret
= request_dma(dma
, "pcl818");
1737 return -EBUSY
; /* DMA isn't free */
1739 pages
= 2; /* we need 16KB */
1740 devpriv
->dmabuf
[0] = __get_dma_pages(GFP_KERNEL
, pages
);
1741 if (!devpriv
->dmabuf
[0])
1742 /* maybe experiment with try_to_free_pages() will help .... */
1743 return -EBUSY
; /* no buffer :-( */
1744 devpriv
->dmapages
[0] = pages
;
1745 devpriv
->hwdmaptr
[0] = virt_to_bus((void *)devpriv
->dmabuf
[0]);
1746 devpriv
->hwdmasize
[0] = (1 << pages
) * PAGE_SIZE
;
1747 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
1748 if (devpriv
->dma_rtc
== 0) { /* we must do duble buff :-( */
1749 devpriv
->dmabuf
[1] = __get_dma_pages(GFP_KERNEL
, pages
);
1750 if (!devpriv
->dmabuf
[1])
1752 devpriv
->dmapages
[1] = pages
;
1753 devpriv
->hwdmaptr
[1] =
1754 virt_to_bus((void *)devpriv
->dmabuf
[1]);
1755 devpriv
->hwdmasize
[1] = (1 << pages
) * PAGE_SIZE
;
1761 ret
= comedi_alloc_subdevices(dev
, 4);
1765 s
= &dev
->subdevices
[0];
1766 if (!board
->n_aichan_se
) {
1767 s
->type
= COMEDI_SUBD_UNUSED
;
1769 s
->type
= COMEDI_SUBD_AI
;
1770 devpriv
->sub_ai
= s
;
1771 s
->subdev_flags
= SDF_READABLE
;
1772 if (check_single_ended(dev
->iobase
)) {
1773 s
->n_chan
= board
->n_aichan_se
;
1774 s
->subdev_flags
|= SDF_COMMON
| SDF_GROUND
;
1775 printk(", %dchans S.E. DAC", s
->n_chan
);
1777 s
->n_chan
= board
->n_aichan_diff
;
1778 s
->subdev_flags
|= SDF_DIFF
;
1779 printk(", %dchans DIFF DAC", s
->n_chan
);
1781 s
->maxdata
= board
->ai_maxdata
;
1782 s
->len_chanlist
= s
->n_chan
;
1783 s
->range_table
= board
->ai_range_type
;
1784 s
->cancel
= pcl818_ai_cancel
;
1785 s
->insn_read
= pcl818_ai_insn_read
;
1786 if ((irq
) || (devpriv
->dma_rtc
)) {
1787 dev
->read_subdev
= s
;
1788 s
->subdev_flags
|= SDF_CMD_READ
;
1789 s
->do_cmdtest
= ai_cmdtest
;
1792 if (board
->is_818
) {
1793 if ((it
->options
[4] == 1) || (it
->options
[4] == 10))
1794 s
->range_table
= &range_pcl818l_h_ai
; /* secondary range list jumper selectable */
1796 switch (it
->options
[4]) {
1798 s
->range_table
= &range_bipolar10
;
1801 s
->range_table
= &range_bipolar5
;
1804 s
->range_table
= &range_bipolar2_5
;
1807 s
->range_table
= &range718_bipolar1
;
1810 s
->range_table
= &range718_bipolar0_5
;
1813 s
->range_table
= &range_unipolar10
;
1816 s
->range_table
= &range_unipolar5
;
1819 s
->range_table
= &range718_unipolar2
;
1822 s
->range_table
= &range718_unipolar1
;
1825 s
->range_table
= &range_unknown
;
1831 s
= &dev
->subdevices
[1];
1832 if (!board
->n_aochan
) {
1833 s
->type
= COMEDI_SUBD_UNUSED
;
1835 s
->type
= COMEDI_SUBD_AO
;
1836 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
;
1837 s
->n_chan
= board
->n_aochan
;
1838 s
->maxdata
= board
->ao_maxdata
;
1839 s
->len_chanlist
= board
->n_aochan
;
1840 s
->range_table
= board
->ao_range_type
;
1841 s
->insn_read
= pcl818_ao_insn_read
;
1842 s
->insn_write
= pcl818_ao_insn_write
;
1844 #ifdef PCL818_MODE13_AO
1846 s
->trig
[1] = pcl818_ao_mode1
;
1847 s
->trig
[3] = pcl818_ao_mode3
;
1851 if (board
->is_818
) {
1852 if ((it
->options
[4] == 1) || (it
->options
[4] == 10))
1853 s
->range_table
= &range_unipolar10
;
1854 if (it
->options
[4] == 2)
1855 s
->range_table
= &range_unknown
;
1857 if ((it
->options
[5] == 1) || (it
->options
[5] == 10))
1858 s
->range_table
= &range_unipolar10
;
1859 if (it
->options
[5] == 2)
1860 s
->range_table
= &range_unknown
;
1864 s
= &dev
->subdevices
[2];
1865 if (!board
->n_dichan
) {
1866 s
->type
= COMEDI_SUBD_UNUSED
;
1868 s
->type
= COMEDI_SUBD_DI
;
1869 s
->subdev_flags
= SDF_READABLE
;
1870 s
->n_chan
= board
->n_dichan
;
1872 s
->len_chanlist
= board
->n_dichan
;
1873 s
->range_table
= &range_digital
;
1874 s
->insn_bits
= pcl818_di_insn_bits
;
1877 s
= &dev
->subdevices
[3];
1878 if (!board
->n_dochan
) {
1879 s
->type
= COMEDI_SUBD_UNUSED
;
1881 s
->type
= COMEDI_SUBD_DO
;
1882 s
->subdev_flags
= SDF_WRITABLE
;
1883 s
->n_chan
= board
->n_dochan
;
1885 s
->len_chanlist
= board
->n_dochan
;
1886 s
->range_table
= &range_digital
;
1887 s
->insn_bits
= pcl818_do_insn_bits
;
1890 /* select 1/10MHz oscilator */
1891 if ((it
->options
[3] == 0) || (it
->options
[3] == 10))
1892 devpriv
->i8253_osc_base
= 100;
1894 devpriv
->i8253_osc_base
= 1000;
1896 /* max sampling speed */
1897 devpriv
->ns_min
= board
->ns_min
;
1899 if (!board
->is_818
) {
1900 if ((it
->options
[6] == 1) || (it
->options
[6] == 100))
1901 devpriv
->ns_min
= 10000; /* extended PCL718 to 100kHz DAC */
1911 static void pcl818_detach(struct comedi_device
*dev
)
1913 struct pcl818_private
*devpriv
= dev
->private;
1916 pcl818_ai_cancel(dev
, devpriv
->sub_ai
);
1919 free_dma(devpriv
->dma
);
1920 if (devpriv
->dmabuf
[0])
1921 free_pages(devpriv
->dmabuf
[0], devpriv
->dmapages
[0]);
1922 if (devpriv
->dmabuf
[1])
1923 free_pages(devpriv
->dmabuf
[1], devpriv
->dmapages
[1]);
1925 if (devpriv
->rtc_irq
)
1926 free_irq(devpriv
->rtc_irq
, dev
);
1927 if ((devpriv
->dma_rtc
) && (RTC_lock
== 1)) {
1928 if (devpriv
->rtc_iobase
)
1929 release_region(devpriv
->rtc_iobase
,
1930 devpriv
->rtc_iosize
);
1932 if (devpriv
->dma_rtc
)
1937 free_irq(dev
->irq
, dev
);
1939 release_region(dev
->iobase
, devpriv
->io_range
);
1942 static const struct pcl818_board boardtypes
[] = {
1943 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai
,
1944 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1945 0x0a, 0xfff, 0xfff, 0, 1},
1946 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai
,
1947 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1948 0x0a, 0xfff, 0xfff, 0, 1},
1949 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai
,
1950 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1951 0x0a, 0xfff, 0xfff, 1, 1},
1952 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai
,
1953 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1954 0x0a, 0xfff, 0xfff, 1, 1},
1955 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai
,
1956 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1957 0x0a, 0xfff, 0xfff, 0, 1},
1958 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5
,
1959 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1960 0x0a, 0xfff, 0xfff, 0, 0},
1962 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai
,
1963 &range_unipolar5
, PCLx1x_RANGE
, 0x00fc,
1964 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
1967 static struct comedi_driver pcl818_driver
= {
1968 .driver_name
= "pcl818",
1969 .module
= THIS_MODULE
,
1970 .attach
= pcl818_attach
,
1971 .detach
= pcl818_detach
,
1972 .board_name
= &boardtypes
[0].name
,
1973 .num_names
= ARRAY_SIZE(boardtypes
),
1974 .offset
= sizeof(struct pcl818_board
),
1976 module_comedi_driver(pcl818_driver
);
1978 MODULE_AUTHOR("Comedi http://www.comedi.org");
1979 MODULE_DESCRIPTION("Comedi low-level driver");
1980 MODULE_LICENSE("GPL");