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