Staging: comedi: add #include <linux/io.h> to a bunch of drivers
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / comedi / drivers / pcl816.c
blob0b9bee36eb5fabe2070f0aa9db243f1c28f4390d
1 /*
2 comedi/drivers/pcl816.c
4 Author: Juan Grigera <juan@grigera.com.ar>
5 based on pcl818 by Michal Dobes <dobes@tesnet.cz> and bits of pcl812
7 hardware driver for Advantech cards:
8 card: PCL-816, PCL814B
9 driver: pcl816
12 Driver: pcl816
13 Description: Advantech PCL-816 cards, PCL-814
14 Author: Juan Grigera <juan@grigera.com.ar>
15 Devices: [Advantech] PCL-816 (pcl816), PCL-814B (pcl814b)
16 Status: works
17 Updated: Tue, 2 Apr 2002 23:15:21 -0800
19 PCL 816 and 814B have 16 SE/DIFF ADCs, 16 DACs, 16 DI and 16 DO.
20 Differences are at resolution (16 vs 12 bits).
22 The driver support AI command mode, other subdevices not written.
24 Analog output and digital input and output are not supported.
26 Configuration Options:
27 [0] - IO Base
28 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
29 [2] - DMA (0=disable, 1, 3)
30 [3] - 0, 10=10MHz clock for 8254
31 1= 1MHz clock for 8254
35 #include "../comedidev.h"
37 #include <linux/ioport.h>
38 #include <linux/mc146818rtc.h>
39 #include <linux/gfp.h>
40 #include <linux/delay.h>
41 #include <linux/io.h>
42 #include <asm/dma.h>
44 #include "8253.h"
46 #define DEBUG(x) x
48 /* boards constants */
49 /* IO space len */
50 #define PCLx1x_RANGE 16
52 /* #define outb(x,y) printk("OUTB(%x, 200+%d)\n", x,y-0x200); outb(x,y) */
54 /* INTEL 8254 counters */
55 #define PCL816_CTR0 4
56 #define PCL816_CTR1 5
57 #define PCL816_CTR2 6
58 /* R: counter read-back register W: counter control */
59 #define PCL816_CTRCTL 7
61 /* R: A/D high byte W: A/D range control */
62 #define PCL816_RANGE 9
63 /* W: clear INT request */
64 #define PCL816_CLRINT 10
65 /* R: next mux scan channel W: mux scan channel & range control pointer */
66 #define PCL816_MUX 11
67 /* R/W: operation control register */
68 #define PCL816_CONTROL 12
70 /* R: return status byte W: set DMA/IRQ */
71 #define PCL816_STATUS 13
72 #define PCL816_STATUS_DRDY_MASK 0x80
74 /* R: low byte of A/D W: soft A/D trigger */
75 #define PCL816_AD_LO 8
76 /* R: high byte of A/D W: A/D range control */
77 #define PCL816_AD_HI 9
79 /* type of interrupt handler */
80 #define INT_TYPE_AI1_INT 1
81 #define INT_TYPE_AI1_DMA 2
82 #define INT_TYPE_AI3_INT 4
83 #define INT_TYPE_AI3_DMA 5
84 #ifdef unused
85 #define INT_TYPE_AI1_DMA_RTC 9
86 #define INT_TYPE_AI3_DMA_RTC 10
88 /* RTC stuff... */
89 #define RTC_IRQ 8
90 #define RTC_IO_EXTENT 0x10
91 #endif
93 #define MAGIC_DMA_WORD 0x5a5a
95 static const struct comedi_lrange range_pcl816 = { 8, {
96 BIP_RANGE(10),
97 BIP_RANGE(5),
98 BIP_RANGE(2.5),
99 BIP_RANGE(1.25),
100 UNI_RANGE(10),
101 UNI_RANGE(5),
102 UNI_RANGE(2.5),
103 UNI_RANGE(1.25),
107 struct pcl816_board {
109 const char *name; /* board name */
110 int n_ranges; /* len of range list */
111 int n_aichan; /* num of A/D chans in diferencial mode */
112 unsigned int ai_ns_min; /* minimal allowed delay between samples (in ns) */
113 int n_aochan; /* num of D/A chans */
114 int n_dichan; /* num of DI chans */
115 int n_dochan; /* num of DO chans */
116 const struct comedi_lrange *ai_range_type; /* default A/D rangelist */
117 const struct comedi_lrange *ao_range_type; /* default D/A rangelist */
118 unsigned int io_range; /* len of IO space */
119 unsigned int IRQbits; /* allowed interrupts */
120 unsigned int DMAbits; /* allowed DMA chans */
121 int ai_maxdata; /* maxdata for A/D */
122 int ao_maxdata; /* maxdata for D/A */
123 int ai_chanlist; /* allowed len of channel list A/D */
124 int ao_chanlist; /* allowed len of channel list D/A */
125 int i8254_osc_base; /* 1/frequency of on board oscilator in ns */
128 static const struct pcl816_board boardtypes[] = {
129 {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816,
130 &range_pcl816, PCLx1x_RANGE,
131 0x00fc, /* IRQ mask */
132 0x0a, /* DMA mask */
133 0xffff, /* 16-bit card */
134 0xffff, /* D/A maxdata */
135 1024,
136 1, /* ao chan list */
137 100},
138 {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816,
139 &range_pcl816, PCLx1x_RANGE,
140 0x00fc,
141 0x0a,
142 0x3fff, /* 14 bit card */
143 0x3fff,
144 1024,
146 100},
149 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl816_board))
150 #define devpriv ((struct pcl816_private *)dev->private)
151 #define this_board ((const struct pcl816_board *)dev->board_ptr)
153 static int pcl816_attach(struct comedi_device *dev,
154 struct comedi_devconfig *it);
155 static int pcl816_detach(struct comedi_device *dev);
157 #ifdef unused
158 static int RTC_lock = 0; /* RTC lock */
159 static int RTC_timer_lock = 0; /* RTC int lock */
160 #endif
162 static struct comedi_driver driver_pcl816 = {
163 .driver_name = "pcl816",
164 .module = THIS_MODULE,
165 .attach = pcl816_attach,
166 .detach = pcl816_detach,
167 .board_name = &boardtypes[0].name,
168 .num_names = n_boardtypes,
169 .offset = sizeof(struct pcl816_board),
172 static int __init driver_pcl816_init_module(void)
174 return comedi_driver_register(&driver_pcl816);
177 static void __exit driver_pcl816_cleanup_module(void)
179 comedi_driver_unregister(&driver_pcl816);
182 module_init(driver_pcl816_init_module);
183 module_exit(driver_pcl816_cleanup_module);
185 struct pcl816_private {
187 unsigned int dma; /* used DMA, 0=don't use DMA */
188 int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */
189 #ifdef unused
190 unsigned long rtc_iobase; /* RTC port region */
191 unsigned int rtc_iosize;
192 unsigned int rtc_irq;
193 #endif
194 unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
195 unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */
196 unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
197 unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */
198 unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */
199 unsigned int last_top_dma; /* DMA pointer in last RTC int */
200 int next_dma_buf; /* which DMA buffer will be used next round */
201 long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
202 unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
204 unsigned int ai_scans; /* len of scanlist */
205 unsigned char ai_neverending; /* if=1, then we do neverending record (you must use cancel()) */
206 int irq_free; /* 1=have allocated IRQ */
207 int irq_blocked; /* 1=IRQ now uses any subdev */
208 #ifdef unused
209 int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */
210 #endif
211 int irq_was_now_closed; /* when IRQ finish, there's stored int816_mode for last interrupt */
212 int int816_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
213 struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */
214 int ai_act_scan; /* how many scans we finished */
215 unsigned int ai_act_chanlist[16]; /* MUX setting for actual AI operations */
216 unsigned int ai_act_chanlist_len; /* how long is actual MUX list */
217 unsigned int ai_act_chanlist_pos; /* actual position in MUX list */
218 unsigned int ai_n_chan; /* how many channels per scan */
219 unsigned int ai_poll_ptr; /* how many sampes transfer poll */
220 struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */
221 #ifdef unused
222 struct timer_list rtc_irq_timer; /* timer for RTC sanity check */
223 unsigned long rtc_freq; /* RTC int freq */
224 #endif
228 ==============================================================================
230 static int check_channel_list(struct comedi_device *dev,
231 struct comedi_subdevice *s,
232 unsigned int *chanlist, unsigned int chanlen);
233 static void setup_channel_list(struct comedi_device *dev,
234 struct comedi_subdevice *s,
235 unsigned int *chanlist, unsigned int seglen);
236 static int pcl816_ai_cancel(struct comedi_device *dev,
237 struct comedi_subdevice *s);
238 static void start_pacer(struct comedi_device *dev, int mode,
239 unsigned int divisor1, unsigned int divisor2);
240 #ifdef unused
241 static int set_rtc_irq_bit(unsigned char bit);
242 #endif
244 static int pcl816_ai_cmdtest(struct comedi_device *dev,
245 struct comedi_subdevice *s,
246 struct comedi_cmd *cmd);
247 static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
250 ==============================================================================
251 ANALOG INPUT MODE0, 816 cards, slow version
253 static int pcl816_ai_insn_read(struct comedi_device *dev,
254 struct comedi_subdevice *s,
255 struct comedi_insn *insn, unsigned int *data)
257 int n;
258 int timeout;
260 DPRINTK("mode 0 analog input\n");
261 /* software trigger, DMA and INT off */
262 outb(0, dev->iobase + PCL816_CONTROL);
263 /* clear INT (conversion end) flag */
264 outb(0, dev->iobase + PCL816_CLRINT);
266 /* Set the input channel */
267 outb(CR_CHAN(insn->chanspec) & 0xf, dev->iobase + PCL816_MUX);
268 /* select gain */
269 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE);
271 for (n = 0; n < insn->n; n++) {
273 outb(0, dev->iobase + PCL816_AD_LO); /* start conversion */
275 timeout = 100;
276 while (timeout--) {
277 if (!(inb(dev->iobase + PCL816_STATUS) &
278 PCL816_STATUS_DRDY_MASK)) {
279 /* return read value */
280 data[n] =
281 ((inb(dev->iobase +
282 PCL816_AD_HI) << 8) |
283 (inb(dev->iobase + PCL816_AD_LO)));
284 /* clear INT (conversion end) flag */
285 outb(0, dev->iobase + PCL816_CLRINT);
286 break;
288 udelay(1);
290 /* Return timeout error */
291 if (!timeout) {
292 comedi_error(dev, "A/D insn timeout\n");
293 data[0] = 0;
294 /* clear INT (conversion end) flag */
295 outb(0, dev->iobase + PCL816_CLRINT);
296 return -EIO;
300 return n;
304 ==============================================================================
305 analog input interrupt mode 1 & 3, 818 cards
306 one sample per interrupt version
308 static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d)
310 struct comedi_device *dev = d;
311 struct comedi_subdevice *s = dev->subdevices + 0;
312 int low, hi;
313 int timeout = 50; /* wait max 50us */
315 while (timeout--) {
316 if (!(inb(dev->iobase + PCL816_STATUS) &
317 PCL816_STATUS_DRDY_MASK))
318 break;
319 udelay(1);
321 if (!timeout) { /* timeout, bail error */
322 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
323 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
324 pcl816_ai_cancel(dev, s);
325 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
326 comedi_event(dev, s);
327 return IRQ_HANDLED;
331 /* get the sample */
332 low = inb(dev->iobase + PCL816_AD_LO);
333 hi = inb(dev->iobase + PCL816_AD_HI);
335 comedi_buf_put(s->async, (hi << 8) | low);
337 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
339 if (++devpriv->ai_act_chanlist_pos >= devpriv->ai_act_chanlist_len)
340 devpriv->ai_act_chanlist_pos = 0;
342 s->async->cur_chan++;
343 if (s->async->cur_chan >= devpriv->ai_n_chan) {
344 s->async->cur_chan = 0;
345 devpriv->ai_act_scan++;
348 if (!devpriv->ai_neverending)
349 /* all data sampled */
350 if (devpriv->ai_act_scan >= devpriv->ai_scans) {
351 /* all data sampled */
352 pcl816_ai_cancel(dev, s);
353 s->async->events |= COMEDI_CB_EOA;
355 comedi_event(dev, s);
356 return IRQ_HANDLED;
360 ==============================================================================
361 analog input dma mode 1 & 3, 816 cards
363 static void transfer_from_dma_buf(struct comedi_device *dev,
364 struct comedi_subdevice *s, short *ptr,
365 unsigned int bufptr, unsigned int len)
367 int i;
369 s->async->events = 0;
371 for (i = 0; i < len; i++) {
373 comedi_buf_put(s->async, ptr[bufptr++]);
375 if (++devpriv->ai_act_chanlist_pos >=
376 devpriv->ai_act_chanlist_len) {
377 devpriv->ai_act_chanlist_pos = 0;
380 s->async->cur_chan++;
381 if (s->async->cur_chan >= devpriv->ai_n_chan) {
382 s->async->cur_chan = 0;
383 devpriv->ai_act_scan++;
386 if (!devpriv->ai_neverending)
387 /* all data sampled */
388 if (devpriv->ai_act_scan >= devpriv->ai_scans) {
389 pcl816_ai_cancel(dev, s);
390 s->async->events |= COMEDI_CB_EOA;
391 s->async->events |= COMEDI_CB_BLOCK;
392 break;
396 comedi_event(dev, s);
399 static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d)
401 struct comedi_device *dev = d;
402 struct comedi_subdevice *s = dev->subdevices + 0;
403 int len, bufptr, this_dma_buf;
404 unsigned long dma_flags;
405 short *ptr;
407 disable_dma(devpriv->dma);
408 this_dma_buf = devpriv->next_dma_buf;
410 /* switch dma bufs */
411 if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) {
413 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
414 set_dma_mode(devpriv->dma, DMA_MODE_READ);
415 dma_flags = claim_dma_lock();
416 /* clear_dma_ff (devpriv->dma); */
417 set_dma_addr(devpriv->dma,
418 devpriv->hwdmaptr[devpriv->next_dma_buf]);
419 if (devpriv->dma_runs_to_end) {
420 set_dma_count(devpriv->dma,
421 devpriv->hwdmasize[devpriv->
422 next_dma_buf]);
423 } else {
424 set_dma_count(devpriv->dma, devpriv->last_dma_run);
426 release_dma_lock(dma_flags);
427 enable_dma(devpriv->dma);
430 devpriv->dma_runs_to_end--;
431 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
433 ptr = (short *)devpriv->dmabuf[this_dma_buf];
435 len = (devpriv->hwdmasize[0] >> 1) - devpriv->ai_poll_ptr;
436 bufptr = devpriv->ai_poll_ptr;
437 devpriv->ai_poll_ptr = 0;
439 transfer_from_dma_buf(dev, s, ptr, bufptr, len);
440 return IRQ_HANDLED;
444 ==============================================================================
445 INT procedure
447 static irqreturn_t interrupt_pcl816(int irq, void *d)
449 struct comedi_device *dev = d;
450 DPRINTK("<I>");
452 if (!dev->attached) {
453 comedi_error(dev, "premature interrupt");
454 return IRQ_HANDLED;
457 switch (devpriv->int816_mode) {
458 case INT_TYPE_AI1_DMA:
459 case INT_TYPE_AI3_DMA:
460 return interrupt_pcl816_ai_mode13_dma(irq, d);
461 case INT_TYPE_AI1_INT:
462 case INT_TYPE_AI3_INT:
463 return interrupt_pcl816_ai_mode13_int(irq, d);
466 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
467 if ((!dev->irq) | (!devpriv->irq_free) | (!devpriv->irq_blocked) |
468 (!devpriv->int816_mode)) {
469 if (devpriv->irq_was_now_closed) {
470 devpriv->irq_was_now_closed = 0;
471 /* comedi_error(dev,"last IRQ.."); */
472 return IRQ_HANDLED;
474 comedi_error(dev, "bad IRQ!");
475 return IRQ_NONE;
477 comedi_error(dev, "IRQ from unknown source!");
478 return IRQ_NONE;
482 ==============================================================================
483 COMMAND MODE
485 static void pcl816_cmdtest_out(int e, struct comedi_cmd *cmd)
487 printk(KERN_INFO "pcl816 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
488 cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
489 printk(KERN_INFO "pcl816 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
490 cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
491 printk(KERN_INFO "pcl816 e=%d stopsrc=%x scanend=%x\n", e,
492 cmd->stop_src, cmd->scan_end_src);
493 printk(KERN_INFO "pcl816 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
494 e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
498 ==============================================================================
500 static int pcl816_ai_cmdtest(struct comedi_device *dev,
501 struct comedi_subdevice *s, struct comedi_cmd *cmd)
503 int err = 0;
504 int tmp, divisor1 = 0, divisor2 = 0;
506 DEBUG(printk(KERN_INFO "pcl816 pcl812_ai_cmdtest\n");
507 pcl816_cmdtest_out(-1, cmd);
510 /* step 1: make sure trigger sources are trivially valid */
511 tmp = cmd->start_src;
512 cmd->start_src &= TRIG_NOW;
513 if (!cmd->start_src || tmp != cmd->start_src)
514 err++;
516 tmp = cmd->scan_begin_src;
517 cmd->scan_begin_src &= TRIG_FOLLOW;
518 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
519 err++;
521 tmp = cmd->convert_src;
522 cmd->convert_src &= TRIG_EXT | TRIG_TIMER;
523 if (!cmd->convert_src || tmp != cmd->convert_src)
524 err++;
526 tmp = cmd->scan_end_src;
527 cmd->scan_end_src &= TRIG_COUNT;
528 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
529 err++;
531 tmp = cmd->stop_src;
532 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
533 if (!cmd->stop_src || tmp != cmd->stop_src)
534 err++;
536 if (err)
537 return 1;
541 * step 2: make sure trigger sources
542 * are unique and mutually compatible
545 if (cmd->start_src != TRIG_NOW) {
546 cmd->start_src = TRIG_NOW;
547 err++;
550 if (cmd->scan_begin_src != TRIG_FOLLOW) {
551 cmd->scan_begin_src = TRIG_FOLLOW;
552 err++;
555 if (cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_TIMER) {
556 cmd->convert_src = TRIG_TIMER;
557 err++;
560 if (cmd->scan_end_src != TRIG_COUNT) {
561 cmd->scan_end_src = TRIG_COUNT;
562 err++;
565 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
566 err++;
568 if (err)
569 return 2;
572 /* step 3: make sure arguments are trivially compatible */
573 if (cmd->start_arg != 0) {
574 cmd->start_arg = 0;
575 err++;
578 if (cmd->scan_begin_arg != 0) {
579 cmd->scan_begin_arg = 0;
580 err++;
582 if (cmd->convert_src == TRIG_TIMER) {
583 if (cmd->convert_arg < this_board->ai_ns_min) {
584 cmd->convert_arg = this_board->ai_ns_min;
585 err++;
587 } else { /* TRIG_EXT */
588 if (cmd->convert_arg != 0) {
589 cmd->convert_arg = 0;
590 err++;
594 if (cmd->scan_end_arg != cmd->chanlist_len) {
595 cmd->scan_end_arg = cmd->chanlist_len;
596 err++;
598 if (cmd->stop_src == TRIG_COUNT) {
599 if (!cmd->stop_arg) {
600 cmd->stop_arg = 1;
601 err++;
603 } else { /* TRIG_NONE */
604 if (cmd->stop_arg != 0) {
605 cmd->stop_arg = 0;
606 err++;
610 if (err)
611 return 3;
614 /* step 4: fix up any arguments */
615 if (cmd->convert_src == TRIG_TIMER) {
616 tmp = cmd->convert_arg;
617 i8253_cascade_ns_to_timer(this_board->i8254_osc_base,
618 &divisor1, &divisor2,
619 &cmd->convert_arg,
620 cmd->flags & TRIG_ROUND_MASK);
621 if (cmd->convert_arg < this_board->ai_ns_min)
622 cmd->convert_arg = this_board->ai_ns_min;
623 if (tmp != cmd->convert_arg)
624 err++;
627 if (err)
628 return 4;
631 /* step 5: complain about special chanlist considerations */
633 if (cmd->chanlist) {
634 if (!check_channel_list(dev, s, cmd->chanlist,
635 cmd->chanlist_len))
636 return 5; /* incorrect channels list */
639 return 0;
642 static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
644 unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq;
645 struct comedi_cmd *cmd = &s->async->cmd;
646 unsigned int seglen;
648 if (cmd->start_src != TRIG_NOW)
649 return -EINVAL;
650 if (cmd->scan_begin_src != TRIG_FOLLOW)
651 return -EINVAL;
652 if (cmd->scan_end_src != TRIG_COUNT)
653 return -EINVAL;
654 if (cmd->scan_end_arg != cmd->chanlist_len)
655 return -EINVAL;
656 /* if(cmd->chanlist_len>MAX_CHANLIST_LEN) return -EINVAL; */
657 if (devpriv->irq_blocked)
658 return -EBUSY;
660 if (cmd->convert_src == TRIG_TIMER) {
661 if (cmd->convert_arg < this_board->ai_ns_min)
662 cmd->convert_arg = this_board->ai_ns_min;
664 i8253_cascade_ns_to_timer(this_board->i8254_osc_base, &divisor1,
665 &divisor2, &cmd->convert_arg,
666 cmd->flags & TRIG_ROUND_MASK);
668 /* PCL816 crash if any divisor is set to 1 */
669 if (divisor1 == 1) {
670 divisor1 = 2;
671 divisor2 /= 2;
673 if (divisor2 == 1) {
674 divisor2 = 2;
675 divisor1 /= 2;
679 start_pacer(dev, -1, 0, 0); /* stop pacer */
681 seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len);
682 if (seglen < 1)
683 return -EINVAL;
684 setup_channel_list(dev, s, cmd->chanlist, seglen);
685 udelay(1);
687 devpriv->ai_n_chan = cmd->chanlist_len;
688 devpriv->ai_act_scan = 0;
689 s->async->cur_chan = 0;
690 devpriv->irq_blocked = 1;
691 devpriv->ai_poll_ptr = 0;
692 devpriv->irq_was_now_closed = 0;
694 if (cmd->stop_src == TRIG_COUNT) {
695 devpriv->ai_scans = cmd->stop_arg;
696 devpriv->ai_neverending = 0;
697 } else {
698 devpriv->ai_scans = 0;
699 devpriv->ai_neverending = 1;
702 /* don't we want wake up every scan? */
703 if ((cmd->flags & TRIG_WAKE_EOS)) {
704 printk(KERN_INFO
705 "pl816: You wankt WAKE_EOS but I dont want handle it");
706 /* devpriv->ai_eos=1; */
707 /* if (devpriv->ai_n_chan==1) */
708 /* devpriv->dma=0; // DMA is useless for this situation */
711 if (devpriv->dma) {
712 bytes = devpriv->hwdmasize[0];
713 if (!devpriv->ai_neverending) {
714 /* how many */
715 bytes = s->async->cmd.chanlist_len *
716 s->async->cmd.chanlist_len *
717 sizeof(short);
719 /* how many DMA pages we must fill */
720 devpriv->dma_runs_to_end = bytes /
721 devpriv->hwdmasize[0];
723 /* on last dma transfer must be moved */
724 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0];
725 devpriv->dma_runs_to_end--;
726 if (devpriv->dma_runs_to_end >= 0)
727 bytes = devpriv->hwdmasize[0];
728 } else
729 devpriv->dma_runs_to_end = -1;
731 devpriv->next_dma_buf = 0;
732 set_dma_mode(devpriv->dma, DMA_MODE_READ);
733 dma_flags = claim_dma_lock();
734 clear_dma_ff(devpriv->dma);
735 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
736 set_dma_count(devpriv->dma, bytes);
737 release_dma_lock(dma_flags);
738 enable_dma(devpriv->dma);
741 start_pacer(dev, 1, divisor1, divisor2);
742 dmairq = ((devpriv->dma & 0x3) << 4) | (dev->irq & 0x7);
744 switch (cmd->convert_src) {
745 case TRIG_TIMER:
746 devpriv->int816_mode = INT_TYPE_AI1_DMA;
748 /* Pacer+IRQ+DMA */
749 outb(0x32, dev->iobase + PCL816_CONTROL);
751 /* write irq and DMA to card */
752 outb(dmairq, dev->iobase + PCL816_STATUS);
753 break;
755 default:
756 devpriv->int816_mode = INT_TYPE_AI3_DMA;
758 /* Ext trig+IRQ+DMA */
759 outb(0x34, dev->iobase + PCL816_CONTROL);
761 /* write irq to card */
762 outb(dmairq, dev->iobase + PCL816_STATUS);
763 break;
766 DPRINTK("pcl816 END: pcl812_ai_cmd()\n");
767 return 0;
770 static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
772 unsigned long flags;
773 unsigned int top1, top2, i;
775 if (!devpriv->dma)
776 return 0; /* poll is valid only for DMA transfer */
778 spin_lock_irqsave(&dev->spinlock, flags);
780 for (i = 0; i < 20; i++) {
781 top1 = get_dma_residue(devpriv->dma); /* where is now DMA */
782 top2 = get_dma_residue(devpriv->dma);
783 if (top1 == top2)
784 break;
786 if (top1 != top2) {
787 spin_unlock_irqrestore(&dev->spinlock, flags);
788 return 0;
791 /* where is now DMA in buffer */
792 top1 = devpriv->hwdmasize[0] - top1;
793 top1 >>= 1; /* sample position */
794 top2 = top1 - devpriv->ai_poll_ptr;
795 if (top2 < 1) { /* no new samples */
796 spin_unlock_irqrestore(&dev->spinlock, flags);
797 return 0;
800 transfer_from_dma_buf(dev, s,
801 (short *)devpriv->dmabuf[devpriv->next_dma_buf],
802 devpriv->ai_poll_ptr, top2);
804 devpriv->ai_poll_ptr = top1; /* new buffer position */
805 spin_unlock_irqrestore(&dev->spinlock, flags);
807 return s->async->buf_write_count - s->async->buf_read_count;
811 ==============================================================================
812 cancel any mode 1-4 AI
814 static int pcl816_ai_cancel(struct comedi_device *dev,
815 struct comedi_subdevice *s)
817 /* DEBUG(printk("pcl816_ai_cancel()\n");) */
819 if (devpriv->irq_blocked > 0) {
820 switch (devpriv->int816_mode) {
821 #ifdef unused
822 case INT_TYPE_AI1_DMA_RTC:
823 case INT_TYPE_AI3_DMA_RTC:
824 set_rtc_irq_bit(0); /* stop RTC */
825 del_timer(&devpriv->rtc_irq_timer);
826 #endif
827 case INT_TYPE_AI1_DMA:
828 case INT_TYPE_AI3_DMA:
829 disable_dma(devpriv->dma);
830 case INT_TYPE_AI1_INT:
831 case INT_TYPE_AI3_INT:
832 outb(inb(dev->iobase + PCL816_CONTROL) & 0x73,
833 dev->iobase + PCL816_CONTROL); /* Stop A/D */
834 udelay(1);
835 outb(0, dev->iobase + PCL816_CONTROL); /* Stop A/D */
837 /* Stop pacer */
838 outb(0xb0, dev->iobase + PCL816_CTRCTL);
839 outb(0x70, dev->iobase + PCL816_CTRCTL);
840 outb(0, dev->iobase + PCL816_AD_LO);
841 inb(dev->iobase + PCL816_AD_LO);
842 inb(dev->iobase + PCL816_AD_HI);
844 /* clear INT request */
845 outb(0, dev->iobase + PCL816_CLRINT);
847 /* Stop A/D */
848 outb(0, dev->iobase + PCL816_CONTROL);
849 devpriv->irq_blocked = 0;
850 devpriv->irq_was_now_closed = devpriv->int816_mode;
851 devpriv->int816_mode = 0;
852 devpriv->last_int_sub = s;
853 /* s->busy = 0; */
854 break;
858 DEBUG(printk("comedi: pcl816_ai_cancel() successful\n");)
859 return 0;
863 ==============================================================================
864 chech for PCL816
866 static int pcl816_check(unsigned long iobase)
868 outb(0x00, iobase + PCL816_MUX);
869 udelay(1);
870 if (inb(iobase + PCL816_MUX) != 0x00)
871 return 1; /* there isn't card */
872 outb(0x55, iobase + PCL816_MUX);
873 udelay(1);
874 if (inb(iobase + PCL816_MUX) != 0x55)
875 return 1; /* there isn't card */
876 outb(0x00, iobase + PCL816_MUX);
877 udelay(1);
878 outb(0x18, iobase + PCL816_CONTROL);
879 udelay(1);
880 if (inb(iobase + PCL816_CONTROL) != 0x18)
881 return 1; /* there isn't card */
882 return 0; /* ok, card exist */
886 ==============================================================================
887 reset whole PCL-816 cards
889 static void pcl816_reset(struct comedi_device *dev)
891 /* outb (0, dev->iobase + PCL818_DA_LO); DAC=0V */
892 /* outb (0, dev->iobase + PCL818_DA_HI); */
893 /* udelay (1); */
894 /* outb (0, dev->iobase + PCL818_DO_HI); DO=$0000 */
895 /* outb (0, dev->iobase + PCL818_DO_LO); */
896 /* udelay (1); */
897 outb(0, dev->iobase + PCL816_CONTROL);
898 outb(0, dev->iobase + PCL816_MUX);
899 outb(0, dev->iobase + PCL816_CLRINT);
900 outb(0xb0, dev->iobase + PCL816_CTRCTL); /* Stop pacer */
901 outb(0x70, dev->iobase + PCL816_CTRCTL);
902 outb(0x30, dev->iobase + PCL816_CTRCTL);
903 outb(0, dev->iobase + PCL816_RANGE);
907 ==============================================================================
908 Start/stop pacer onboard pacer
910 static void
911 start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1,
912 unsigned int divisor2)
914 outb(0x32, dev->iobase + PCL816_CTRCTL);
915 outb(0xff, dev->iobase + PCL816_CTR0);
916 outb(0x00, dev->iobase + PCL816_CTR0);
917 udelay(1);
919 /* set counter 2 as mode 3 */
920 outb(0xb4, dev->iobase + PCL816_CTRCTL);
921 /* set counter 1 as mode 3 */
922 outb(0x74, dev->iobase + PCL816_CTRCTL);
923 udelay(1);
925 if (mode == 1) {
926 DPRINTK("mode %d, divisor1 %d, divisor2 %d\n", mode, divisor1,
927 divisor2);
928 outb(divisor2 & 0xff, dev->iobase + PCL816_CTR2);
929 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL816_CTR2);
930 outb(divisor1 & 0xff, dev->iobase + PCL816_CTR1);
931 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL816_CTR1);
934 /* clear pending interrupts (just in case) */
935 /* outb(0, dev->iobase + PCL816_CLRINT); */
939 ==============================================================================
940 Check if channel list from user is builded correctly
941 If it's ok, then return non-zero length of repeated segment of channel list
943 static int
944 check_channel_list(struct comedi_device *dev,
945 struct comedi_subdevice *s, unsigned int *chanlist,
946 unsigned int chanlen)
948 unsigned int chansegment[16];
949 unsigned int i, nowmustbechan, seglen, segpos;
951 /* correct channel and range number check itself comedi/range.c */
952 if (chanlen < 1) {
953 comedi_error(dev, "range/channel list is empty!");
954 return 0;
957 if (chanlen > 1) {
958 /* first channel is every time ok */
959 chansegment[0] = chanlist[0];
960 for (i = 1, seglen = 1; i < chanlen; i++, seglen++) {
961 /* build part of chanlist */
962 DEBUG(printk(KERN_INFO "%d. %d %d\n", i,
963 CR_CHAN(chanlist[i]),
964 CR_RANGE(chanlist[i]));)
966 /* we detect loop, this must by finish */
967 if (chanlist[0] == chanlist[i])
968 break;
969 nowmustbechan =
970 (CR_CHAN(chansegment[i - 1]) + 1) % chanlen;
971 if (nowmustbechan != CR_CHAN(chanlist[i])) {
972 /* channel list isn't continuous :-( */
973 printk(KERN_WARNING
974 "comedi%d: pcl816: channel list must "
975 "be continuous! chanlist[%i]=%d but "
976 "must be %d or %d!\n", dev->minor,
977 i, CR_CHAN(chanlist[i]), nowmustbechan,
978 CR_CHAN(chanlist[0]));
979 return 0;
981 /* well, this is next correct channel in list */
982 chansegment[i] = chanlist[i];
985 /* check whole chanlist */
986 for (i = 0, segpos = 0; i < chanlen; i++) {
987 DEBUG(printk("%d %d=%d %d\n",
988 CR_CHAN(chansegment[i % seglen]),
989 CR_RANGE(chansegment[i % seglen]),
990 CR_CHAN(chanlist[i]),
991 CR_RANGE(chanlist[i]));)
992 if (chanlist[i] != chansegment[i % seglen]) {
993 printk(KERN_WARNING
994 "comedi%d: pcl816: bad channel or range"
995 " number! chanlist[%i]=%d,%d,%d and not"
996 " %d,%d,%d!\n", dev->minor, i,
997 CR_CHAN(chansegment[i]),
998 CR_RANGE(chansegment[i]),
999 CR_AREF(chansegment[i]),
1000 CR_CHAN(chanlist[i % seglen]),
1001 CR_RANGE(chanlist[i % seglen]),
1002 CR_AREF(chansegment[i % seglen]));
1003 return 0; /* chan/gain list is strange */
1006 } else {
1007 seglen = 1;
1010 return seglen; /* we can serve this with MUX logic */
1014 ==============================================================================
1015 Program scan/gain logic with channel list.
1017 static void
1018 setup_channel_list(struct comedi_device *dev,
1019 struct comedi_subdevice *s, unsigned int *chanlist,
1020 unsigned int seglen)
1022 unsigned int i;
1024 devpriv->ai_act_chanlist_len = seglen;
1025 devpriv->ai_act_chanlist_pos = 0;
1027 for (i = 0; i < seglen; i++) { /* store range list to card */
1028 devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]);
1029 outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX);
1030 /* select gain */
1031 outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE);
1034 udelay(1);
1035 /* select channel interval to scan */
1036 outb(devpriv->ai_act_chanlist[0] |
1037 (devpriv->ai_act_chanlist[seglen - 1] << 4),
1038 dev->iobase + PCL816_MUX);
1041 #ifdef unused
1043 ==============================================================================
1044 Enable(1)/disable(0) periodic interrupts from RTC
1046 static int set_rtc_irq_bit(unsigned char bit)
1048 unsigned char val;
1049 unsigned long flags;
1051 if (bit == 1) {
1052 RTC_timer_lock++;
1053 if (RTC_timer_lock > 1)
1054 return 0;
1055 } else {
1056 RTC_timer_lock--;
1057 if (RTC_timer_lock < 0)
1058 RTC_timer_lock = 0;
1059 if (RTC_timer_lock > 0)
1060 return 0;
1063 save_flags(flags);
1064 cli();
1065 val = CMOS_READ(RTC_CONTROL);
1066 if (bit)
1067 val |= RTC_PIE;
1068 else
1069 val &= ~RTC_PIE;
1071 CMOS_WRITE(val, RTC_CONTROL);
1072 CMOS_READ(RTC_INTR_FLAGS);
1073 restore_flags(flags);
1074 return 0;
1076 #endif
1079 ==============================================================================
1080 Free any resources that we have claimed
1082 static void free_resources(struct comedi_device *dev)
1084 /* printk("free_resource()\n"); */
1085 if (dev->private) {
1086 pcl816_ai_cancel(dev, devpriv->sub_ai);
1087 pcl816_reset(dev);
1088 if (devpriv->dma)
1089 free_dma(devpriv->dma);
1090 if (devpriv->dmabuf[0])
1091 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1092 if (devpriv->dmabuf[1])
1093 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1094 #ifdef unused
1095 if (devpriv->rtc_irq)
1096 free_irq(devpriv->rtc_irq, dev);
1097 if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1098 if (devpriv->rtc_iobase)
1099 release_region(devpriv->rtc_iobase,
1100 devpriv->rtc_iosize);
1102 #endif
1105 if (dev->irq)
1106 free_irq(dev->irq, dev);
1107 if (dev->iobase)
1108 release_region(dev->iobase, this_board->io_range);
1109 /* printk("free_resource() end\n"); */
1113 ==============================================================================
1115 Initialization
1118 static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1120 int ret;
1121 unsigned long iobase;
1122 unsigned int irq, dma;
1123 unsigned long pages;
1124 /* int i; */
1125 struct comedi_subdevice *s;
1127 /* claim our I/O space */
1128 iobase = it->options[0];
1129 printk("comedi%d: pcl816: board=%s, ioport=0x%03lx", dev->minor,
1130 this_board->name, iobase);
1132 if (!request_region(iobase, this_board->io_range, "pcl816")) {
1133 printk("I/O port conflict\n");
1134 return -EIO;
1137 dev->iobase = iobase;
1139 if (pcl816_check(iobase)) {
1140 printk(KERN_ERR ", I cann't detect board. FAIL!\n");
1141 return -EIO;
1144 ret = alloc_private(dev, sizeof(struct pcl816_private));
1145 if (ret < 0)
1146 return ret; /* Can't alloc mem */
1148 /* set up some name stuff */
1149 dev->board_name = this_board->name;
1151 /* grab our IRQ */
1152 irq = 0;
1153 if (this_board->IRQbits != 0) { /* board support IRQ */
1154 irq = it->options[1];
1155 if (irq) { /* we want to use IRQ */
1156 if (((1 << irq) & this_board->IRQbits) == 0) {
1157 printk
1158 (", IRQ %u is out of allowed range, "
1159 "DISABLING IT", irq);
1160 irq = 0; /* Bad IRQ */
1161 } else {
1162 if (request_irq
1163 (irq, interrupt_pcl816, 0, "pcl816", dev)) {
1164 printk
1165 (", unable to allocate IRQ %u, "
1166 "DISABLING IT", irq);
1167 irq = 0; /* Can't use IRQ */
1168 } else {
1169 printk(KERN_INFO ", irq=%u", irq);
1175 dev->irq = irq;
1176 if (irq) /* 1=we have allocated irq */
1177 devpriv->irq_free = 1;
1178 else
1179 devpriv->irq_free = 0;
1181 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
1182 devpriv->int816_mode = 0; /* mode of irq */
1184 #ifdef unused
1185 /* grab RTC for DMA operations */
1186 devpriv->dma_rtc = 0;
1187 if (it->options[2] > 0) { /* we want to use DMA */
1188 if (RTC_lock == 0) {
1189 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
1190 "pcl816 (RTC)"))
1191 goto no_rtc;
1193 devpriv->rtc_iobase = RTC_PORT(0);
1194 devpriv->rtc_iosize = RTC_IO_EXTENT;
1195 RTC_lock++;
1196 #ifdef UNTESTED_CODE
1197 if (!request_irq(RTC_IRQ, interrupt_pcl816_ai_mode13_dma_rtc, 0,
1198 "pcl816 DMA (RTC)", dev)) {
1199 devpriv->dma_rtc = 1;
1200 devpriv->rtc_irq = RTC_IRQ;
1201 printk(", dma_irq=%u", devpriv->rtc_irq);
1202 } else {
1203 RTC_lock--;
1204 if (RTC_lock == 0) {
1205 if (devpriv->rtc_iobase)
1206 release_region(devpriv->rtc_iobase,
1207 devpriv->rtc_iosize);
1209 devpriv->rtc_iobase = 0;
1210 devpriv->rtc_iosize = 0;
1212 #else
1213 printk("pcl816: RTC code missing");
1214 #endif
1218 no_rtc:
1219 #endif
1220 /* grab our DMA */
1221 dma = 0;
1222 devpriv->dma = dma;
1223 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1224 goto no_dma; /* if we haven't IRQ, we can't use DMA */
1226 if (this_board->DMAbits != 0) { /* board support DMA */
1227 dma = it->options[2];
1228 if (dma < 1)
1229 goto no_dma; /* DMA disabled */
1231 if (((1 << dma) & this_board->DMAbits) == 0) {
1232 printk(", DMA is out of allowed range, FAIL!\n");
1233 return -EINVAL; /* Bad DMA */
1235 ret = request_dma(dma, "pcl816");
1236 if (ret) {
1237 printk(KERN_ERR
1238 ", unable to allocate DMA %u, FAIL!\n", dma);
1239 return -EBUSY; /* DMA isn't free */
1242 devpriv->dma = dma;
1243 printk(KERN_INFO ", dma=%u", dma);
1244 pages = 2; /* we need 16KB */
1245 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1247 if (!devpriv->dmabuf[0]) {
1248 printk(", unable to allocate DMA buffer, FAIL!\n");
1250 * maybe experiment with try_to_free_pages()
1251 * will help ....
1253 return -EBUSY; /* no buffer :-( */
1255 devpriv->dmapages[0] = pages;
1256 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1257 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
1258 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
1260 if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */
1261 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1262 if (!devpriv->dmabuf[1]) {
1263 printk(KERN_ERR
1264 ", unable to allocate DMA buffer, "
1265 "FAIL!\n");
1266 return -EBUSY;
1268 devpriv->dmapages[1] = pages;
1269 devpriv->hwdmaptr[1] =
1270 virt_to_bus((void *)devpriv->dmabuf[1]);
1271 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1275 no_dma:
1277 /* if (this_board->n_aochan > 0)
1278 subdevs[1] = COMEDI_SUBD_AO;
1279 if (this_board->n_dichan > 0)
1280 subdevs[2] = COMEDI_SUBD_DI;
1281 if (this_board->n_dochan > 0)
1282 subdevs[3] = COMEDI_SUBD_DO;
1285 ret = alloc_subdevices(dev, 1);
1286 if (ret < 0)
1287 return ret;
1289 s = dev->subdevices + 0;
1290 if (this_board->n_aichan > 0) {
1291 s->type = COMEDI_SUBD_AI;
1292 devpriv->sub_ai = s;
1293 dev->read_subdev = s;
1294 s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
1295 s->n_chan = this_board->n_aichan;
1296 s->subdev_flags |= SDF_DIFF;
1297 /* printk (", %dchans DIFF DAC - %d", s->n_chan, i); */
1298 s->maxdata = this_board->ai_maxdata;
1299 s->len_chanlist = this_board->ai_chanlist;
1300 s->range_table = this_board->ai_range_type;
1301 s->cancel = pcl816_ai_cancel;
1302 s->do_cmdtest = pcl816_ai_cmdtest;
1303 s->do_cmd = pcl816_ai_cmd;
1304 s->poll = pcl816_ai_poll;
1305 s->insn_read = pcl816_ai_insn_read;
1306 } else {
1307 s->type = COMEDI_SUBD_UNUSED;
1310 #if 0
1311 case COMEDI_SUBD_AO:
1312 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1313 s->n_chan = this_board->n_aochan;
1314 s->maxdata = this_board->ao_maxdata;
1315 s->len_chanlist = this_board->ao_chanlist;
1316 s->range_table = this_board->ao_range_type;
1317 break;
1319 case COMEDI_SUBD_DI:
1320 s->subdev_flags = SDF_READABLE;
1321 s->n_chan = this_board->n_dichan;
1322 s->maxdata = 1;
1323 s->len_chanlist = this_board->n_dichan;
1324 s->range_table = &range_digital;
1325 break;
1327 case COMEDI_SUBD_DO:
1328 s->subdev_flags = SDF_WRITABLE;
1329 s->n_chan = this_board->n_dochan;
1330 s->maxdata = 1;
1331 s->len_chanlist = this_board->n_dochan;
1332 s->range_table = &range_digital;
1333 break;
1334 #endif
1336 pcl816_reset(dev);
1338 printk("\n");
1340 return 0;
1344 ==============================================================================
1345 Removes device
1347 static int pcl816_detach(struct comedi_device *dev)
1349 DEBUG(printk(KERN_INFO "comedi%d: pcl816: remove\n", dev->minor);)
1350 free_resources(dev);
1351 #ifdef unused
1352 if (devpriv->dma_rtc)
1353 RTC_lock--;
1354 #endif
1355 return 0;
1358 MODULE_AUTHOR("Comedi http://www.comedi.org");
1359 MODULE_DESCRIPTION("Comedi low-level driver");
1360 MODULE_LICENSE("GPL");