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>
111 /* #define PCL818_MODE13_AO 1 */
113 /* boards constants */
115 #define boardPCL818L 0
116 #define boardPCL818H 1
117 #define boardPCL818HD 2
118 #define boardPCL818HG 3
119 #define boardPCL818 4
120 #define boardPCL718 5
123 #define PCLx1x_RANGE 16
124 /* IO space len if we use FIFO */
125 #define PCLx1xFIFO_RANGE 32
127 /* W: clear INT request */
128 #define PCL818_CLRINT 8
129 /* R: return status byte */
130 #define PCL818_STATUS 8
131 /* R: A/D high byte W: A/D range control */
132 #define PCL818_RANGE 1
133 /* R: next mux scan channel W: mux scan channel & range control pointer */
135 /* R/W: operation control register */
136 #define PCL818_CONTROL 9
137 /* W: counter enable */
138 #define PCL818_CNTENABLE 10
140 /* R: low byte of A/D W: soft A/D trigger */
141 #define PCL818_AD_LO 0
142 /* R: high byte of A/D W: A/D range control */
143 #define PCL818_AD_HI 1
144 /* W: D/A low&high byte */
145 #define PCL818_DA_LO 4
146 #define PCL818_DA_HI 5
147 /* R: low&high byte of DI */
148 #define PCL818_DI_LO 3
149 #define PCL818_DI_HI 11
150 /* W: low&high byte of DO */
151 #define PCL818_DO_LO 3
152 #define PCL818_DO_HI 11
153 /* W: PCL718 second D/A */
154 #define PCL718_DA2_LO 6
155 #define PCL718_DA2_HI 7
157 #define PCL818_CTR0 12
158 #define PCL818_CTR1 13
159 #define PCL818_CTR2 14
160 /* W: counter control */
161 #define PCL818_CTRCTL 15
163 /* W: fifo enable/disable */
164 #define PCL818_FI_ENABLE 6
165 /* W: fifo interrupt clear */
166 #define PCL818_FI_INTCLR 20
167 /* W: fifo interrupt clear */
168 #define PCL818_FI_FLUSH 25
170 #define PCL818_FI_STATUS 25
171 /* R: one record from FIFO */
172 #define PCL818_FI_DATALO 23
173 #define PCL818_FI_DATAHI 23
175 /* type of interrupt handler */
176 #define INT_TYPE_AI1_INT 1
177 #define INT_TYPE_AI1_DMA 2
178 #define INT_TYPE_AI1_FIFO 3
179 #define INT_TYPE_AI3_INT 4
180 #define INT_TYPE_AI3_DMA 5
181 #define INT_TYPE_AI3_FIFO 6
182 #ifdef PCL818_MODE13_AO
183 #define INT_TYPE_AO1_INT 7
184 #define INT_TYPE_AO3_INT 8
189 #define INT_TYPE_AI1_DMA_RTC 9
190 #define INT_TYPE_AI3_DMA_RTC 10
193 #define RTC_IO_EXTENT 0x10
196 #define MAGIC_DMA_WORD 0x5a5a
198 static const struct comedi_lrange range_pcl818h_ai = { 9, {
211 static const struct comedi_lrange range_pcl818hg_ai = { 10, {
227 static const struct comedi_lrange range_pcl818l_l_ai = { 4, {
235 static const struct comedi_lrange range_pcl818l_h_ai = { 4, {
243 static const struct comedi_lrange range718_bipolar1 = { 1, {BIP_RANGE(1),} };
244 static const struct comedi_lrange range718_bipolar0_5 =
245 { 1, {BIP_RANGE(0.5),} };
246 static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} };
247 static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} };
249 static int pcl818_attach(struct comedi_device *dev,
250 struct comedi_devconfig *it);
251 static int pcl818_detach(struct comedi_device *dev);
254 static int RTC_lock = 0; /* RTC lock */
255 static int RTC_timer_lock = 0; /* RTC int lock */
258 struct pcl818_board {
260 const char *name; /* driver name */
261 int n_ranges; /* len of range list */
262 int n_aichan_se; /* num of A/D chans in single ended mode */
263 int n_aichan_diff; /* num of A/D chans in diferencial mode */
264 unsigned int ns_min; /* minimal alllowed delay between samples (in ns) */
265 int n_aochan; /* num of D/A chans */
266 int n_dichan; /* num of DI chans */
267 int n_dochan; /* num of DO chans */
268 const struct comedi_lrange *ai_range_type; /* default A/D rangelist */
269 const struct comedi_lrange *ao_range_type; /* default D/A rangelist */
270 unsigned int io_range; /* len of IO space */
271 unsigned int IRQbits; /* allowed interrupts */
272 unsigned int DMAbits; /* allowed DMA chans */
273 int ai_maxdata; /* maxdata for A/D */
274 int ao_maxdata; /* maxdata for D/A */
275 unsigned char fifo; /* 1=board has FIFO */
279 static const struct pcl818_board boardtypes[] = {
280 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
281 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
282 0x0a, 0xfff, 0xfff, 0, 1},
283 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
284 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
285 0x0a, 0xfff, 0xfff, 0, 1},
286 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
287 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
288 0x0a, 0xfff, 0xfff, 1, 1},
289 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
290 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
291 0x0a, 0xfff, 0xfff, 1, 1},
292 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
293 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
294 0x0a, 0xfff, 0xfff, 0, 1},
295 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
296 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
297 0x0a, 0xfff, 0xfff, 0, 0},
299 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
300 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
301 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
304 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl818_board))
306 static struct comedi_driver driver_pcl818 = {
307 .driver_name = "pcl818",
308 .module = THIS_MODULE,
309 .attach = pcl818_attach,
310 .detach = pcl818_detach,
311 .board_name = &boardtypes[0].name,
312 .num_names = n_boardtypes,
313 .offset = sizeof(struct pcl818_board),
316 COMEDI_INITCLEANUP(driver_pcl818);
318 struct pcl818_private {
320 unsigned int dma; /* used DMA, 0=don't use DMA */
321 int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */
322 unsigned int io_range;
324 unsigned long rtc_iobase; /* RTC port region */
325 unsigned int rtc_iosize;
326 unsigned int rtc_irq;
327 struct timer_list rtc_irq_timer; /* timer for RTC sanity check */
328 unsigned long rtc_freq; /* RTC int freq */
329 int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */
331 unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
332 unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */
333 unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
334 unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */
335 unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */
336 unsigned int last_top_dma; /* DMA pointer in last RTC int */
337 int next_dma_buf; /* which DMA buffer will be used next round */
338 long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
339 unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
340 unsigned char neverending_ai; /* if=1, then we do neverending record (you must use cancel()) */
341 unsigned int ns_min; /* manimal alllowed delay between samples (in us) for actual card */
342 int i8253_osc_base; /* 1/frequency of on board oscilator in ns */
343 int irq_free; /* 1=have allocated IRQ */
344 int irq_blocked; /* 1=IRQ now uses any subdev */
345 int irq_was_now_closed; /* when IRQ finish, there's stored int818_mode for last interrupt */
346 int ai_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
347 struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */
348 int ai_act_scan; /* how many scans we finished */
349 int ai_act_chan; /* actual position in actual scan */
350 unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */
351 unsigned int act_chanlist_len; /* how long is actual MUX list */
352 unsigned int act_chanlist_pos; /* actual position in MUX list */
353 unsigned int ai_scans; /* len of scanlist */
354 unsigned int ai_n_chan; /* how many channels is measured */
355 unsigned int *ai_chanlist; /* actaul chanlist */
356 unsigned int ai_flags; /* flaglist */
357 unsigned int ai_data_len; /* len of data buffer */
358 short *ai_data; /* data buffer */
359 unsigned int ai_timer1; /* timers */
360 unsigned int ai_timer2;
361 struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */
362 unsigned char usefifo; /* 1=use fifo */
363 unsigned int ao_readback[2];
366 static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */
367 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
370 #define devpriv ((struct pcl818_private *)dev->private)
371 #define this_board ((const struct pcl818_board *)dev->board_ptr)
374 ==============================================================================
376 static void setup_channel_list(struct comedi_device *dev,
377 struct comedi_subdevice *s,
378 unsigned int *chanlist, unsigned int n_chan,
379 unsigned int seglen);
380 static int check_channel_list(struct comedi_device *dev,
381 struct comedi_subdevice *s,
382 unsigned int *chanlist, unsigned int n_chan);
384 static int pcl818_ai_cancel(struct comedi_device *dev,
385 struct comedi_subdevice *s);
386 static void start_pacer(struct comedi_device *dev, int mode,
387 unsigned int divisor1, unsigned int divisor2);
390 static int set_rtc_irq_bit(unsigned char bit);
391 static void rtc_dropped_irq(unsigned long data);
392 static int rtc_setfreq_irq(int freq);
396 ==============================================================================
397 ANALOG INPUT MODE0, 818 cards, slow version
399 static int pcl818_ai_insn_read(struct comedi_device *dev,
400 struct comedi_subdevice *s,
401 struct comedi_insn *insn, unsigned int *data)
406 /* software trigger, DMA and INT off */
407 outb(0, dev->iobase + PCL818_CONTROL);
410 outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX);
413 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE);
415 for (n = 0; n < insn->n; n++) {
417 /* clear INT (conversion end) flag */
418 outb(0, dev->iobase + PCL818_CLRINT);
420 /* start conversion */
421 outb(0, dev->iobase + PCL818_AD_LO);
425 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
429 comedi_error(dev, "A/D insn timeout");
430 /* clear INT (conversion end) flag */
431 outb(0, dev->iobase + PCL818_CLRINT);
435 data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |
436 (inb(dev->iobase + PCL818_AD_LO) >> 4));
443 ==============================================================================
444 ANALOG OUTPUT MODE0, 818 cards
445 only one sample per call is supported
447 static int pcl818_ao_insn_read(struct comedi_device *dev,
448 struct comedi_subdevice *s,
449 struct comedi_insn *insn, unsigned int *data)
452 int chan = CR_CHAN(insn->chanspec);
454 for (n = 0; n < insn->n; n++) {
455 data[n] = devpriv->ao_readback[chan];
461 static int pcl818_ao_insn_write(struct comedi_device *dev,
462 struct comedi_subdevice *s,
463 struct comedi_insn *insn, unsigned int *data)
466 int chan = CR_CHAN(insn->chanspec);
468 for (n = 0; n < insn->n; n++) {
469 devpriv->ao_readback[chan] = data[n];
470 outb((data[n] & 0x000f) << 4, dev->iobase +
471 (chan ? PCL718_DA2_LO : PCL818_DA_LO));
472 outb((data[n] & 0x0ff0) >> 4, dev->iobase +
473 (chan ? PCL718_DA2_HI : PCL818_DA_HI));
480 ==============================================================================
481 DIGITAL INPUT MODE0, 818 cards
483 only one sample per call is supported
485 static int pcl818_di_insn_bits(struct comedi_device *dev,
486 struct comedi_subdevice *s,
487 struct comedi_insn *insn, unsigned int *data)
492 data[1] = inb(dev->iobase + PCL818_DI_LO) |
493 (inb(dev->iobase + PCL818_DI_HI) << 8);
499 ==============================================================================
500 DIGITAL OUTPUT MODE0, 818 cards
502 only one sample per call is supported
504 static int pcl818_do_insn_bits(struct comedi_device *dev,
505 struct comedi_subdevice *s,
506 struct comedi_insn *insn, unsigned int *data)
511 s->state &= ~data[0];
512 s->state |= (data[0] & data[1]);
514 outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
515 outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
523 ==============================================================================
524 analog input interrupt mode 1 & 3, 818 cards
525 one sample per interrupt version
527 static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
529 struct comedi_device *dev = d;
530 struct comedi_subdevice *s = dev->subdevices + 0;
532 int timeout = 50; /* wait max 50us */
535 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
539 outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */
540 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
541 pcl818_ai_cancel(dev, s);
542 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
543 comedi_event(dev, s);
547 low = inb(dev->iobase + PCL818_AD_LO);
548 comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */
549 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
551 if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
553 ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
555 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
556 pcl818_ai_cancel(dev, s);
557 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
558 comedi_event(dev, s);
561 devpriv->act_chanlist_pos++;
562 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) {
563 devpriv->act_chanlist_pos = 0;
565 s->async->cur_chan++;
566 if (s->async->cur_chan >= devpriv->ai_n_chan) {
568 s->async->cur_chan = 0;
569 devpriv->ai_act_scan--;
572 if (!devpriv->neverending_ai) {
573 if (devpriv->ai_act_scan == 0) { /* all data sampled */
574 pcl818_ai_cancel(dev, s);
575 s->async->events |= COMEDI_CB_EOA;
578 comedi_event(dev, s);
583 ==============================================================================
584 analog input dma mode 1 & 3, 818 cards
586 static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
588 struct comedi_device *dev = d;
589 struct comedi_subdevice *s = dev->subdevices + 0;
594 disable_dma(devpriv->dma);
595 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
596 if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */
597 set_dma_mode(devpriv->dma, DMA_MODE_READ);
598 flags = claim_dma_lock();
599 set_dma_addr(devpriv->dma,
600 devpriv->hwdmaptr[devpriv->next_dma_buf]);
601 if (devpriv->dma_runs_to_end || devpriv->neverending_ai) {
602 set_dma_count(devpriv->dma,
603 devpriv->hwdmasize[devpriv->
606 set_dma_count(devpriv->dma, devpriv->last_dma_run);
608 release_dma_lock(flags);
609 enable_dma(devpriv->dma);
611 printk("comedi: A/D mode1/3 IRQ \n");
613 devpriv->dma_runs_to_end--;
614 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
615 ptr = (short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
617 len = devpriv->hwdmasize[0] >> 1;
620 for (i = 0; i < len; i++) {
621 if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
623 ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
625 devpriv->act_chanlist[devpriv->act_chanlist_pos],
626 devpriv->act_chanlist_pos);
627 pcl818_ai_cancel(dev, s);
628 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
629 comedi_event(dev, s);
633 comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */
635 devpriv->act_chanlist_pos++;
636 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) {
637 devpriv->act_chanlist_pos = 0;
639 s->async->cur_chan++;
640 if (s->async->cur_chan >= devpriv->ai_n_chan) {
641 s->async->cur_chan = 0;
642 devpriv->ai_act_scan--;
645 if (!devpriv->neverending_ai)
646 if (devpriv->ai_act_scan == 0) { /* all data sampled */
647 pcl818_ai_cancel(dev, s);
648 s->async->events |= COMEDI_CB_EOA;
649 comedi_event(dev, s);
650 /* printk("done int ai13 dma\n"); */
656 comedi_event(dev, s);
662 ==============================================================================
663 analog input dma mode 1 & 3 over RTC, 818 cards
665 static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d)
667 struct comedi_device *dev = d;
668 struct comedi_subdevice *s = dev->subdevices + 0;
670 unsigned int top1, top2, i, bufptr;
672 short *dmabuf = (short *)devpriv->dmabuf[0];
675 switch (devpriv->ai_mode) {
676 case INT_TYPE_AI1_DMA_RTC:
677 case INT_TYPE_AI3_DMA_RTC:
678 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
679 mod_timer(&devpriv->rtc_irq_timer,
680 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
682 for (i = 0; i < 10; i++) {
683 top1 = get_dma_residue(devpriv->dma);
684 top2 = get_dma_residue(devpriv->dma);
691 top1 = devpriv->hwdmasize[0] - top1; /* where is now DMA in buffer */
693 ofs_dats = top1 - devpriv->last_top_dma; /* new samples from last call */
695 ofs_dats = (devpriv->dmasamplsize) + ofs_dats;
697 return IRQ_HANDLED; /* exit=no new samples from last call */
699 i = devpriv->last_top_dma - 1;
700 i &= (devpriv->dmasamplsize - 1);
702 if (dmabuf[i] != MAGIC_DMA_WORD) { /* DMA overflow! */
703 comedi_error(dev, "A/D mode1/3 DMA buffer overflow!");
704 /* printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize); */
705 pcl818_ai_cancel(dev, s);
706 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
707 comedi_event(dev, s);
710 /* printk("r %ld ",ofs_dats); */
712 bufptr = devpriv->last_top_dma;
714 for (i = 0; i < ofs_dats; i++) {
715 if ((dmabuf[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
717 ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",
718 (dmabuf[bufptr] & 0xf),
720 act_chanlist[devpriv->act_chanlist_pos]);
721 pcl818_ai_cancel(dev, s);
723 COMEDI_CB_EOA | COMEDI_CB_ERROR;
724 comedi_event(dev, s);
728 comedi_buf_put(s->async, dmabuf[bufptr++] >> 4); /* get one sample */
729 bufptr &= (devpriv->dmasamplsize - 1);
731 devpriv->act_chanlist_pos++;
732 if (devpriv->act_chanlist_pos >=
733 devpriv->act_chanlist_len) {
734 devpriv->act_chanlist_pos = 0;
736 s->async->cur_chan++;
737 if (s->async->cur_chan >= devpriv->ai_n_chan) {
738 s->async->cur_chan = 0;
739 devpriv->ai_act_scan--;
742 if (!devpriv->neverending_ai)
743 if (devpriv->ai_act_scan == 0) { /* all data sampled */
744 pcl818_ai_cancel(dev, s);
745 s->async->events |= COMEDI_CB_EOA;
746 comedi_event(dev, s);
747 /* printk("done int ai13 dma\n"); */
752 devpriv->last_top_dma = bufptr;
754 bufptr &= (devpriv->dmasamplsize - 1);
755 dmabuf[bufptr] = MAGIC_DMA_WORD;
756 comedi_event(dev, s);
767 ==============================================================================
768 analog input interrupt mode 1 & 3, 818HD/HG cards
770 static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
772 struct comedi_device *dev = d;
773 struct comedi_subdevice *s = dev->subdevices + 0;
776 outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */
778 lo = inb(dev->iobase + PCL818_FI_STATUS);
781 comedi_error(dev, "A/D mode1/3 FIFO overflow!");
782 pcl818_ai_cancel(dev, s);
783 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
784 comedi_event(dev, s);
789 comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!");
790 pcl818_ai_cancel(dev, s);
791 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
792 comedi_event(dev, s);
802 for (i = 0; i < len; i++) {
803 lo = inb(dev->iobase + PCL818_FI_DATALO);
804 if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
806 ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
808 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
809 pcl818_ai_cancel(dev, s);
810 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
811 comedi_event(dev, s);
815 comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */
817 devpriv->act_chanlist_pos++;
818 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) {
819 devpriv->act_chanlist_pos = 0;
821 s->async->cur_chan++;
822 if (s->async->cur_chan >= devpriv->ai_n_chan) {
823 s->async->cur_chan = 0;
824 devpriv->ai_act_scan--;
827 if (!devpriv->neverending_ai)
828 if (devpriv->ai_act_scan == 0) { /* all data sampled */
829 pcl818_ai_cancel(dev, s);
830 s->async->events |= COMEDI_CB_EOA;
831 comedi_event(dev, s);
837 comedi_event(dev, s);
842 ==============================================================================
845 static irqreturn_t interrupt_pcl818(int irq, void *d)
847 struct comedi_device *dev = d;
849 if (!dev->attached) {
850 comedi_error(dev, "premature interrupt");
855 if (devpriv->irq_blocked && devpriv->irq_was_now_closed) {
856 if ((devpriv->neverending_ai || (!devpriv->neverending_ai &&
857 devpriv->ai_act_scan > 0)) &&
858 (devpriv->ai_mode == INT_TYPE_AI1_DMA ||
859 devpriv->ai_mode == INT_TYPE_AI3_DMA)) {
860 /* The cleanup from ai_cancel() has been delayed
861 until now because the card doesn't seem to like
862 being reprogrammed while a DMA transfer is in
865 struct comedi_subdevice *s = dev->subdevices + 0;
866 devpriv->ai_act_scan = 0;
867 devpriv->neverending_ai = 0;
868 pcl818_ai_cancel(dev, s);
871 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
876 switch (devpriv->ai_mode) {
877 case INT_TYPE_AI1_DMA:
878 case INT_TYPE_AI3_DMA:
879 return interrupt_pcl818_ai_mode13_dma(irq, d);
880 case INT_TYPE_AI1_INT:
881 case INT_TYPE_AI3_INT:
882 return interrupt_pcl818_ai_mode13_int(irq, d);
883 case INT_TYPE_AI1_FIFO:
884 case INT_TYPE_AI3_FIFO:
885 return interrupt_pcl818_ai_mode13_fifo(irq, d);
886 #ifdef PCL818_MODE13_AO
887 case INT_TYPE_AO1_INT:
888 case INT_TYPE_AO3_INT:
889 return interrupt_pcl818_ao_mode13_int(irq, d);
895 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
897 if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked)
898 || (!devpriv->ai_mode)) {
899 comedi_error(dev, "bad IRQ!");
903 comedi_error(dev, "IRQ from unknown source!");
908 ==============================================================================
909 ANALOG INPUT MODE 1 or 3 DMA , 818 cards
911 static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev,
912 struct comedi_subdevice *s)
917 printk("mode13dma_int, mode: %d\n", mode);
918 disable_dma(devpriv->dma); /* disable dma */
919 bytes = devpriv->hwdmasize[0];
920 if (!devpriv->neverending_ai) {
921 bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */
922 devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */
923 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */
924 devpriv->dma_runs_to_end--;
925 if (devpriv->dma_runs_to_end >= 0)
926 bytes = devpriv->hwdmasize[0];
929 devpriv->next_dma_buf = 0;
930 set_dma_mode(devpriv->dma, DMA_MODE_READ);
931 flags = claim_dma_lock();
932 clear_dma_ff(devpriv->dma);
933 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
934 set_dma_count(devpriv->dma, bytes);
935 release_dma_lock(flags);
936 enable_dma(devpriv->dma);
939 devpriv->ai_mode = INT_TYPE_AI1_DMA;
940 outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */
942 devpriv->ai_mode = INT_TYPE_AI3_DMA;
943 outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */
949 ==============================================================================
950 ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards
952 static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device *dev,
953 struct comedi_subdevice *s)
958 set_dma_mode(devpriv->dma, DMA_MODE_READ | DMA_AUTOINIT);
959 flags = claim_dma_lock();
960 clear_dma_ff(devpriv->dma);
961 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
962 set_dma_count(devpriv->dma, devpriv->hwdmasize[0]);
963 release_dma_lock(flags);
964 enable_dma(devpriv->dma);
965 devpriv->last_top_dma = 0; /* devpriv->hwdmasize[0]; */
966 pole = (short *)devpriv->dmabuf[0];
967 devpriv->dmasamplsize = devpriv->hwdmasize[0] / 2;
968 pole[devpriv->dmasamplsize - 1] = MAGIC_DMA_WORD;
970 devpriv->rtc_freq = rtc_setfreq_irq(2048);
971 devpriv->rtc_irq_timer.expires =
972 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100;
973 devpriv->rtc_irq_timer.data = (unsigned long)dev;
974 devpriv->rtc_irq_timer.function = rtc_dropped_irq;
976 add_timer(&devpriv->rtc_irq_timer);
980 devpriv->int818_mode = INT_TYPE_AI1_DMA_RTC;
981 outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+DMA */
983 devpriv->int818_mode = INT_TYPE_AI3_DMA_RTC;
984 outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+DMA */
990 ==============================================================================
991 ANALOG INPUT MODE 1 or 3, 818 cards
993 static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
994 struct comedi_subdevice *s)
996 struct comedi_cmd *cmd = &s->async->cmd;
997 int divisor1 = 0, divisor2 = 0;
1000 printk("pcl818_ai_cmd_mode()\n");
1001 if ((!dev->irq) && (!devpriv->dma_rtc)) {
1002 comedi_error(dev, "IRQ not defined!");
1006 if (devpriv->irq_blocked)
1009 start_pacer(dev, -1, 0, 0); /* stop pacer */
1011 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
1012 devpriv->ai_n_chan);
1015 setup_channel_list(dev, s, devpriv->ai_chanlist,
1016 devpriv->ai_n_chan, seglen);
1020 devpriv->ai_act_scan = devpriv->ai_scans;
1021 devpriv->ai_act_chan = 0;
1022 devpriv->irq_blocked = 1;
1023 devpriv->irq_was_now_closed = 0;
1024 devpriv->neverending_ai = 0;
1025 devpriv->act_chanlist_pos = 0;
1026 devpriv->dma_runs_to_end = 0;
1028 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
1029 devpriv->neverending_ai = 1; /* well, user want neverending */
1032 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1033 &divisor2, &cmd->convert_arg,
1034 TRIG_ROUND_NEAREST);
1035 if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */
1039 if (divisor2 == 1) {
1045 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1047 switch (devpriv->dma) {
1050 if (devpriv->dma_rtc == 0) {
1051 pcl818_ai_mode13dma_int(mode, dev, s);
1055 pcl818_ai_mode13dma_rtc(mode, dev, s);
1064 if (!devpriv->usefifo) {
1066 /* printk("IRQ\n"); */
1068 devpriv->ai_mode = INT_TYPE_AI1_INT;
1070 outb(0x83 | (dev->irq << 4),
1071 dev->iobase + PCL818_CONTROL);
1073 devpriv->ai_mode = INT_TYPE_AI3_INT;
1075 outb(0x82 | (dev->irq << 4),
1076 dev->iobase + PCL818_CONTROL);
1081 outb(1, dev->iobase + PCL818_FI_ENABLE);
1083 devpriv->ai_mode = INT_TYPE_AI1_FIFO;
1085 outb(0x03, dev->iobase + PCL818_CONTROL);
1087 devpriv->ai_mode = INT_TYPE_AI3_FIFO;
1088 outb(0x02, dev->iobase + PCL818_CONTROL);
1093 start_pacer(dev, mode, divisor1, divisor2);
1096 switch (devpriv->ai_mode) {
1097 case INT_TYPE_AI1_DMA_RTC:
1098 case INT_TYPE_AI3_DMA_RTC:
1099 set_rtc_irq_bit(1); /* start RTC */
1103 printk("pcl818_ai_cmd_mode() end\n");
1109 ==============================================================================
1110 ANALOG OUTPUT MODE 1 or 3, 818 cards
1112 #ifdef PCL818_MODE13_AO
1113 static int pcl818_ao_mode13(int mode, struct comedi_device *dev,
1114 struct comedi_subdevice *s, comedi_trig * it)
1116 int divisor1 = 0, divisor2 = 0;
1119 comedi_error(dev, "IRQ not defined!");
1123 if (devpriv->irq_blocked)
1126 start_pacer(dev, -1, 0, 0); /* stop pacer */
1128 devpriv->int13_act_scan = it->n;
1129 devpriv->int13_act_chan = 0;
1130 devpriv->irq_blocked = 1;
1131 devpriv->irq_was_now_closed = 0;
1132 devpriv->neverending_ai = 0;
1133 devpriv->act_chanlist_pos = 0;
1136 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1137 &divisor2, &it->trigvar,
1138 TRIG_ROUND_NEAREST);
1139 if (divisor1 == 1) { /* PCL818 crash if any divisor is set to 1 */
1143 if (divisor2 == 1) {
1149 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1151 devpriv->int818_mode = INT_TYPE_AO1_INT;
1152 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */
1154 devpriv->int818_mode = INT_TYPE_AO3_INT;
1155 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */
1158 start_pacer(dev, mode, divisor1, divisor2);
1164 ==============================================================================
1165 ANALOG OUTPUT MODE 1, 818 cards
1167 static int pcl818_ao_mode1(struct comedi_device *dev,
1168 struct comedi_subdevice *s, comedi_trig * it)
1170 return pcl818_ao_mode13(1, dev, s, it);
1174 ==============================================================================
1175 ANALOG OUTPUT MODE 3, 818 cards
1177 static int pcl818_ao_mode3(struct comedi_device *dev,
1178 struct comedi_subdevice *s, comedi_trig * it)
1180 return pcl818_ao_mode13(3, dev, s, it);
1186 ==============================================================================
1187 Start/stop pacer onboard pacer
1189 static void start_pacer(struct comedi_device *dev, int mode,
1190 unsigned int divisor1, unsigned int divisor2)
1192 outb(0xb4, dev->iobase + PCL818_CTRCTL);
1193 outb(0x74, dev->iobase + PCL818_CTRCTL);
1197 outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
1198 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
1199 outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
1200 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
1205 ==============================================================================
1206 Check if channel list from user is builded correctly
1207 If it's ok, then program scan/gain logic
1209 static int check_channel_list(struct comedi_device *dev,
1210 struct comedi_subdevice *s,
1211 unsigned int *chanlist, unsigned int n_chan)
1213 unsigned int chansegment[16];
1214 unsigned int i, nowmustbechan, seglen, segpos;
1216 /* correct channel and range number check itself comedi/range.c */
1218 comedi_error(dev, "range/channel list is empty!");
1223 /* first channel is everytime ok */
1224 chansegment[0] = chanlist[0];
1225 /* build part of chanlist */
1226 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
1228 /* printk("%d. %d * %d\n",i,
1229 * CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));*/
1231 /* we detect loop, this must by finish */
1233 if (chanlist[0] == chanlist[i])
1236 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1237 if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continous :-( */
1239 ("comedi%d: pcl818: channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1240 dev->minor, i, CR_CHAN(chanlist[i]),
1241 nowmustbechan, CR_CHAN(chanlist[0]));
1244 /* well, this is next correct channel in list */
1245 chansegment[i] = chanlist[i];
1248 /* check whole chanlist */
1249 for (i = 0, segpos = 0; i < n_chan; i++) {
1250 /* 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])); */
1251 if (chanlist[i] != chansegment[i % seglen]) {
1253 ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1254 dev->minor, i, CR_CHAN(chansegment[i]),
1255 CR_RANGE(chansegment[i]),
1256 CR_AREF(chansegment[i]),
1257 CR_CHAN(chanlist[i % seglen]),
1258 CR_RANGE(chanlist[i % seglen]),
1259 CR_AREF(chansegment[i % seglen]));
1260 return 0; /* chan/gain list is strange */
1266 printk("check_channel_list: seglen %d\n", seglen);
1270 static void setup_channel_list(struct comedi_device *dev,
1271 struct comedi_subdevice *s,
1272 unsigned int *chanlist, unsigned int n_chan,
1273 unsigned int seglen)
1277 devpriv->act_chanlist_len = seglen;
1278 devpriv->act_chanlist_pos = 0;
1280 for (i = 0; i < seglen; i++) { /* store range list to card */
1281 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
1282 outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */
1283 outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */
1288 /* select channel interval to scan */
1289 outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen -
1291 dev->iobase + PCL818_MUX);
1295 ==============================================================================
1296 Check if board is switched to SE (1) or DIFF(0) mode
1298 static int check_single_ended(unsigned int port)
1300 if (inb(port + PCL818_STATUS) & 0x20) {
1308 ==============================================================================
1310 static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
1311 struct comedi_cmd *cmd)
1314 int tmp, divisor1 = 0, divisor2 = 0;
1316 /* step 1: make sure trigger sources are trivially valid */
1318 tmp = cmd->start_src;
1319 cmd->start_src &= TRIG_NOW;
1320 if (!cmd->start_src || tmp != cmd->start_src)
1323 tmp = cmd->scan_begin_src;
1324 cmd->scan_begin_src &= TRIG_FOLLOW;
1325 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1328 tmp = cmd->convert_src;
1329 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
1330 if (!cmd->convert_src || tmp != cmd->convert_src)
1333 tmp = cmd->scan_end_src;
1334 cmd->scan_end_src &= TRIG_COUNT;
1335 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1338 tmp = cmd->stop_src;
1339 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
1340 if (!cmd->stop_src || tmp != cmd->stop_src)
1347 /* step 2: make sure trigger sources are unique and mutually compatible */
1349 if (cmd->start_src != TRIG_NOW) {
1350 cmd->start_src = TRIG_NOW;
1353 if (cmd->scan_begin_src != TRIG_FOLLOW) {
1354 cmd->scan_begin_src = TRIG_FOLLOW;
1357 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
1360 if (cmd->scan_end_src != TRIG_COUNT) {
1361 cmd->scan_end_src = TRIG_COUNT;
1365 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
1372 /* step 3: make sure arguments are trivially compatible */
1374 if (cmd->start_arg != 0) {
1379 if (cmd->scan_begin_arg != 0) {
1380 cmd->scan_begin_arg = 0;
1384 if (cmd->convert_src == TRIG_TIMER) {
1385 if (cmd->convert_arg < this_board->ns_min) {
1386 cmd->convert_arg = this_board->ns_min;
1389 } else { /* TRIG_EXT */
1390 if (cmd->convert_arg != 0) {
1391 cmd->convert_arg = 0;
1396 if (cmd->scan_end_arg != cmd->chanlist_len) {
1397 cmd->scan_end_arg = cmd->chanlist_len;
1400 if (cmd->stop_src == TRIG_COUNT) {
1401 if (!cmd->stop_arg) {
1405 } else { /* TRIG_NONE */
1406 if (cmd->stop_arg != 0) {
1416 /* step 4: fix up any arguments */
1418 if (cmd->convert_src == TRIG_TIMER) {
1419 tmp = cmd->convert_arg;
1420 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1421 &divisor2, &cmd->convert_arg,
1422 cmd->flags & TRIG_ROUND_MASK);
1423 if (cmd->convert_arg < this_board->ns_min)
1424 cmd->convert_arg = this_board->ns_min;
1425 if (tmp != cmd->convert_arg)
1433 /* step 5: complain about special chanlist considerations */
1435 if (cmd->chanlist) {
1436 if (!check_channel_list(dev, s, cmd->chanlist,
1438 return 5; /* incorrect channels list */
1445 ==============================================================================
1447 static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1449 struct comedi_cmd *cmd = &s->async->cmd;
1452 printk("pcl818_ai_cmd()\n");
1453 devpriv->ai_n_chan = cmd->chanlist_len;
1454 devpriv->ai_chanlist = cmd->chanlist;
1455 devpriv->ai_flags = cmd->flags;
1456 devpriv->ai_data_len = s->async->prealloc_bufsz;
1457 devpriv->ai_data = s->async->prealloc_buf;
1458 devpriv->ai_timer1 = 0;
1459 devpriv->ai_timer2 = 0;
1461 if (cmd->stop_src == TRIG_COUNT) {
1462 devpriv->ai_scans = cmd->stop_arg;
1464 devpriv->ai_scans = 0;
1467 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */
1468 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */
1469 devpriv->ai_timer1 = cmd->convert_arg;
1470 retval = pcl818_ai_cmd_mode(1, dev, s);
1471 printk("pcl818_ai_cmd() end\n");
1474 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
1475 return pcl818_ai_cmd_mode(3, dev, s);
1483 ==============================================================================
1484 cancel any mode 1-4 AI
1486 static int pcl818_ai_cancel(struct comedi_device *dev,
1487 struct comedi_subdevice *s)
1489 if (devpriv->irq_blocked > 0) {
1490 printk("pcl818_ai_cancel()\n");
1491 devpriv->irq_was_now_closed = 1;
1493 switch (devpriv->ai_mode) {
1495 case INT_TYPE_AI1_DMA_RTC:
1496 case INT_TYPE_AI3_DMA_RTC:
1497 set_rtc_irq_bit(0); /* stop RTC */
1498 del_timer(&devpriv->rtc_irq_timer);
1500 case INT_TYPE_AI1_DMA:
1501 case INT_TYPE_AI3_DMA:
1502 if (devpriv->neverending_ai ||
1503 (!devpriv->neverending_ai &&
1504 devpriv->ai_act_scan > 0)) {
1505 /* wait for running dma transfer to end, do cleanup in interrupt */
1508 disable_dma(devpriv->dma);
1509 case INT_TYPE_AI1_INT:
1510 case INT_TYPE_AI3_INT:
1511 case INT_TYPE_AI1_FIFO:
1512 case INT_TYPE_AI3_FIFO:
1513 #ifdef PCL818_MODE13_AO
1514 case INT_TYPE_AO1_INT:
1515 case INT_TYPE_AO3_INT:
1517 outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */
1519 start_pacer(dev, -1, 0, 0);
1520 outb(0, dev->iobase + PCL818_AD_LO);
1521 inb(dev->iobase + PCL818_AD_LO);
1522 inb(dev->iobase + PCL818_AD_HI);
1523 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
1524 outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */
1525 if (devpriv->usefifo) { /* FIFO shutdown */
1526 outb(0, dev->iobase + PCL818_FI_INTCLR);
1527 outb(0, dev->iobase + PCL818_FI_FLUSH);
1528 outb(0, dev->iobase + PCL818_FI_ENABLE);
1530 devpriv->irq_blocked = 0;
1531 devpriv->last_int_sub = s;
1532 devpriv->neverending_ai = 0;
1533 devpriv->ai_mode = 0;
1534 devpriv->irq_was_now_closed = 0;
1540 printk("pcl818_ai_cancel() end\n");
1545 ==============================================================================
1548 static int pcl818_check(unsigned long iobase)
1550 outb(0x00, iobase + PCL818_MUX);
1552 if (inb(iobase + PCL818_MUX) != 0x00)
1553 return 1; /* there isn't card */
1554 outb(0x55, iobase + PCL818_MUX);
1556 if (inb(iobase + PCL818_MUX) != 0x55)
1557 return 1; /* there isn't card */
1558 outb(0x00, iobase + PCL818_MUX);
1560 outb(0x18, iobase + PCL818_CONTROL);
1562 if (inb(iobase + PCL818_CONTROL) != 0x18)
1563 return 1; /* there isn't card */
1564 return 0; /* ok, card exist */
1568 ==============================================================================
1569 reset whole PCL-818 cards
1571 static void pcl818_reset(struct comedi_device *dev)
1573 if (devpriv->usefifo) { /* FIFO shutdown */
1574 outb(0, dev->iobase + PCL818_FI_INTCLR);
1575 outb(0, dev->iobase + PCL818_FI_FLUSH);
1576 outb(0, dev->iobase + PCL818_FI_ENABLE);
1578 outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */
1579 outb(0, dev->iobase + PCL818_DA_HI);
1581 outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */
1582 outb(0, dev->iobase + PCL818_DO_LO);
1584 outb(0, dev->iobase + PCL818_CONTROL);
1585 outb(0, dev->iobase + PCL818_CNTENABLE);
1586 outb(0, dev->iobase + PCL818_MUX);
1587 outb(0, dev->iobase + PCL818_CLRINT);
1588 outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */
1589 outb(0x70, dev->iobase + PCL818_CTRCTL);
1590 outb(0x30, dev->iobase + PCL818_CTRCTL);
1591 if (this_board->is_818) {
1592 outb(0, dev->iobase + PCL818_RANGE);
1594 outb(0, dev->iobase + PCL718_DA2_LO);
1595 outb(0, dev->iobase + PCL718_DA2_HI);
1601 ==============================================================================
1602 Enable(1)/disable(0) periodic interrupts from RTC
1604 static int set_rtc_irq_bit(unsigned char bit)
1607 unsigned long flags;
1611 if (RTC_timer_lock > 1)
1615 if (RTC_timer_lock < 0)
1617 if (RTC_timer_lock > 0)
1623 val = CMOS_READ(RTC_CONTROL);
1629 CMOS_WRITE(val, RTC_CONTROL);
1630 CMOS_READ(RTC_INTR_FLAGS);
1631 restore_flags(flags);
1636 ==============================================================================
1637 Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers)
1639 static void rtc_dropped_irq(unsigned long data)
1641 struct comedi_device *dev = (void *)data;
1642 unsigned long flags, tmp;
1644 switch (devpriv->int818_mode) {
1645 case INT_TYPE_AI1_DMA_RTC:
1646 case INT_TYPE_AI3_DMA_RTC:
1647 mod_timer(&devpriv->rtc_irq_timer,
1648 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
1651 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */
1652 restore_flags(flags);
1658 ==============================================================================
1659 Set frequency of interrupts from RTC
1661 static int rtc_setfreq_irq(int freq)
1666 unsigned long flags;
1673 while (freq > (1 << tmp))
1676 rtc_freq = 1 << tmp;
1680 val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
1682 CMOS_WRITE(val, RTC_FREQ_SELECT);
1683 restore_flags(flags);
1689 ==============================================================================
1690 Free any resources that we have claimed
1692 static void free_resources(struct comedi_device *dev)
1694 /* printk("free_resource()\n"); */
1696 pcl818_ai_cancel(dev, devpriv->sub_ai);
1699 free_dma(devpriv->dma);
1700 if (devpriv->dmabuf[0])
1701 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1702 if (devpriv->dmabuf[1])
1703 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1705 if (devpriv->rtc_irq)
1706 free_irq(devpriv->rtc_irq, dev);
1707 if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1708 if (devpriv->rtc_iobase)
1709 release_region(devpriv->rtc_iobase,
1710 devpriv->rtc_iosize);
1712 if (devpriv->dma_rtc)
1718 free_irq(dev->irq, dev);
1720 release_region(dev->iobase, devpriv->io_range);
1721 /* printk("free_resource() end\n"); */
1725 ==============================================================================
1730 static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1733 unsigned long iobase;
1736 unsigned long pages;
1737 struct comedi_subdevice *s;
1739 ret = alloc_private(dev, sizeof(struct pcl818_private));
1741 return ret; /* Can't alloc mem */
1743 /* claim our I/O space */
1744 iobase = it->options[0];
1745 printk("comedi%d: pcl818: board=%s, ioport=0x%03lx",
1746 dev->minor, this_board->name, iobase);
1747 devpriv->io_range = this_board->io_range;
1748 if ((this_board->fifo) && (it->options[2] == -1)) { /* we've board with FIFO and we want to use FIFO */
1749 devpriv->io_range = PCLx1xFIFO_RANGE;
1750 devpriv->usefifo = 1;
1752 if (!request_region(iobase, devpriv->io_range, "pcl818")) {
1753 printk("I/O port conflict\n");
1757 dev->iobase = iobase;
1759 if (pcl818_check(iobase)) {
1760 printk(", I can't detect board. FAIL!\n");
1764 /* set up some name stuff */
1765 dev->board_name = this_board->name;
1768 if (this_board->IRQbits != 0) { /* board support IRQ */
1769 irq = it->options[1];
1770 if (irq) { /* we want to use IRQ */
1771 if (((1 << irq) & this_board->IRQbits) == 0) {
1773 (", IRQ %u is out of allowed range, DISABLING IT",
1775 irq = 0; /* Bad IRQ */
1778 (irq, interrupt_pcl818, 0, "pcl818", dev)) {
1780 (", unable to allocate IRQ %u, DISABLING IT",
1782 irq = 0; /* Can't use IRQ */
1784 printk(", irq=%u", irq);
1792 devpriv->irq_free = 1;
1793 } /* 1=we have allocated irq */
1795 devpriv->irq_free = 0;
1797 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
1798 devpriv->ai_mode = 0; /* mode of irq */
1801 /* grab RTC for DMA operations */
1802 devpriv->dma_rtc = 0;
1803 if (it->options[2] > 0) { /* we want to use DMA */
1804 if (RTC_lock == 0) {
1805 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
1809 devpriv->rtc_iobase = RTC_PORT(0);
1810 devpriv->rtc_iosize = RTC_IO_EXTENT;
1812 if (!request_irq(RTC_IRQ, interrupt_pcl818_ai_mode13_dma_rtc, 0,
1813 "pcl818 DMA (RTC)", dev)) {
1814 devpriv->dma_rtc = 1;
1815 devpriv->rtc_irq = RTC_IRQ;
1816 printk(", dma_irq=%u", devpriv->rtc_irq);
1819 if (RTC_lock == 0) {
1820 if (devpriv->rtc_iobase)
1821 release_region(devpriv->rtc_iobase,
1822 devpriv->rtc_iosize);
1824 devpriv->rtc_iobase = 0;
1825 devpriv->rtc_iosize = 0;
1834 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1835 goto no_dma; /* if we haven't IRQ, we can't use DMA */
1836 if (this_board->DMAbits != 0) { /* board support DMA */
1837 dma = it->options[2];
1839 goto no_dma; /* DMA disabled */
1840 if (((1 << dma) & this_board->DMAbits) == 0) {
1841 printk(", DMA is out of allowed range, FAIL!\n");
1842 return -EINVAL; /* Bad DMA */
1844 ret = request_dma(dma, "pcl818");
1846 printk(", unable to allocate DMA %u, FAIL!\n", dma);
1847 return -EBUSY; /* DMA isn't free */
1850 printk(", dma=%u", dma);
1851 pages = 2; /* we need 16KB */
1852 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1853 if (!devpriv->dmabuf[0]) {
1854 printk(", unable to allocate DMA buffer, FAIL!\n");
1855 /* maybe experiment with try_to_free_pages() will help .... */
1856 return -EBUSY; /* no buffer :-( */
1858 devpriv->dmapages[0] = pages;
1859 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1860 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
1861 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
1862 if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */
1863 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1864 if (!devpriv->dmabuf[1]) {
1866 (", unable to allocate DMA buffer, FAIL!\n");
1869 devpriv->dmapages[1] = pages;
1870 devpriv->hwdmaptr[1] =
1871 virt_to_bus((void *)devpriv->dmabuf[1]);
1872 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1878 ret = alloc_subdevices(dev, 4);
1882 s = dev->subdevices + 0;
1883 if (!this_board->n_aichan_se) {
1884 s->type = COMEDI_SUBD_UNUSED;
1886 s->type = COMEDI_SUBD_AI;
1887 devpriv->sub_ai = s;
1888 s->subdev_flags = SDF_READABLE;
1889 if (check_single_ended(dev->iobase)) {
1890 s->n_chan = this_board->n_aichan_se;
1891 s->subdev_flags |= SDF_COMMON | SDF_GROUND;
1892 printk(", %dchans S.E. DAC", s->n_chan);
1894 s->n_chan = this_board->n_aichan_diff;
1895 s->subdev_flags |= SDF_DIFF;
1896 printk(", %dchans DIFF DAC", s->n_chan);
1898 s->maxdata = this_board->ai_maxdata;
1899 s->len_chanlist = s->n_chan;
1900 s->range_table = this_board->ai_range_type;
1901 s->cancel = pcl818_ai_cancel;
1902 s->insn_read = pcl818_ai_insn_read;
1903 if ((irq) || (devpriv->dma_rtc)) {
1904 dev->read_subdev = s;
1905 s->subdev_flags |= SDF_CMD_READ;
1906 s->do_cmdtest = ai_cmdtest;
1909 if (this_board->is_818) {
1910 if ((it->options[4] == 1) || (it->options[4] == 10))
1911 s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */
1913 switch (it->options[4]) {
1915 s->range_table = &range_bipolar10;
1918 s->range_table = &range_bipolar5;
1921 s->range_table = &range_bipolar2_5;
1924 s->range_table = &range718_bipolar1;
1927 s->range_table = &range718_bipolar0_5;
1930 s->range_table = &range_unipolar10;
1933 s->range_table = &range_unipolar5;
1936 s->range_table = &range718_unipolar2;
1939 s->range_table = &range718_unipolar1;
1942 s->range_table = &range_unknown;
1948 s = dev->subdevices + 1;
1949 if (!this_board->n_aochan) {
1950 s->type = COMEDI_SUBD_UNUSED;
1952 s->type = COMEDI_SUBD_AO;
1953 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1954 s->n_chan = this_board->n_aochan;
1955 s->maxdata = this_board->ao_maxdata;
1956 s->len_chanlist = this_board->n_aochan;
1957 s->range_table = this_board->ao_range_type;
1958 s->insn_read = pcl818_ao_insn_read;
1959 s->insn_write = pcl818_ao_insn_write;
1961 #ifdef PCL818_MODE13_AO
1963 s->trig[1] = pcl818_ao_mode1;
1964 s->trig[3] = pcl818_ao_mode3;
1968 if (this_board->is_818) {
1969 if ((it->options[4] == 1) || (it->options[4] == 10))
1970 s->range_table = &range_unipolar10;
1971 if (it->options[4] == 2)
1972 s->range_table = &range_unknown;
1974 if ((it->options[5] == 1) || (it->options[5] == 10))
1975 s->range_table = &range_unipolar10;
1976 if (it->options[5] == 2)
1977 s->range_table = &range_unknown;
1981 s = dev->subdevices + 2;
1982 if (!this_board->n_dichan) {
1983 s->type = COMEDI_SUBD_UNUSED;
1985 s->type = COMEDI_SUBD_DI;
1986 s->subdev_flags = SDF_READABLE;
1987 s->n_chan = this_board->n_dichan;
1989 s->len_chanlist = this_board->n_dichan;
1990 s->range_table = &range_digital;
1991 s->insn_bits = pcl818_di_insn_bits;
1994 s = dev->subdevices + 3;
1995 if (!this_board->n_dochan) {
1996 s->type = COMEDI_SUBD_UNUSED;
1998 s->type = COMEDI_SUBD_DO;
1999 s->subdev_flags = SDF_WRITABLE;
2000 s->n_chan = this_board->n_dochan;
2002 s->len_chanlist = this_board->n_dochan;
2003 s->range_table = &range_digital;
2004 s->insn_bits = pcl818_do_insn_bits;
2007 /* select 1/10MHz oscilator */
2008 if ((it->options[3] == 0) || (it->options[3] == 10)) {
2009 devpriv->i8253_osc_base = 100;
2011 devpriv->i8253_osc_base = 1000;
2014 /* max sampling speed */
2015 devpriv->ns_min = this_board->ns_min;
2017 if (!this_board->is_818) {
2018 if ((it->options[6] == 1) || (it->options[6] == 100))
2019 devpriv->ns_min = 10000; /* extended PCL718 to 100kHz DAC */
2030 ==============================================================================
2033 static int pcl818_detach(struct comedi_device *dev)
2035 /* printk("comedi%d: pcl818: remove\n", dev->minor); */
2036 free_resources(dev);