10e09609924d536bb1b6b0db76cc6ac92e4c9972
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / comedi / drivers / pcl816.c
1 /*
2 comedi/drivers/pcl816.c
3
4 Author: Juan Grigera <juan@grigera.com.ar>
5 based on pcl818 by Michal Dobes <dobes@tesnet.cz> and bits of pcl812
6
7 hardware driver for Advantech cards:
8 card: PCL-816, PCL814B
9 driver: pcl816
10 */
11 /*
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
18
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).
21
22 The driver support AI command mode, other subdevices not written.
23
24 Analog output and digital input and output are not supported.
25
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
32
33 */
34
35 #include "../comedidev.h"
36
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>
43
44 #include "comedi_fc.h"
45 #include "8253.h"
46
47 #define DEBUG(x) x
48
49 /* boards constants */
50 /* IO space len */
51 #define PCLx1x_RANGE 16
52
53 /* #define outb(x,y) printk("OUTB(%x, 200+%d)\n", x,y-0x200); outb(x,y) */
54
55 /* INTEL 8254 counters */
56 #define PCL816_CTR0 4
57 #define PCL816_CTR1 5
58 #define PCL816_CTR2 6
59 /* R: counter read-back register W: counter control */
60 #define PCL816_CTRCTL 7
61
62 /* R: A/D high byte W: A/D range control */
63 #define PCL816_RANGE 9
64 /* W: clear INT request */
65 #define PCL816_CLRINT 10
66 /* R: next mux scan channel W: mux scan channel & range control pointer */
67 #define PCL816_MUX 11
68 /* R/W: operation control register */
69 #define PCL816_CONTROL 12
70
71 /* R: return status byte W: set DMA/IRQ */
72 #define PCL816_STATUS 13
73 #define PCL816_STATUS_DRDY_MASK 0x80
74
75 /* R: low byte of A/D W: soft A/D trigger */
76 #define PCL816_AD_LO 8
77 /* R: high byte of A/D W: A/D range control */
78 #define PCL816_AD_HI 9
79
80 /* type of interrupt handler */
81 #define INT_TYPE_AI1_INT 1
82 #define INT_TYPE_AI1_DMA 2
83 #define INT_TYPE_AI3_INT 4
84 #define INT_TYPE_AI3_DMA 5
85 #ifdef unused
86 #define INT_TYPE_AI1_DMA_RTC 9
87 #define INT_TYPE_AI3_DMA_RTC 10
88
89 /* RTC stuff... */
90 #define RTC_IRQ 8
91 #define RTC_IO_EXTENT 0x10
92 #endif
93
94 #define MAGIC_DMA_WORD 0x5a5a
95
96 static const struct comedi_lrange range_pcl816 = { 8, {
97 BIP_RANGE(10),
98 BIP_RANGE(5),
99 BIP_RANGE(2.5),
100 BIP_RANGE(1.25),
101 UNI_RANGE(10),
102 UNI_RANGE(5),
103 UNI_RANGE(2.5),
104 UNI_RANGE(1.25),
105 }
106 };
107
108 struct pcl816_board {
109
110 const char *name; /* board name */
111 int n_ranges; /* len of range list */
112 int n_aichan; /* num of A/D chans in diferencial mode */
113 unsigned int ai_ns_min; /* minimal allowed delay between samples (in ns) */
114 int n_aochan; /* num of D/A chans */
115 int n_dichan; /* num of DI chans */
116 int n_dochan; /* num of DO chans */
117 const struct comedi_lrange *ai_range_type; /* default A/D rangelist */
118 const struct comedi_lrange *ao_range_type; /* default D/A rangelist */
119 unsigned int io_range; /* len of IO space */
120 unsigned int IRQbits; /* allowed interrupts */
121 unsigned int DMAbits; /* allowed DMA chans */
122 int ai_maxdata; /* maxdata for A/D */
123 int ao_maxdata; /* maxdata for D/A */
124 int ai_chanlist; /* allowed len of channel list A/D */
125 int ao_chanlist; /* allowed len of channel list D/A */
126 int i8254_osc_base; /* 1/frequency of on board oscilator in ns */
127 };
128
129 #ifdef unused
130 static int RTC_lock; /* RTC lock */
131 static int RTC_timer_lock; /* RTC int lock */
132 #endif
133
134 struct pcl816_private {
135
136 unsigned int dma; /* used DMA, 0=don't use DMA */
137 int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */
138 #ifdef unused
139 unsigned long rtc_iobase; /* RTC port region */
140 unsigned int rtc_iosize;
141 unsigned int rtc_irq;
142 #endif
143 unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
144 unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */
145 unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
146 unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */
147 unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */
148 unsigned int last_top_dma; /* DMA pointer in last RTC int */
149 int next_dma_buf; /* which DMA buffer will be used next round */
150 long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
151 unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
152
153 unsigned int ai_scans; /* len of scanlist */
154 unsigned char ai_neverending; /* if=1, then we do neverending record (you must use cancel()) */
155 int irq_free; /* 1=have allocated IRQ */
156 int irq_blocked; /* 1=IRQ now uses any subdev */
157 #ifdef unused
158 int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */
159 #endif
160 int irq_was_now_closed; /* when IRQ finish, there's stored int816_mode for last interrupt */
161 int int816_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
162 struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */
163 int ai_act_scan; /* how many scans we finished */
164 unsigned int ai_act_chanlist[16]; /* MUX setting for actual AI operations */
165 unsigned int ai_act_chanlist_len; /* how long is actual MUX list */
166 unsigned int ai_act_chanlist_pos; /* actual position in MUX list */
167 unsigned int ai_n_chan; /* how many channels per scan */
168 unsigned int ai_poll_ptr; /* how many sampes transfer poll */
169 struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */
170 #ifdef unused
171 struct timer_list rtc_irq_timer; /* timer for RTC sanity check */
172 unsigned long rtc_freq; /* RTC int freq */
173 #endif
174 };
175
176 /*
177 ==============================================================================
178 */
179 static int check_channel_list(struct comedi_device *dev,
180 struct comedi_subdevice *s,
181 unsigned int *chanlist, unsigned int chanlen);
182 static void setup_channel_list(struct comedi_device *dev,
183 struct comedi_subdevice *s,
184 unsigned int *chanlist, unsigned int seglen);
185 static int pcl816_ai_cancel(struct comedi_device *dev,
186 struct comedi_subdevice *s);
187 static void start_pacer(struct comedi_device *dev, int mode,
188 unsigned int divisor1, unsigned int divisor2);
189 #ifdef unused
190 static int set_rtc_irq_bit(unsigned char bit);
191 #endif
192
193 static int pcl816_ai_cmdtest(struct comedi_device *dev,
194 struct comedi_subdevice *s,
195 struct comedi_cmd *cmd);
196 static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
197
198 /*
199 ==============================================================================
200 ANALOG INPUT MODE0, 816 cards, slow version
201 */
202 static int pcl816_ai_insn_read(struct comedi_device *dev,
203 struct comedi_subdevice *s,
204 struct comedi_insn *insn, unsigned int *data)
205 {
206 int n;
207 int timeout;
208
209 DPRINTK("mode 0 analog input\n");
210 /* software trigger, DMA and INT off */
211 outb(0, dev->iobase + PCL816_CONTROL);
212 /* clear INT (conversion end) flag */
213 outb(0, dev->iobase + PCL816_CLRINT);
214
215 /* Set the input channel */
216 outb(CR_CHAN(insn->chanspec) & 0xf, dev->iobase + PCL816_MUX);
217 /* select gain */
218 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE);
219
220 for (n = 0; n < insn->n; n++) {
221
222 outb(0, dev->iobase + PCL816_AD_LO); /* start conversion */
223
224 timeout = 100;
225 while (timeout--) {
226 if (!(inb(dev->iobase + PCL816_STATUS) &
227 PCL816_STATUS_DRDY_MASK)) {
228 /* return read value */
229 data[n] =
230 ((inb(dev->iobase +
231 PCL816_AD_HI) << 8) |
232 (inb(dev->iobase + PCL816_AD_LO)));
233 /* clear INT (conversion end) flag */
234 outb(0, dev->iobase + PCL816_CLRINT);
235 break;
236 }
237 udelay(1);
238 }
239 /* Return timeout error */
240 if (!timeout) {
241 comedi_error(dev, "A/D insn timeout\n");
242 data[0] = 0;
243 /* clear INT (conversion end) flag */
244 outb(0, dev->iobase + PCL816_CLRINT);
245 return -EIO;
246 }
247
248 }
249 return n;
250 }
251
252 /*
253 ==============================================================================
254 analog input interrupt mode 1 & 3, 818 cards
255 one sample per interrupt version
256 */
257 static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d)
258 {
259 struct comedi_device *dev = d;
260 struct pcl816_private *devpriv = dev->private;
261 struct comedi_subdevice *s = &dev->subdevices[0];
262 int low, hi;
263 int timeout = 50; /* wait max 50us */
264
265 while (timeout--) {
266 if (!(inb(dev->iobase + PCL816_STATUS) &
267 PCL816_STATUS_DRDY_MASK))
268 break;
269 udelay(1);
270 }
271 if (!timeout) { /* timeout, bail error */
272 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
273 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
274 pcl816_ai_cancel(dev, s);
275 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
276 comedi_event(dev, s);
277 return IRQ_HANDLED;
278
279 }
280
281 /* get the sample */
282 low = inb(dev->iobase + PCL816_AD_LO);
283 hi = inb(dev->iobase + PCL816_AD_HI);
284
285 comedi_buf_put(s->async, (hi << 8) | low);
286
287 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
288
289 if (++devpriv->ai_act_chanlist_pos >= devpriv->ai_act_chanlist_len)
290 devpriv->ai_act_chanlist_pos = 0;
291
292 s->async->cur_chan++;
293 if (s->async->cur_chan >= devpriv->ai_n_chan) {
294 s->async->cur_chan = 0;
295 devpriv->ai_act_scan++;
296 }
297
298 if (!devpriv->ai_neverending)
299 /* all data sampled */
300 if (devpriv->ai_act_scan >= devpriv->ai_scans) {
301 /* all data sampled */
302 pcl816_ai_cancel(dev, s);
303 s->async->events |= COMEDI_CB_EOA;
304 }
305 comedi_event(dev, s);
306 return IRQ_HANDLED;
307 }
308
309 /*
310 ==============================================================================
311 analog input dma mode 1 & 3, 816 cards
312 */
313 static void transfer_from_dma_buf(struct comedi_device *dev,
314 struct comedi_subdevice *s, short *ptr,
315 unsigned int bufptr, unsigned int len)
316 {
317 struct pcl816_private *devpriv = dev->private;
318 int i;
319
320 s->async->events = 0;
321
322 for (i = 0; i < len; i++) {
323
324 comedi_buf_put(s->async, ptr[bufptr++]);
325
326 if (++devpriv->ai_act_chanlist_pos >=
327 devpriv->ai_act_chanlist_len) {
328 devpriv->ai_act_chanlist_pos = 0;
329 }
330
331 s->async->cur_chan++;
332 if (s->async->cur_chan >= devpriv->ai_n_chan) {
333 s->async->cur_chan = 0;
334 devpriv->ai_act_scan++;
335 }
336
337 if (!devpriv->ai_neverending)
338 /* all data sampled */
339 if (devpriv->ai_act_scan >= devpriv->ai_scans) {
340 pcl816_ai_cancel(dev, s);
341 s->async->events |= COMEDI_CB_EOA;
342 s->async->events |= COMEDI_CB_BLOCK;
343 break;
344 }
345 }
346
347 comedi_event(dev, s);
348 }
349
350 static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d)
351 {
352 struct comedi_device *dev = d;
353 struct pcl816_private *devpriv = dev->private;
354 struct comedi_subdevice *s = &dev->subdevices[0];
355 int len, bufptr, this_dma_buf;
356 unsigned long dma_flags;
357 short *ptr;
358
359 disable_dma(devpriv->dma);
360 this_dma_buf = devpriv->next_dma_buf;
361
362 /* switch dma bufs */
363 if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) {
364
365 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
366 set_dma_mode(devpriv->dma, DMA_MODE_READ);
367 dma_flags = claim_dma_lock();
368 /* clear_dma_ff (devpriv->dma); */
369 set_dma_addr(devpriv->dma,
370 devpriv->hwdmaptr[devpriv->next_dma_buf]);
371 if (devpriv->dma_runs_to_end) {
372 set_dma_count(devpriv->dma,
373 devpriv->hwdmasize[devpriv->
374 next_dma_buf]);
375 } else {
376 set_dma_count(devpriv->dma, devpriv->last_dma_run);
377 }
378 release_dma_lock(dma_flags);
379 enable_dma(devpriv->dma);
380 }
381
382 devpriv->dma_runs_to_end--;
383 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
384
385 ptr = (short *)devpriv->dmabuf[this_dma_buf];
386
387 len = (devpriv->hwdmasize[0] >> 1) - devpriv->ai_poll_ptr;
388 bufptr = devpriv->ai_poll_ptr;
389 devpriv->ai_poll_ptr = 0;
390
391 transfer_from_dma_buf(dev, s, ptr, bufptr, len);
392 return IRQ_HANDLED;
393 }
394
395 /*
396 ==============================================================================
397 INT procedure
398 */
399 static irqreturn_t interrupt_pcl816(int irq, void *d)
400 {
401 struct comedi_device *dev = d;
402 struct pcl816_private *devpriv = dev->private;
403
404 DPRINTK("<I>");
405
406 if (!dev->attached) {
407 comedi_error(dev, "premature interrupt");
408 return IRQ_HANDLED;
409 }
410
411 switch (devpriv->int816_mode) {
412 case INT_TYPE_AI1_DMA:
413 case INT_TYPE_AI3_DMA:
414 return interrupt_pcl816_ai_mode13_dma(irq, d);
415 case INT_TYPE_AI1_INT:
416 case INT_TYPE_AI3_INT:
417 return interrupt_pcl816_ai_mode13_int(irq, d);
418 }
419
420 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
421 if (!dev->irq || !devpriv->irq_free || !devpriv->irq_blocked ||
422 !devpriv->int816_mode) {
423 if (devpriv->irq_was_now_closed) {
424 devpriv->irq_was_now_closed = 0;
425 /* comedi_error(dev,"last IRQ.."); */
426 return IRQ_HANDLED;
427 }
428 comedi_error(dev, "bad IRQ!");
429 return IRQ_NONE;
430 }
431 comedi_error(dev, "IRQ from unknown source!");
432 return IRQ_NONE;
433 }
434
435 /*
436 ==============================================================================
437 COMMAND MODE
438 */
439 static void pcl816_cmdtest_out(int e, struct comedi_cmd *cmd)
440 {
441 printk(KERN_INFO "pcl816 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
442 cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
443 printk(KERN_INFO "pcl816 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
444 cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
445 printk(KERN_INFO "pcl816 e=%d stopsrc=%x scanend=%x\n", e,
446 cmd->stop_src, cmd->scan_end_src);
447 printk(KERN_INFO "pcl816 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
448 e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
449 }
450
451 /*
452 ==============================================================================
453 */
454 static int pcl816_ai_cmdtest(struct comedi_device *dev,
455 struct comedi_subdevice *s, struct comedi_cmd *cmd)
456 {
457 const struct pcl816_board *board = comedi_board(dev);
458 int err = 0;
459 int tmp, divisor1 = 0, divisor2 = 0;
460
461 DEBUG(printk(KERN_INFO "pcl816 pcl812_ai_cmdtest\n");
462 pcl816_cmdtest_out(-1, cmd);
463 );
464
465 /* Step 1 : check if triggers are trivially valid */
466
467 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
468 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
469 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_EXT | TRIG_TIMER);
470 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
471 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
472
473 if (err)
474 return 1;
475
476 /* Step 2a : make sure trigger sources are unique */
477
478 err |= cfc_check_trigger_is_unique(cmd->convert_src);
479 err |= cfc_check_trigger_is_unique(cmd->stop_src);
480
481 /* Step 2b : and mutually compatible */
482
483 if (err)
484 return 2;
485
486
487 /* Step 3: check if arguments are trivially valid */
488
489 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
490 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
491
492 if (cmd->convert_src == TRIG_TIMER)
493 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
494 board->ai_ns_min);
495 else /* TRIG_EXT */
496 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
497
498 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
499
500 if (cmd->stop_src == TRIG_COUNT)
501 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
502 else /* TRIG_NONE */
503 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
504
505 if (err)
506 return 3;
507
508
509 /* step 4: fix up any arguments */
510 if (cmd->convert_src == TRIG_TIMER) {
511 tmp = cmd->convert_arg;
512 i8253_cascade_ns_to_timer(board->i8254_osc_base,
513 &divisor1, &divisor2,
514 &cmd->convert_arg,
515 cmd->flags & TRIG_ROUND_MASK);
516 if (cmd->convert_arg < board->ai_ns_min)
517 cmd->convert_arg = board->ai_ns_min;
518 if (tmp != cmd->convert_arg)
519 err++;
520 }
521
522 if (err)
523 return 4;
524
525
526 /* step 5: complain about special chanlist considerations */
527
528 if (cmd->chanlist) {
529 if (!check_channel_list(dev, s, cmd->chanlist,
530 cmd->chanlist_len))
531 return 5; /* incorrect channels list */
532 }
533
534 return 0;
535 }
536
537 static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
538 {
539 const struct pcl816_board *board = comedi_board(dev);
540 struct pcl816_private *devpriv = dev->private;
541 unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq;
542 struct comedi_cmd *cmd = &s->async->cmd;
543 unsigned int seglen;
544
545 if (cmd->start_src != TRIG_NOW)
546 return -EINVAL;
547 if (cmd->scan_begin_src != TRIG_FOLLOW)
548 return -EINVAL;
549 if (cmd->scan_end_src != TRIG_COUNT)
550 return -EINVAL;
551 if (cmd->scan_end_arg != cmd->chanlist_len)
552 return -EINVAL;
553 /* if(cmd->chanlist_len>MAX_CHANLIST_LEN) return -EINVAL; */
554 if (devpriv->irq_blocked)
555 return -EBUSY;
556
557 if (cmd->convert_src == TRIG_TIMER) {
558 if (cmd->convert_arg < board->ai_ns_min)
559 cmd->convert_arg = board->ai_ns_min;
560
561 i8253_cascade_ns_to_timer(board->i8254_osc_base, &divisor1,
562 &divisor2, &cmd->convert_arg,
563 cmd->flags & TRIG_ROUND_MASK);
564
565 /* PCL816 crash if any divisor is set to 1 */
566 if (divisor1 == 1) {
567 divisor1 = 2;
568 divisor2 /= 2;
569 }
570 if (divisor2 == 1) {
571 divisor2 = 2;
572 divisor1 /= 2;
573 }
574 }
575
576 start_pacer(dev, -1, 0, 0); /* stop pacer */
577
578 seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len);
579 if (seglen < 1)
580 return -EINVAL;
581 setup_channel_list(dev, s, cmd->chanlist, seglen);
582 udelay(1);
583
584 devpriv->ai_n_chan = cmd->chanlist_len;
585 devpriv->ai_act_scan = 0;
586 s->async->cur_chan = 0;
587 devpriv->irq_blocked = 1;
588 devpriv->ai_poll_ptr = 0;
589 devpriv->irq_was_now_closed = 0;
590
591 if (cmd->stop_src == TRIG_COUNT) {
592 devpriv->ai_scans = cmd->stop_arg;
593 devpriv->ai_neverending = 0;
594 } else {
595 devpriv->ai_scans = 0;
596 devpriv->ai_neverending = 1;
597 }
598
599 /* don't we want wake up every scan? */
600 if ((cmd->flags & TRIG_WAKE_EOS)) {
601 printk(KERN_INFO
602 "pl816: You wankt WAKE_EOS but I dont want handle it");
603 /* devpriv->ai_eos=1; */
604 /* if (devpriv->ai_n_chan==1) */
605 /* devpriv->dma=0; // DMA is useless for this situation */
606 }
607
608 if (devpriv->dma) {
609 bytes = devpriv->hwdmasize[0];
610 if (!devpriv->ai_neverending) {
611 /* how many */
612 bytes = s->async->cmd.chanlist_len *
613 s->async->cmd.chanlist_len *
614 sizeof(short);
615
616 /* how many DMA pages we must fill */
617 devpriv->dma_runs_to_end = bytes /
618 devpriv->hwdmasize[0];
619
620 /* on last dma transfer must be moved */
621 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0];
622 devpriv->dma_runs_to_end--;
623 if (devpriv->dma_runs_to_end >= 0)
624 bytes = devpriv->hwdmasize[0];
625 } else
626 devpriv->dma_runs_to_end = -1;
627
628 devpriv->next_dma_buf = 0;
629 set_dma_mode(devpriv->dma, DMA_MODE_READ);
630 dma_flags = claim_dma_lock();
631 clear_dma_ff(devpriv->dma);
632 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
633 set_dma_count(devpriv->dma, bytes);
634 release_dma_lock(dma_flags);
635 enable_dma(devpriv->dma);
636 }
637
638 start_pacer(dev, 1, divisor1, divisor2);
639 dmairq = ((devpriv->dma & 0x3) << 4) | (dev->irq & 0x7);
640
641 switch (cmd->convert_src) {
642 case TRIG_TIMER:
643 devpriv->int816_mode = INT_TYPE_AI1_DMA;
644
645 /* Pacer+IRQ+DMA */
646 outb(0x32, dev->iobase + PCL816_CONTROL);
647
648 /* write irq and DMA to card */
649 outb(dmairq, dev->iobase + PCL816_STATUS);
650 break;
651
652 default:
653 devpriv->int816_mode = INT_TYPE_AI3_DMA;
654
655 /* Ext trig+IRQ+DMA */
656 outb(0x34, dev->iobase + PCL816_CONTROL);
657
658 /* write irq to card */
659 outb(dmairq, dev->iobase + PCL816_STATUS);
660 break;
661 }
662
663 DPRINTK("pcl816 END: pcl812_ai_cmd()\n");
664 return 0;
665 }
666
667 static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
668 {
669 struct pcl816_private *devpriv = dev->private;
670 unsigned long flags;
671 unsigned int top1, top2, i;
672
673 if (!devpriv->dma)
674 return 0; /* poll is valid only for DMA transfer */
675
676 spin_lock_irqsave(&dev->spinlock, flags);
677
678 for (i = 0; i < 20; i++) {
679 top1 = get_dma_residue(devpriv->dma); /* where is now DMA */
680 top2 = get_dma_residue(devpriv->dma);
681 if (top1 == top2)
682 break;
683 }
684 if (top1 != top2) {
685 spin_unlock_irqrestore(&dev->spinlock, flags);
686 return 0;
687 }
688
689 /* where is now DMA in buffer */
690 top1 = devpriv->hwdmasize[0] - top1;
691 top1 >>= 1; /* sample position */
692 top2 = top1 - devpriv->ai_poll_ptr;
693 if (top2 < 1) { /* no new samples */
694 spin_unlock_irqrestore(&dev->spinlock, flags);
695 return 0;
696 }
697
698 transfer_from_dma_buf(dev, s,
699 (short *)devpriv->dmabuf[devpriv->next_dma_buf],
700 devpriv->ai_poll_ptr, top2);
701
702 devpriv->ai_poll_ptr = top1; /* new buffer position */
703 spin_unlock_irqrestore(&dev->spinlock, flags);
704
705 return s->async->buf_write_count - s->async->buf_read_count;
706 }
707
708 /*
709 ==============================================================================
710 cancel any mode 1-4 AI
711 */
712 static int pcl816_ai_cancel(struct comedi_device *dev,
713 struct comedi_subdevice *s)
714 {
715 struct pcl816_private *devpriv = dev->private;
716
717 /* DEBUG(printk("pcl816_ai_cancel()\n");) */
718
719 if (devpriv->irq_blocked > 0) {
720 switch (devpriv->int816_mode) {
721 #ifdef unused
722 case INT_TYPE_AI1_DMA_RTC:
723 case INT_TYPE_AI3_DMA_RTC:
724 set_rtc_irq_bit(0); /* stop RTC */
725 del_timer(&devpriv->rtc_irq_timer);
726 #endif
727 case INT_TYPE_AI1_DMA:
728 case INT_TYPE_AI3_DMA:
729 disable_dma(devpriv->dma);
730 case INT_TYPE_AI1_INT:
731 case INT_TYPE_AI3_INT:
732 outb(inb(dev->iobase + PCL816_CONTROL) & 0x73,
733 dev->iobase + PCL816_CONTROL); /* Stop A/D */
734 udelay(1);
735 outb(0, dev->iobase + PCL816_CONTROL); /* Stop A/D */
736
737 /* Stop pacer */
738 outb(0xb0, dev->iobase + PCL816_CTRCTL);
739 outb(0x70, dev->iobase + PCL816_CTRCTL);
740 outb(0, dev->iobase + PCL816_AD_LO);
741 inb(dev->iobase + PCL816_AD_LO);
742 inb(dev->iobase + PCL816_AD_HI);
743
744 /* clear INT request */
745 outb(0, dev->iobase + PCL816_CLRINT);
746
747 /* Stop A/D */
748 outb(0, dev->iobase + PCL816_CONTROL);
749 devpriv->irq_blocked = 0;
750 devpriv->irq_was_now_closed = devpriv->int816_mode;
751 devpriv->int816_mode = 0;
752 devpriv->last_int_sub = s;
753 /* s->busy = 0; */
754 break;
755 }
756 }
757
758 DEBUG(printk("comedi: pcl816_ai_cancel() successful\n");)
759 return 0;
760 }
761
762 /*
763 ==============================================================================
764 chech for PCL816
765 */
766 static int pcl816_check(unsigned long iobase)
767 {
768 outb(0x00, iobase + PCL816_MUX);
769 udelay(1);
770 if (inb(iobase + PCL816_MUX) != 0x00)
771 return 1; /* there isn't card */
772 outb(0x55, iobase + PCL816_MUX);
773 udelay(1);
774 if (inb(iobase + PCL816_MUX) != 0x55)
775 return 1; /* there isn't card */
776 outb(0x00, iobase + PCL816_MUX);
777 udelay(1);
778 outb(0x18, iobase + PCL816_CONTROL);
779 udelay(1);
780 if (inb(iobase + PCL816_CONTROL) != 0x18)
781 return 1; /* there isn't card */
782 return 0; /* ok, card exist */
783 }
784
785 /*
786 ==============================================================================
787 reset whole PCL-816 cards
788 */
789 static void pcl816_reset(struct comedi_device *dev)
790 {
791 /* outb (0, dev->iobase + PCL818_DA_LO); DAC=0V */
792 /* outb (0, dev->iobase + PCL818_DA_HI); */
793 /* udelay (1); */
794 /* outb (0, dev->iobase + PCL818_DO_HI); DO=$0000 */
795 /* outb (0, dev->iobase + PCL818_DO_LO); */
796 /* udelay (1); */
797 outb(0, dev->iobase + PCL816_CONTROL);
798 outb(0, dev->iobase + PCL816_MUX);
799 outb(0, dev->iobase + PCL816_CLRINT);
800 outb(0xb0, dev->iobase + PCL816_CTRCTL); /* Stop pacer */
801 outb(0x70, dev->iobase + PCL816_CTRCTL);
802 outb(0x30, dev->iobase + PCL816_CTRCTL);
803 outb(0, dev->iobase + PCL816_RANGE);
804 }
805
806 /*
807 ==============================================================================
808 Start/stop pacer onboard pacer
809 */
810 static void
811 start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1,
812 unsigned int divisor2)
813 {
814 outb(0x32, dev->iobase + PCL816_CTRCTL);
815 outb(0xff, dev->iobase + PCL816_CTR0);
816 outb(0x00, dev->iobase + PCL816_CTR0);
817 udelay(1);
818
819 /* set counter 2 as mode 3 */
820 outb(0xb4, dev->iobase + PCL816_CTRCTL);
821 /* set counter 1 as mode 3 */
822 outb(0x74, dev->iobase + PCL816_CTRCTL);
823 udelay(1);
824
825 if (mode == 1) {
826 DPRINTK("mode %d, divisor1 %d, divisor2 %d\n", mode, divisor1,
827 divisor2);
828 outb(divisor2 & 0xff, dev->iobase + PCL816_CTR2);
829 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL816_CTR2);
830 outb(divisor1 & 0xff, dev->iobase + PCL816_CTR1);
831 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL816_CTR1);
832 }
833
834 /* clear pending interrupts (just in case) */
835 /* outb(0, dev->iobase + PCL816_CLRINT); */
836 }
837
838 /*
839 ==============================================================================
840 Check if channel list from user is built correctly
841 If it's ok, then return non-zero length of repeated segment of channel list
842 */
843 static int
844 check_channel_list(struct comedi_device *dev,
845 struct comedi_subdevice *s, unsigned int *chanlist,
846 unsigned int chanlen)
847 {
848 unsigned int chansegment[16];
849 unsigned int i, nowmustbechan, seglen, segpos;
850
851 /* correct channel and range number check itself comedi/range.c */
852 if (chanlen < 1) {
853 comedi_error(dev, "range/channel list is empty!");
854 return 0;
855 }
856
857 if (chanlen > 1) {
858 /* first channel is every time ok */
859 chansegment[0] = chanlist[0];
860 for (i = 1, seglen = 1; i < chanlen; i++, seglen++) {
861 /* build part of chanlist */
862 DEBUG(printk(KERN_INFO "%d. %d %d\n", i,
863 CR_CHAN(chanlist[i]),
864 CR_RANGE(chanlist[i]));)
865
866 /* we detect loop, this must by finish */
867 if (chanlist[0] == chanlist[i])
868 break;
869 nowmustbechan =
870 (CR_CHAN(chansegment[i - 1]) + 1) % chanlen;
871 if (nowmustbechan != CR_CHAN(chanlist[i])) {
872 /* channel list isn't continuous :-( */
873 printk(KERN_WARNING
874 "comedi%d: pcl816: channel list must "
875 "be continuous! chanlist[%i]=%d but "
876 "must be %d or %d!\n", dev->minor,
877 i, CR_CHAN(chanlist[i]), nowmustbechan,
878 CR_CHAN(chanlist[0]));
879 return 0;
880 }
881 /* well, this is next correct channel in list */
882 chansegment[i] = chanlist[i];
883 }
884
885 /* check whole chanlist */
886 for (i = 0, segpos = 0; i < chanlen; i++) {
887 DEBUG(printk("%d %d=%d %d\n",
888 CR_CHAN(chansegment[i % seglen]),
889 CR_RANGE(chansegment[i % seglen]),
890 CR_CHAN(chanlist[i]),
891 CR_RANGE(chanlist[i]));)
892 if (chanlist[i] != chansegment[i % seglen]) {
893 printk(KERN_WARNING
894 "comedi%d: pcl816: bad channel or range"
895 " number! chanlist[%i]=%d,%d,%d and not"
896 " %d,%d,%d!\n", dev->minor, i,
897 CR_CHAN(chansegment[i]),
898 CR_RANGE(chansegment[i]),
899 CR_AREF(chansegment[i]),
900 CR_CHAN(chanlist[i % seglen]),
901 CR_RANGE(chanlist[i % seglen]),
902 CR_AREF(chansegment[i % seglen]));
903 return 0; /* chan/gain list is strange */
904 }
905 }
906 } else {
907 seglen = 1;
908 }
909
910 return seglen; /* we can serve this with MUX logic */
911 }
912
913 /*
914 ==============================================================================
915 Program scan/gain logic with channel list.
916 */
917 static void
918 setup_channel_list(struct comedi_device *dev,
919 struct comedi_subdevice *s, unsigned int *chanlist,
920 unsigned int seglen)
921 {
922 struct pcl816_private *devpriv = dev->private;
923 unsigned int i;
924
925 devpriv->ai_act_chanlist_len = seglen;
926 devpriv->ai_act_chanlist_pos = 0;
927
928 for (i = 0; i < seglen; i++) { /* store range list to card */
929 devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]);
930 outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX);
931 /* select gain */
932 outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE);
933 }
934
935 udelay(1);
936 /* select channel interval to scan */
937 outb(devpriv->ai_act_chanlist[0] |
938 (devpriv->ai_act_chanlist[seglen - 1] << 4),
939 dev->iobase + PCL816_MUX);
940 }
941
942 #ifdef unused
943 /*
944 ==============================================================================
945 Enable(1)/disable(0) periodic interrupts from RTC
946 */
947 static int set_rtc_irq_bit(unsigned char bit)
948 {
949 unsigned char val;
950 unsigned long flags;
951
952 if (bit == 1) {
953 RTC_timer_lock++;
954 if (RTC_timer_lock > 1)
955 return 0;
956 } else {
957 RTC_timer_lock--;
958 if (RTC_timer_lock < 0)
959 RTC_timer_lock = 0;
960 if (RTC_timer_lock > 0)
961 return 0;
962 }
963
964 save_flags(flags);
965 cli();
966 val = CMOS_READ(RTC_CONTROL);
967 if (bit)
968 val |= RTC_PIE;
969 else
970 val &= ~RTC_PIE;
971
972 CMOS_WRITE(val, RTC_CONTROL);
973 CMOS_READ(RTC_INTR_FLAGS);
974 restore_flags(flags);
975 return 0;
976 }
977 #endif
978
979 static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
980 {
981 const struct pcl816_board *board = comedi_board(dev);
982 struct pcl816_private *devpriv;
983 int ret;
984 unsigned int irq, dma;
985 unsigned long pages;
986 /* int i; */
987 struct comedi_subdevice *s;
988
989 ret = comedi_request_region(dev, it->options[0], board->io_range);
990 if (ret)
991 return ret;
992
993 if (pcl816_check(dev->iobase)) {
994 printk(KERN_ERR ", I cann't detect board. FAIL!\n");
995 return -EIO;
996 }
997
998 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
999 if (!devpriv)
1000 return -ENOMEM;
1001 dev->private = devpriv;
1002
1003 /* grab our IRQ */
1004 irq = 0;
1005 if (board->IRQbits != 0) { /* board support IRQ */
1006 irq = it->options[1];
1007 if (irq) { /* we want to use IRQ */
1008 if (((1 << irq) & board->IRQbits) == 0) {
1009 printk
1010 (", IRQ %u is out of allowed range, "
1011 "DISABLING IT", irq);
1012 irq = 0; /* Bad IRQ */
1013 } else {
1014 if (request_irq(irq, interrupt_pcl816, 0,
1015 dev->board_name, dev)) {
1016 printk
1017 (", unable to allocate IRQ %u, "
1018 "DISABLING IT", irq);
1019 irq = 0; /* Can't use IRQ */
1020 } else {
1021 printk(KERN_INFO ", irq=%u", irq);
1022 }
1023 }
1024 }
1025 }
1026
1027 dev->irq = irq;
1028 if (irq) /* 1=we have allocated irq */
1029 devpriv->irq_free = 1;
1030 else
1031 devpriv->irq_free = 0;
1032
1033 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
1034 devpriv->int816_mode = 0; /* mode of irq */
1035
1036 #ifdef unused
1037 /* grab RTC for DMA operations */
1038 devpriv->dma_rtc = 0;
1039 if (it->options[2] > 0) { /* we want to use DMA */
1040 if (RTC_lock == 0) {
1041 ret = __comedi_request_region(dev, RTC_PORT(0),
1042 RTC_IO_EXTENT);
1043 if (ret)
1044 goto no_rtc;
1045 }
1046 devpriv->rtc_iobase = RTC_PORT(0);
1047 devpriv->rtc_iosize = RTC_IO_EXTENT;
1048 RTC_lock++;
1049 #ifdef UNTESTED_CODE
1050 if (!request_irq(RTC_IRQ, interrupt_pcl816_ai_mode13_dma_rtc, 0,
1051 "pcl816 DMA (RTC)", dev)) {
1052 devpriv->dma_rtc = 1;
1053 devpriv->rtc_irq = RTC_IRQ;
1054 printk(", dma_irq=%u", devpriv->rtc_irq);
1055 } else {
1056 RTC_lock--;
1057 if (RTC_lock == 0) {
1058 if (devpriv->rtc_iobase)
1059 release_region(devpriv->rtc_iobase,
1060 devpriv->rtc_iosize);
1061 }
1062 devpriv->rtc_iobase = 0;
1063 devpriv->rtc_iosize = 0;
1064 }
1065 #else
1066 printk("pcl816: RTC code missing");
1067 #endif
1068
1069 }
1070
1071 no_rtc:
1072 #endif
1073 /* grab our DMA */
1074 dma = 0;
1075 devpriv->dma = dma;
1076 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1077 goto no_dma; /* if we haven't IRQ, we can't use DMA */
1078
1079 if (board->DMAbits != 0) { /* board support DMA */
1080 dma = it->options[2];
1081 if (dma < 1)
1082 goto no_dma; /* DMA disabled */
1083
1084 if (((1 << dma) & board->DMAbits) == 0) {
1085 printk(", DMA is out of allowed range, FAIL!\n");
1086 return -EINVAL; /* Bad DMA */
1087 }
1088 ret = request_dma(dma, dev->board_name);
1089 if (ret) {
1090 printk(KERN_ERR
1091 ", unable to allocate DMA %u, FAIL!\n", dma);
1092 return -EBUSY; /* DMA isn't free */
1093 }
1094
1095 devpriv->dma = dma;
1096 printk(KERN_INFO ", dma=%u", dma);
1097 pages = 2; /* we need 16KB */
1098 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1099
1100 if (!devpriv->dmabuf[0]) {
1101 printk(", unable to allocate DMA buffer, FAIL!\n");
1102 /*
1103 * maybe experiment with try_to_free_pages()
1104 * will help ....
1105 */
1106 return -EBUSY; /* no buffer :-( */
1107 }
1108 devpriv->dmapages[0] = pages;
1109 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1110 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
1111 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
1112
1113 if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */
1114 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1115 if (!devpriv->dmabuf[1]) {
1116 printk(KERN_ERR
1117 ", unable to allocate DMA buffer, "
1118 "FAIL!\n");
1119 return -EBUSY;
1120 }
1121 devpriv->dmapages[1] = pages;
1122 devpriv->hwdmaptr[1] =
1123 virt_to_bus((void *)devpriv->dmabuf[1]);
1124 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1125 }
1126 }
1127
1128 no_dma:
1129
1130 /* if (board->n_aochan > 0)
1131 subdevs[1] = COMEDI_SUBD_AO;
1132 if (board->n_dichan > 0)
1133 subdevs[2] = COMEDI_SUBD_DI;
1134 if (board->n_dochan > 0)
1135 subdevs[3] = COMEDI_SUBD_DO;
1136 */
1137
1138 ret = comedi_alloc_subdevices(dev, 1);
1139 if (ret)
1140 return ret;
1141
1142 s = &dev->subdevices[0];
1143 if (board->n_aichan > 0) {
1144 s->type = COMEDI_SUBD_AI;
1145 devpriv->sub_ai = s;
1146 dev->read_subdev = s;
1147 s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
1148 s->n_chan = board->n_aichan;
1149 s->subdev_flags |= SDF_DIFF;
1150 /* printk (", %dchans DIFF DAC - %d", s->n_chan, i); */
1151 s->maxdata = board->ai_maxdata;
1152 s->len_chanlist = board->ai_chanlist;
1153 s->range_table = board->ai_range_type;
1154 s->cancel = pcl816_ai_cancel;
1155 s->do_cmdtest = pcl816_ai_cmdtest;
1156 s->do_cmd = pcl816_ai_cmd;
1157 s->poll = pcl816_ai_poll;
1158 s->insn_read = pcl816_ai_insn_read;
1159 } else {
1160 s->type = COMEDI_SUBD_UNUSED;
1161 }
1162
1163 #if 0
1164 case COMEDI_SUBD_AO:
1165 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1166 s->n_chan = board->n_aochan;
1167 s->maxdata = board->ao_maxdata;
1168 s->len_chanlist = board->ao_chanlist;
1169 s->range_table = board->ao_range_type;
1170 break;
1171
1172 case COMEDI_SUBD_DI:
1173 s->subdev_flags = SDF_READABLE;
1174 s->n_chan = board->n_dichan;
1175 s->maxdata = 1;
1176 s->len_chanlist = board->n_dichan;
1177 s->range_table = &range_digital;
1178 break;
1179
1180 case COMEDI_SUBD_DO:
1181 s->subdev_flags = SDF_WRITABLE;
1182 s->n_chan = board->n_dochan;
1183 s->maxdata = 1;
1184 s->len_chanlist = board->n_dochan;
1185 s->range_table = &range_digital;
1186 break;
1187 #endif
1188
1189 pcl816_reset(dev);
1190
1191 printk("\n");
1192
1193 return 0;
1194 }
1195
1196 static void pcl816_detach(struct comedi_device *dev)
1197 {
1198 struct pcl816_private *devpriv = dev->private;
1199
1200 if (dev->private) {
1201 pcl816_ai_cancel(dev, devpriv->sub_ai);
1202 pcl816_reset(dev);
1203 if (devpriv->dma)
1204 free_dma(devpriv->dma);
1205 if (devpriv->dmabuf[0])
1206 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1207 if (devpriv->dmabuf[1])
1208 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1209 #ifdef unused
1210 if (devpriv->rtc_irq)
1211 free_irq(devpriv->rtc_irq, dev);
1212 if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1213 if (devpriv->rtc_iobase)
1214 release_region(devpriv->rtc_iobase,
1215 devpriv->rtc_iosize);
1216 }
1217 if (devpriv->dma_rtc)
1218 RTC_lock--;
1219 #endif
1220 }
1221 comedi_legacy_detach(dev);
1222 }
1223
1224 static const struct pcl816_board boardtypes[] = {
1225 {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816,
1226 &range_pcl816, PCLx1x_RANGE,
1227 0x00fc, /* IRQ mask */
1228 0x0a, /* DMA mask */
1229 0xffff, /* 16-bit card */
1230 0xffff, /* D/A maxdata */
1231 1024,
1232 1, /* ao chan list */
1233 100},
1234 {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816,
1235 &range_pcl816, PCLx1x_RANGE,
1236 0x00fc,
1237 0x0a,
1238 0x3fff, /* 14 bit card */
1239 0x3fff,
1240 1024,
1241 1,
1242 100},
1243 };
1244
1245 static struct comedi_driver pcl816_driver = {
1246 .driver_name = "pcl816",
1247 .module = THIS_MODULE,
1248 .attach = pcl816_attach,
1249 .detach = pcl816_detach,
1250 .board_name = &boardtypes[0].name,
1251 .num_names = ARRAY_SIZE(boardtypes),
1252 .offset = sizeof(struct pcl816_board),
1253 };
1254 module_comedi_driver(pcl816_driver);
1255
1256 MODULE_AUTHOR("Comedi http://www.comedi.org");
1257 MODULE_DESCRIPTION("Comedi low-level driver");
1258 MODULE_LICENSE("GPL");