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 "8253.h"
45 
46 #define DEBUG(x) x
47 
48 /* boards constants */
49 /* IO space len */
50 #define PCLx1x_RANGE 16
51 
52 /* #define outb(x,y)  printk("OUTB(%x, 200+%d)\n", x,y-0x200); outb(x,y) */
53 
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
60 
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
69 
70 /* R: return status byte  W: set DMA/IRQ */
71 #define PCL816_STATUS 13
72 #define PCL816_STATUS_DRDY_MASK 0x80
73 
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
78 
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
87 
88 /* RTC stuff... */
89 #define RTC_IRQ		8
90 #define RTC_IO_EXTENT	0x10
91 #endif
92 
93 #define MAGIC_DMA_WORD 0x5a5a
94 
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),
104 						       }
105 };
106 
107 struct pcl816_board {
108 
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 */
126 };
127 
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,
145 	 1,
146 	 100},
147 };
148 
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)
152 
153 static int pcl816_attach(struct comedi_device *dev,
154 			 struct comedi_devconfig *it);
155 static int pcl816_detach(struct comedi_device *dev);
156 
157 #ifdef unused
158 static int RTC_lock;	/* RTC lock */
159 static int RTC_timer_lock;	/* RTC int lock */
160 #endif
161 
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),
170 };
171 
driver_pcl816_init_module(void)172 static int __init driver_pcl816_init_module(void)
173 {
174 	return comedi_driver_register(&driver_pcl816);
175 }
176 
driver_pcl816_cleanup_module(void)177 static void __exit driver_pcl816_cleanup_module(void)
178 {
179 	comedi_driver_unregister(&driver_pcl816);
180 }
181 
182 module_init(driver_pcl816_init_module);
183 module_exit(driver_pcl816_cleanup_module);
184 
185 struct pcl816_private {
186 
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 */
203 
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
225 };
226 
227 /*
228 ==============================================================================
229 */
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
243 
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);
248 
249 /*
250 ==============================================================================
251    ANALOG INPUT MODE0, 816 cards, slow version
252 */
pcl816_ai_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)253 static int pcl816_ai_insn_read(struct comedi_device *dev,
254 			       struct comedi_subdevice *s,
255 			       struct comedi_insn *insn, unsigned int *data)
256 {
257 	int n;
258 	int timeout;
259 
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);
265 
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);
270 
271 	for (n = 0; n < insn->n; n++) {
272 
273 		outb(0, dev->iobase + PCL816_AD_LO);	/* start conversion */
274 
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;
287 			}
288 			udelay(1);
289 		}
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;
297 		}
298 
299 	}
300 	return n;
301 }
302 
303 /*
304 ==============================================================================
305    analog input interrupt mode 1 & 3, 818 cards
306    one sample per interrupt version
307 */
interrupt_pcl816_ai_mode13_int(int irq,void * d)308 static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d)
309 {
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 */
314 
315 	while (timeout--) {
316 		if (!(inb(dev->iobase + PCL816_STATUS) &
317 		      PCL816_STATUS_DRDY_MASK))
318 			break;
319 		udelay(1);
320 	}
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;
328 
329 	}
330 
331 	/*  get the sample */
332 	low = inb(dev->iobase + PCL816_AD_LO);
333 	hi = inb(dev->iobase + PCL816_AD_HI);
334 
335 	comedi_buf_put(s->async, (hi << 8) | low);
336 
337 	outb(0, dev->iobase + PCL816_CLRINT);	/* clear INT request */
338 
339 	if (++devpriv->ai_act_chanlist_pos >= devpriv->ai_act_chanlist_len)
340 		devpriv->ai_act_chanlist_pos = 0;
341 
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++;
346 	}
347 
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;
354 		}
355 	comedi_event(dev, s);
356 	return IRQ_HANDLED;
357 }
358 
359 /*
360 ==============================================================================
361    analog input dma mode 1 & 3, 816 cards
362 */
transfer_from_dma_buf(struct comedi_device * dev,struct comedi_subdevice * s,short * ptr,unsigned int bufptr,unsigned int len)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)
366 {
367 	int i;
368 
369 	s->async->events = 0;
370 
371 	for (i = 0; i < len; i++) {
372 
373 		comedi_buf_put(s->async, ptr[bufptr++]);
374 
375 		if (++devpriv->ai_act_chanlist_pos >=
376 		    devpriv->ai_act_chanlist_len) {
377 			devpriv->ai_act_chanlist_pos = 0;
378 		}
379 
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++;
384 		}
385 
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;
393 			}
394 	}
395 
396 	comedi_event(dev, s);
397 }
398 
interrupt_pcl816_ai_mode13_dma(int irq,void * d)399 static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d)
400 {
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;
406 
407 	disable_dma(devpriv->dma);
408 	this_dma_buf = devpriv->next_dma_buf;
409 
410 	/*  switch dma bufs */
411 	if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) {
412 
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);
425 		}
426 		release_dma_lock(dma_flags);
427 		enable_dma(devpriv->dma);
428 	}
429 
430 	devpriv->dma_runs_to_end--;
431 	outb(0, dev->iobase + PCL816_CLRINT);	/* clear INT request */
432 
433 	ptr = (short *)devpriv->dmabuf[this_dma_buf];
434 
435 	len = (devpriv->hwdmasize[0] >> 1) - devpriv->ai_poll_ptr;
436 	bufptr = devpriv->ai_poll_ptr;
437 	devpriv->ai_poll_ptr = 0;
438 
439 	transfer_from_dma_buf(dev, s, ptr, bufptr, len);
440 	return IRQ_HANDLED;
441 }
442 
443 /*
444 ==============================================================================
445     INT procedure
446 */
interrupt_pcl816(int irq,void * d)447 static irqreturn_t interrupt_pcl816(int irq, void *d)
448 {
449 	struct comedi_device *dev = d;
450 	DPRINTK("<I>");
451 
452 	if (!dev->attached) {
453 		comedi_error(dev, "premature interrupt");
454 		return IRQ_HANDLED;
455 	}
456 
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);
464 	}
465 
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;
473 		}
474 		comedi_error(dev, "bad IRQ!");
475 		return IRQ_NONE;
476 	}
477 	comedi_error(dev, "IRQ from unknown source!");
478 	return IRQ_NONE;
479 }
480 
481 /*
482 ==============================================================================
483    COMMAND MODE
484 */
pcl816_cmdtest_out(int e,struct comedi_cmd * cmd)485 static void pcl816_cmdtest_out(int e, struct comedi_cmd *cmd)
486 {
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);
495 }
496 
497 /*
498 ==============================================================================
499 */
pcl816_ai_cmdtest(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)500 static int pcl816_ai_cmdtest(struct comedi_device *dev,
501 			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
502 {
503 	int err = 0;
504 	int tmp, divisor1 = 0, divisor2 = 0;
505 
506 	DEBUG(printk(KERN_INFO "pcl816 pcl812_ai_cmdtest\n");
507 	      pcl816_cmdtest_out(-1, cmd);
508 	     );
509 
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++;
515 
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++;
520 
521 	tmp = cmd->convert_src;
522 	cmd->convert_src &= TRIG_EXT | TRIG_TIMER;
523 	if (!cmd->convert_src || tmp != cmd->convert_src)
524 		err++;
525 
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++;
530 
531 	tmp = cmd->stop_src;
532 	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
533 	if (!cmd->stop_src || tmp != cmd->stop_src)
534 		err++;
535 
536 	if (err)
537 		return 1;
538 
539 
540 	/*
541 	 * step 2: make sure trigger sources
542 	 * are unique and mutually compatible
543 	 */
544 
545 	if (cmd->start_src != TRIG_NOW) {
546 		cmd->start_src = TRIG_NOW;
547 		err++;
548 	}
549 
550 	if (cmd->scan_begin_src != TRIG_FOLLOW) {
551 		cmd->scan_begin_src = TRIG_FOLLOW;
552 		err++;
553 	}
554 
555 	if (cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_TIMER) {
556 		cmd->convert_src = TRIG_TIMER;
557 		err++;
558 	}
559 
560 	if (cmd->scan_end_src != TRIG_COUNT) {
561 		cmd->scan_end_src = TRIG_COUNT;
562 		err++;
563 	}
564 
565 	if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
566 		err++;
567 
568 	if (err)
569 		return 2;
570 
571 
572 	/* step 3: make sure arguments are trivially compatible */
573 	if (cmd->start_arg != 0) {
574 		cmd->start_arg = 0;
575 		err++;
576 	}
577 
578 	if (cmd->scan_begin_arg != 0) {
579 		cmd->scan_begin_arg = 0;
580 		err++;
581 	}
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++;
586 		}
587 	} else {		/* TRIG_EXT */
588 		if (cmd->convert_arg != 0) {
589 			cmd->convert_arg = 0;
590 			err++;
591 		}
592 	}
593 
594 	if (cmd->scan_end_arg != cmd->chanlist_len) {
595 		cmd->scan_end_arg = cmd->chanlist_len;
596 		err++;
597 	}
598 	if (cmd->stop_src == TRIG_COUNT) {
599 		if (!cmd->stop_arg) {
600 			cmd->stop_arg = 1;
601 			err++;
602 		}
603 	} else {		/* TRIG_NONE */
604 		if (cmd->stop_arg != 0) {
605 			cmd->stop_arg = 0;
606 			err++;
607 		}
608 	}
609 
610 	if (err)
611 		return 3;
612 
613 
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++;
625 	}
626 
627 	if (err)
628 		return 4;
629 
630 
631 	/* step 5: complain about special chanlist considerations */
632 
633 	if (cmd->chanlist) {
634 		if (!check_channel_list(dev, s, cmd->chanlist,
635 					cmd->chanlist_len))
636 			return 5;	/*  incorrect channels list */
637 	}
638 
639 	return 0;
640 }
641 
pcl816_ai_cmd(struct comedi_device * dev,struct comedi_subdevice * s)642 static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
643 {
644 	unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq;
645 	struct comedi_cmd *cmd = &s->async->cmd;
646 	unsigned int seglen;
647 
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;
659 
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;
663 
664 		i8253_cascade_ns_to_timer(this_board->i8254_osc_base, &divisor1,
665 					  &divisor2, &cmd->convert_arg,
666 					  cmd->flags & TRIG_ROUND_MASK);
667 
668 		/*  PCL816 crash if any divisor is set to 1 */
669 		if (divisor1 == 1) {
670 			divisor1 = 2;
671 			divisor2 /= 2;
672 		}
673 		if (divisor2 == 1) {
674 			divisor2 = 2;
675 			divisor1 /= 2;
676 		}
677 	}
678 
679 	start_pacer(dev, -1, 0, 0);	/*  stop pacer */
680 
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);
686 
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;
693 
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;
700 	}
701 
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 */
709 	}
710 
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);
718 
719 			/*  how many DMA pages we must fill */
720 			devpriv->dma_runs_to_end = bytes /
721 			devpriv->hwdmasize[0];
722 
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;
730 
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);
739 	}
740 
741 	start_pacer(dev, 1, divisor1, divisor2);
742 	dmairq = ((devpriv->dma & 0x3) << 4) | (dev->irq & 0x7);
743 
744 	switch (cmd->convert_src) {
745 	case TRIG_TIMER:
746 		devpriv->int816_mode = INT_TYPE_AI1_DMA;
747 
748 		/*  Pacer+IRQ+DMA */
749 		outb(0x32, dev->iobase + PCL816_CONTROL);
750 
751 		/*  write irq and DMA to card */
752 		outb(dmairq, dev->iobase + PCL816_STATUS);
753 		break;
754 
755 	default:
756 		devpriv->int816_mode = INT_TYPE_AI3_DMA;
757 
758 		/*  Ext trig+IRQ+DMA */
759 		outb(0x34, dev->iobase + PCL816_CONTROL);
760 
761 		/*  write irq to card */
762 		outb(dmairq, dev->iobase + PCL816_STATUS);
763 		break;
764 	}
765 
766 	DPRINTK("pcl816 END: pcl812_ai_cmd()\n");
767 	return 0;
768 }
769 
pcl816_ai_poll(struct comedi_device * dev,struct comedi_subdevice * s)770 static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
771 {
772 	unsigned long flags;
773 	unsigned int top1, top2, i;
774 
775 	if (!devpriv->dma)
776 		return 0;	/*  poll is valid only for DMA transfer */
777 
778 	spin_lock_irqsave(&dev->spinlock, flags);
779 
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;
785 	}
786 	if (top1 != top2) {
787 		spin_unlock_irqrestore(&dev->spinlock, flags);
788 		return 0;
789 	}
790 
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;
798 	}
799 
800 	transfer_from_dma_buf(dev, s,
801 			      (short *)devpriv->dmabuf[devpriv->next_dma_buf],
802 			      devpriv->ai_poll_ptr, top2);
803 
804 	devpriv->ai_poll_ptr = top1;	/*  new buffer position */
805 	spin_unlock_irqrestore(&dev->spinlock, flags);
806 
807 	return s->async->buf_write_count - s->async->buf_read_count;
808 }
809 
810 /*
811 ==============================================================================
812  cancel any mode 1-4 AI
813 */
pcl816_ai_cancel(struct comedi_device * dev,struct comedi_subdevice * s)814 static int pcl816_ai_cancel(struct comedi_device *dev,
815 			    struct comedi_subdevice *s)
816 {
817 /* DEBUG(printk("pcl816_ai_cancel()\n");) */
818 
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 */
836 
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);
843 
844 			/* clear INT request */
845 			outb(0, dev->iobase + PCL816_CLRINT);
846 
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;
855 		}
856 	}
857 
858 	DEBUG(printk("comedi: pcl816_ai_cancel() successful\n");)
859 	    return 0;
860 }
861 
862 /*
863 ==============================================================================
864  chech for PCL816
865 */
pcl816_check(unsigned long iobase)866 static int pcl816_check(unsigned long iobase)
867 {
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 */
883 }
884 
885 /*
886 ==============================================================================
887  reset whole PCL-816 cards
888 */
pcl816_reset(struct comedi_device * dev)889 static void pcl816_reset(struct comedi_device *dev)
890 {
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);
904 }
905 
906 /*
907 ==============================================================================
908  Start/stop pacer onboard pacer
909 */
910 static void
start_pacer(struct comedi_device * dev,int mode,unsigned int divisor1,unsigned int divisor2)911 start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1,
912 	    unsigned int divisor2)
913 {
914 	outb(0x32, dev->iobase + PCL816_CTRCTL);
915 	outb(0xff, dev->iobase + PCL816_CTR0);
916 	outb(0x00, dev->iobase + PCL816_CTR0);
917 	udelay(1);
918 
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);
924 
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);
932 	}
933 
934 	/* clear pending interrupts (just in case) */
935 /* outb(0, dev->iobase + PCL816_CLRINT); */
936 }
937 
938 /*
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
942 */
943 static int
check_channel_list(struct comedi_device * dev,struct comedi_subdevice * s,unsigned int * chanlist,unsigned int chanlen)944 check_channel_list(struct comedi_device *dev,
945 		   struct comedi_subdevice *s, unsigned int *chanlist,
946 		   unsigned int chanlen)
947 {
948 	unsigned int chansegment[16];
949 	unsigned int i, nowmustbechan, seglen, segpos;
950 
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;
955 	}
956 
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]));)
965 
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;
980 			}
981 			/*  well, this is next correct channel in list */
982 			chansegment[i] = chanlist[i];
983 		}
984 
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 */
1004 			}
1005 		}
1006 	} else {
1007 		seglen = 1;
1008 	}
1009 
1010 	return seglen;	/*  we can serve this with MUX logic */
1011 }
1012 
1013 /*
1014 ==============================================================================
1015  Program scan/gain logic with channel list.
1016 */
1017 static void
setup_channel_list(struct comedi_device * dev,struct comedi_subdevice * s,unsigned int * chanlist,unsigned int seglen)1018 setup_channel_list(struct comedi_device *dev,
1019 		   struct comedi_subdevice *s, unsigned int *chanlist,
1020 		   unsigned int seglen)
1021 {
1022 	unsigned int i;
1023 
1024 	devpriv->ai_act_chanlist_len = seglen;
1025 	devpriv->ai_act_chanlist_pos = 0;
1026 
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);
1032 	}
1033 
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);
1039 }
1040 
1041 #ifdef unused
1042 /*
1043 ==============================================================================
1044   Enable(1)/disable(0) periodic interrupts from RTC
1045 */
set_rtc_irq_bit(unsigned char bit)1046 static int set_rtc_irq_bit(unsigned char bit)
1047 {
1048 	unsigned char val;
1049 	unsigned long flags;
1050 
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;
1061 	}
1062 
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;
1070 
1071 	CMOS_WRITE(val, RTC_CONTROL);
1072 	CMOS_READ(RTC_INTR_FLAGS);
1073 	restore_flags(flags);
1074 	return 0;
1075 }
1076 #endif
1077 
1078 /*
1079 ==============================================================================
1080   Free any resources that we have claimed
1081 */
free_resources(struct comedi_device * dev)1082 static void free_resources(struct comedi_device *dev)
1083 {
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);
1101 		}
1102 #endif
1103 	}
1104 
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"); */
1110 }
1111 
1112 /*
1113 ==============================================================================
1114 
1115    Initialization
1116 
1117 */
pcl816_attach(struct comedi_device * dev,struct comedi_devconfig * it)1118 static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1119 {
1120 	int ret;
1121 	unsigned long iobase;
1122 	unsigned int irq, dma;
1123 	unsigned long pages;
1124 	/* int i; */
1125 	struct comedi_subdevice *s;
1126 
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);
1131 
1132 	if (!request_region(iobase, this_board->io_range, "pcl816")) {
1133 		printk("I/O port conflict\n");
1134 		return -EIO;
1135 	}
1136 
1137 	dev->iobase = iobase;
1138 
1139 	if (pcl816_check(iobase)) {
1140 		printk(KERN_ERR ", I cann't detect board. FAIL!\n");
1141 		return -EIO;
1142 	}
1143 
1144 	ret = alloc_private(dev, sizeof(struct pcl816_private));
1145 	if (ret < 0)
1146 		return ret;	/* Can't alloc mem */
1147 
1148 	/* set up some name stuff */
1149 	dev->board_name = this_board->name;
1150 
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);
1170 				}
1171 			}
1172 		}
1173 	}
1174 
1175 	dev->irq = irq;
1176 	if (irq)	/* 1=we have allocated irq */
1177 		devpriv->irq_free = 1;
1178 	else
1179 		devpriv->irq_free = 0;
1180 
1181 	devpriv->irq_blocked = 0;	/* number of subdevice which use IRQ */
1182 	devpriv->int816_mode = 0;	/* mode of irq */
1183 
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;
1192 		}
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);
1208 			}
1209 			devpriv->rtc_iobase = 0;
1210 			devpriv->rtc_iosize = 0;
1211 		}
1212 #else
1213 		printk("pcl816: RTC code missing");
1214 #endif
1215 
1216 	}
1217 
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 */
1225 
1226 	if (this_board->DMAbits != 0) {	/* board support DMA */
1227 		dma = it->options[2];
1228 		if (dma < 1)
1229 			goto no_dma;	/* DMA disabled */
1230 
1231 		if (((1 << dma) & this_board->DMAbits) == 0) {
1232 			printk(", DMA is out of allowed range, FAIL!\n");
1233 			return -EINVAL;	/* Bad DMA */
1234 		}
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 */
1240 		}
1241 
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);
1246 
1247 		if (!devpriv->dmabuf[0]) {
1248 			printk(", unable to allocate DMA buffer, FAIL!\n");
1249 			/*
1250 			 * maybe experiment with try_to_free_pages()
1251 			 * will help ....
1252 			 */
1253 			return -EBUSY;	/* no buffer :-( */
1254 		}
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); */
1259 
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;
1267 			}
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;
1272 		}
1273 	}
1274 
1275 no_dma:
1276 
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;
1283 */
1284 
1285 	ret = alloc_subdevices(dev, 1);
1286 	if (ret < 0)
1287 		return ret;
1288 
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;
1308 	}
1309 
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;
1318 
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;
1326 
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
1335 
1336 	pcl816_reset(dev);
1337 
1338 	printk("\n");
1339 
1340 	return 0;
1341 }
1342 
1343 /*
1344 ==============================================================================
1345   Removes device
1346  */
pcl816_detach(struct comedi_device * dev)1347 static int pcl816_detach(struct comedi_device *dev)
1348 {
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;
1356 }
1357 
1358 MODULE_AUTHOR("Comedi http://www.comedi.org");
1359 MODULE_DESCRIPTION("Comedi low-level driver");
1360 MODULE_LICENSE("GPL");
1361