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