pcl818.c revision 139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88
1/*
2   comedi/drivers/pcl818.c
3
4   Author:  Michal Dobes <dobes@tesnet.cz>
5
6   hardware driver for Advantech cards:
7    card:   PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818, PCL-718
8    driver: pcl818l,  pcl818h,  pcl818hd,  pcl818hg,  pcl818,  pcl718
9*/
10/*
11Driver: pcl818
12Description: Advantech PCL-818 cards, PCL-718
13Author: Michal Dobes <dobes@tesnet.cz>
14Devices: [Advantech] PCL-818L (pcl818l), PCL-818H (pcl818h),
15  PCL-818HD (pcl818hd), PCL-818HG (pcl818hg), PCL-818 (pcl818),
16  PCL-718 (pcl718)
17Status: works
18
19All cards have 16 SE/8 DIFF ADCs, one or two DACs, 16 DI and 16 DO.
20Differences are only at maximal sample speed, range list and FIFO
21support.
22The driver support AI mode 0, 1, 3 other subdevices (AO, DI, DO) support
23only mode 0. If DMA/FIFO/INT are disabled then AI support only mode 0.
24PCL-818HD and PCL-818HG support 1kword FIFO. Driver support this FIFO
25but this code is untested.
26A word or two about DMA. Driver support DMA operations at two ways:
271) DMA uses two buffers and after one is filled then is generated
28   INT and DMA restart with second buffer. With this mode I'm unable run
29   more that 80Ksamples/secs without data dropouts on K6/233.
302) DMA uses one buffer and run in autoinit mode and the data are
31   from DMA buffer moved on the fly with 2kHz interrupts from RTC.
32   This mode is used if the interrupt 8 is available for allocation.
33   If not, then first DMA mode is used. With this I can run at
34   full speed one card (100ksamples/secs) or two cards with
35   60ksamples/secs each (more is problem on account of ISA limitations).
36   To use this mode you must have compiled  kernel with disabled
37   "Enhanced Real Time Clock Support".
38   Maybe you can have problems if you use xntpd or similar.
39   If you've data dropouts with DMA mode 2 then:
40    a) disable IDE DMA
41    b) switch text mode console to fb.
42
43   Options for PCL-818L:
44    [0] - IO Base
45    [1] - IRQ	(0=disable, 2, 3, 4, 5, 6, 7)
46    [2] - DMA	(0=disable, 1, 3)
47    [3] - 0, 10=10MHz clock for 8254
48              1= 1MHz clock for 8254
49    [4] - 0,  5=A/D input  -5V.. +5V
50          1, 10=A/D input -10V..+10V
51    [5] - 0,  5=D/A output 0-5V  (internal reference -5V)
52          1, 10=D/A output 0-10V (internal reference -10V)
53	  2    =D/A output unknow (external reference)
54
55   Options for PCL-818, PCL-818H:
56    [0] - IO Base
57    [1] - IRQ	(0=disable, 2, 3, 4, 5, 6, 7)
58    [2] - DMA	(0=disable, 1, 3)
59    [3] - 0, 10=10MHz clock for 8254
60              1= 1MHz clock for 8254
61    [4] - 0,  5=D/A output 0-5V  (internal reference -5V)
62          1, 10=D/A output 0-10V (internal reference -10V)
63	  2    =D/A output unknow (external reference)
64
65   Options for PCL-818HD, PCL-818HG:
66    [0] - IO Base
67    [1] - IRQ	(0=disable, 2, 3, 4, 5, 6, 7)
68    [2] - DMA/FIFO  (-1=use FIFO, 0=disable both FIFO and DMA,
69                      1=use DMA ch 1, 3=use DMA ch 3)
70    [3] - 0, 10=10MHz clock for 8254
71              1= 1MHz clock for 8254
72    [4] - 0,  5=D/A output 0-5V  (internal reference -5V)
73          1, 10=D/A output 0-10V (internal reference -10V)
74   	  2    =D/A output unknow (external reference)
75
76   Options for PCL-718:
77    [0] - IO Base
78    [1] - IRQ	(0=disable, 2, 3, 4, 5, 6, 7)
79    [2] - DMA	(0=disable, 1, 3)
80    [3] - 0, 10=10MHz clock for 8254
81              1= 1MHz clock for 8254
82    [4] -     0=A/D Range is +/-10V
83	      1=             +/-5V
84	      2=             +/-2.5V
85	      3=             +/-1V
86	      4=             +/-0.5V
87	      5=  	     user defined bipolar
88	      6=	     0-10V
89	      7=	     0-5V
90 	      8=	     0-2V
91	      9=	     0-1V
92	     10=	     user defined unipolar
93    [5] - 0,  5=D/A outputs 0-5V  (internal reference -5V)
94          1, 10=D/A outputs 0-10V (internal reference -10V)
95	      2=D/A outputs unknow (external reference)
96    [6] - 0, 60=max  60kHz A/D sampling
97          1,100=max 100kHz A/D sampling (PCL-718 with Option 001 installed)
98
99*/
100
101#include "../comedidev.h"
102
103#include <linux/ioport.h>
104#include <linux/mc146818rtc.h>
105#include <linux/delay.h>
106#include <asm/dma.h>
107
108#include "8253.h"
109
110// #define PCL818_MODE13_AO 1
111
112// boards constants
113
114#define boardPCL818L 0
115#define boardPCL818H 1
116#define boardPCL818HD 2
117#define boardPCL818HG 3
118#define boardPCL818 4
119#define boardPCL718 5
120
121// IO space len
122#define PCLx1x_RANGE 16
123// IO space len if we use FIFO
124#define PCLx1xFIFO_RANGE 32
125
126// W: clear INT request
127#define PCL818_CLRINT 8
128// R: return status byte
129#define PCL818_STATUS 8
130// R: A/D high byte W: A/D range control
131#define PCL818_RANGE 1
132// R: next mux scan channel W: mux scan channel & range control pointer
133#define PCL818_MUX 2
134// R/W: operation control register
135#define PCL818_CONTROL 9
136// W: counter enable
137#define PCL818_CNTENABLE 10
138
139// R: low byte of A/D W: soft A/D trigger
140#define PCL818_AD_LO 0
141// R: high byte of A/D W: A/D range control
142#define PCL818_AD_HI 1
143// W: D/A low&high byte
144#define PCL818_DA_LO 4
145#define PCL818_DA_HI 5
146// R: low&high byte of DI
147#define PCL818_DI_LO 3
148#define PCL818_DI_HI 11
149// W: low&high byte of DO
150#define PCL818_DO_LO 3
151#define PCL818_DO_HI 11
152// W: PCL718 second D/A
153#define PCL718_DA2_LO 6
154#define PCL718_DA2_HI 7
155// counters
156#define PCL818_CTR0 12
157#define PCL818_CTR1 13
158#define PCL818_CTR2 14
159// W: counter control
160#define PCL818_CTRCTL 15
161
162// W: fifo enable/disable
163#define PCL818_FI_ENABLE 6
164// W: fifo interrupt clear
165#define PCL818_FI_INTCLR 20
166// W: fifo interrupt clear
167#define PCL818_FI_FLUSH 25
168// R: fifo status
169#define PCL818_FI_STATUS 25
170// R: one record from FIFO
171#define PCL818_FI_DATALO 23
172#define PCL818_FI_DATAHI 23
173
174// type of interrupt handler
175#define INT_TYPE_AI1_INT 1
176#define INT_TYPE_AI1_DMA 2
177#define INT_TYPE_AI1_FIFO 3
178#define INT_TYPE_AI3_INT 4
179#define INT_TYPE_AI3_DMA 5
180#define INT_TYPE_AI3_FIFO 6
181#ifdef PCL818_MODE13_AO
182#define INT_TYPE_AO1_INT 7
183#define INT_TYPE_AO3_INT 8
184#endif
185
186#ifdef unused
187// RTC stuff...
188#define INT_TYPE_AI1_DMA_RTC 9
189#define INT_TYPE_AI3_DMA_RTC 10
190
191#define RTC_IRQ 	8
192#define RTC_IO_EXTENT	0x10
193#endif
194
195#define MAGIC_DMA_WORD 0x5a5a
196
197static const comedi_lrange range_pcl818h_ai = { 9, {
198			BIP_RANGE(5),
199			BIP_RANGE(2.5),
200			BIP_RANGE(1.25),
201			BIP_RANGE(0.625),
202			UNI_RANGE(10),
203			UNI_RANGE(5),
204			UNI_RANGE(2.5),
205			UNI_RANGE(1.25),
206			BIP_RANGE(10),
207	}
208};
209
210static const comedi_lrange range_pcl818hg_ai = { 10, {
211			BIP_RANGE(5),
212			BIP_RANGE(0.5),
213			BIP_RANGE(0.05),
214			BIP_RANGE(0.005),
215			UNI_RANGE(10),
216			UNI_RANGE(1),
217			UNI_RANGE(0.1),
218			UNI_RANGE(0.01),
219			BIP_RANGE(10),
220			BIP_RANGE(1),
221			BIP_RANGE(0.1),
222			BIP_RANGE(0.01),
223	}
224};
225
226static const comedi_lrange range_pcl818l_l_ai = { 4, {
227			BIP_RANGE(5),
228			BIP_RANGE(2.5),
229			BIP_RANGE(1.25),
230			BIP_RANGE(0.625),
231	}
232};
233
234static const comedi_lrange range_pcl818l_h_ai = { 4, {
235			BIP_RANGE(10),
236			BIP_RANGE(5),
237			BIP_RANGE(2.5),
238			BIP_RANGE(1.25),
239	}
240};
241
242static const comedi_lrange range718_bipolar1 = { 1, {BIP_RANGE(1),} };
243static const comedi_lrange range718_bipolar0_5 = { 1, {BIP_RANGE(0.5),} };
244static const comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} };
245static const comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} };
246
247static int pcl818_attach(struct comedi_device * dev, comedi_devconfig * it);
248static int pcl818_detach(struct comedi_device * dev);
249
250#ifdef unused
251static int RTC_lock = 0;	/* RTC lock */
252static int RTC_timer_lock = 0;	/* RTC int lock */
253#endif
254
255typedef struct {
256	const char *name;	// driver name
257	int n_ranges;		// len of range list
258	int n_aichan_se;	// num of A/D chans in single ended  mode
259	int n_aichan_diff;	// num of A/D chans in diferencial mode
260	unsigned int ns_min;	// minimal alllowed delay between samples (in ns)
261	int n_aochan;		// num of D/A chans
262	int n_dichan;		// num of DI chans
263	int n_dochan;		// num of DO chans
264	const comedi_lrange *ai_range_type;	// default A/D rangelist
265	const comedi_lrange *ao_range_type;	// default D/A rangelist
266	unsigned int io_range;	// len of IO space
267	unsigned int IRQbits;	// allowed interrupts
268	unsigned int DMAbits;	// allowed DMA chans
269	int ai_maxdata;		// maxdata for A/D
270	int ao_maxdata;		// maxdata for D/A
271	unsigned char fifo;	// 1=board has FIFO
272	int is_818;
273} boardtype;
274
275static const boardtype boardtypes[] = {
276	{"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
277			&range_unipolar5, PCLx1x_RANGE, 0x00fc,
278		0x0a, 0xfff, 0xfff, 0, 1},
279	{"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
280			&range_unipolar5, PCLx1x_RANGE, 0x00fc,
281		0x0a, 0xfff, 0xfff, 0, 1},
282	{"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
283			&range_unipolar5, PCLx1x_RANGE, 0x00fc,
284		0x0a, 0xfff, 0xfff, 1, 1},
285	{"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
286			&range_unipolar5, PCLx1x_RANGE, 0x00fc,
287		0x0a, 0xfff, 0xfff, 1, 1},
288	{"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
289			&range_unipolar5, PCLx1x_RANGE, 0x00fc,
290		0x0a, 0xfff, 0xfff, 0, 1},
291	{"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
292			&range_unipolar5, PCLx1x_RANGE, 0x00fc,
293		0x0a, 0xfff, 0xfff, 0, 0},
294	/* pcm3718 */
295	{"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
296			&range_unipolar5, PCLx1x_RANGE, 0x00fc,
297		0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
298};
299
300#define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype))
301
302static struct comedi_driver driver_pcl818 = {
303      driver_name:"pcl818",
304      module:THIS_MODULE,
305      attach:pcl818_attach,
306      detach:pcl818_detach,
307      board_name:&boardtypes[0].name,
308      num_names:n_boardtypes,
309      offset:sizeof(boardtype),
310};
311
312COMEDI_INITCLEANUP(driver_pcl818);
313
314typedef struct {
315	unsigned int dma;	// used DMA, 0=don't use DMA
316	int dma_rtc;		// 1=RTC used with DMA, 0=no RTC alloc
317	unsigned int io_range;
318#ifdef unused
319	unsigned long rtc_iobase;	// RTC port region
320	unsigned int rtc_iosize;
321	unsigned int rtc_irq;
322	struct timer_list rtc_irq_timer;	// timer for RTC sanity check
323	unsigned long rtc_freq;	// RTC int freq
324	int rtc_irq_blocked;	// 1=we now do AI with DMA&RTC
325#endif
326	unsigned long dmabuf[2];	// pointers to begin of DMA buffers
327	unsigned int dmapages[2];	// len of DMA buffers in PAGE_SIZEs
328	unsigned int hwdmaptr[2];	// hardware address of DMA buffers
329	unsigned int hwdmasize[2];	// len of DMA buffers in Bytes
330	unsigned int dmasamplsize;	// size in samples hwdmasize[0]/2
331	unsigned int last_top_dma;	// DMA pointer in last RTC int
332	int next_dma_buf;	// which DMA buffer will be used next round
333	long dma_runs_to_end;	// how many we must permorm DMA transfer to end of record
334	unsigned long last_dma_run;	// how many bytes we must transfer on last DMA page
335	unsigned char neverending_ai;	// if=1, then we do neverending record (you must use cancel())
336	unsigned int ns_min;	// manimal alllowed delay between samples (in us) for actual card
337	int i8253_osc_base;	// 1/frequency of on board oscilator in ns
338	int irq_free;		// 1=have allocated IRQ
339	int irq_blocked;	// 1=IRQ now uses any subdev
340	int irq_was_now_closed;	// when IRQ finish, there's stored int818_mode for last interrupt
341	int ai_mode;		// who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma
342	struct comedi_subdevice *last_int_sub;	// ptr to subdevice which now finish
343	int ai_act_scan;	// how many scans we finished
344	int ai_act_chan;	// actual position in actual scan
345	unsigned int act_chanlist[16];	// MUX setting for actual AI operations
346	unsigned int act_chanlist_len;	// how long is actual MUX list
347	unsigned int act_chanlist_pos;	// actual position in MUX list
348	unsigned int ai_scans;	// len of scanlist
349	unsigned int ai_n_chan;	// how many channels is measured
350	unsigned int *ai_chanlist;	// actaul chanlist
351	unsigned int ai_flags;	// flaglist
352	unsigned int ai_data_len;	// len of data buffer
353	short *ai_data;	// data buffer
354	unsigned int ai_timer1;	// timers
355	unsigned int ai_timer2;
356	struct comedi_subdevice *sub_ai;	// ptr to AI subdevice
357	unsigned char usefifo;	// 1=use fifo
358	unsigned int ao_readback[2];
359} pcl818_private;
360
361static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,	// used for gain list programming
362	0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
363};
364
365#define devpriv ((pcl818_private *)dev->private)
366#define this_board ((const boardtype *)dev->board_ptr)
367
368/*
369==============================================================================
370*/
371static void setup_channel_list(struct comedi_device * dev, struct comedi_subdevice * s,
372	unsigned int *chanlist, unsigned int n_chan, unsigned int seglen);
373static int check_channel_list(struct comedi_device * dev, struct comedi_subdevice * s,
374	unsigned int *chanlist, unsigned int n_chan);
375
376static int pcl818_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s);
377static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1,
378	unsigned int divisor2);
379
380#ifdef unused
381static int set_rtc_irq_bit(unsigned char bit);
382static void rtc_dropped_irq(unsigned long data);
383static int rtc_setfreq_irq(int freq);
384#endif
385
386/*
387==============================================================================
388   ANALOG INPUT MODE0, 818 cards, slow version
389*/
390static int pcl818_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
391	comedi_insn * insn, unsigned int * data)
392{
393	int n;
394	int timeout;
395
396	/* software trigger, DMA and INT off */
397	outb(0, dev->iobase + PCL818_CONTROL);
398
399	/* select channel */
400	outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX);
401
402	/* select gain */
403	outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE);
404
405	for (n = 0; n < insn->n; n++) {
406
407		/* clear INT (conversion end) flag */
408		outb(0, dev->iobase + PCL818_CLRINT);
409
410		/* start conversion */
411		outb(0, dev->iobase + PCL818_AD_LO);
412
413		timeout = 100;
414		while (timeout--) {
415			if (inb(dev->iobase + PCL818_STATUS) & 0x10)
416				goto conv_finish;
417			comedi_udelay(1);
418		}
419		comedi_error(dev, "A/D insn timeout");
420		/* clear INT (conversion end) flag */
421		outb(0, dev->iobase + PCL818_CLRINT);
422		return -EIO;
423
424	      conv_finish:
425		data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |
426			(inb(dev->iobase + PCL818_AD_LO) >> 4));
427	}
428
429	return n;
430}
431
432/*
433==============================================================================
434   ANALOG OUTPUT MODE0, 818 cards
435   only one sample per call is supported
436*/
437static int pcl818_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
438	comedi_insn * insn, unsigned int * data)
439{
440	int n;
441	int chan = CR_CHAN(insn->chanspec);
442
443	for (n = 0; n < insn->n; n++) {
444		data[n] = devpriv->ao_readback[chan];
445	}
446
447	return n;
448}
449
450static int pcl818_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s,
451	comedi_insn * insn, unsigned int * data)
452{
453	int n;
454	int chan = CR_CHAN(insn->chanspec);
455
456	for (n = 0; n < insn->n; n++) {
457		devpriv->ao_readback[chan] = data[n];
458		outb((data[n] & 0x000f) << 4, dev->iobase +
459			(chan) ? PCL718_DA2_LO : PCL818_DA_LO);
460		outb((data[n] & 0x0ff0) >> 4, dev->iobase +
461			(chan) ? PCL718_DA2_HI : PCL818_DA_HI);
462	}
463
464	return n;
465}
466
467/*
468==============================================================================
469   DIGITAL INPUT MODE0, 818 cards
470
471   only one sample per call is supported
472*/
473static int pcl818_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
474	comedi_insn * insn, unsigned int * data)
475{
476	if (insn->n != 2)
477		return -EINVAL;
478
479	data[1] = inb(dev->iobase + PCL818_DI_LO) |
480		(inb(dev->iobase + PCL818_DI_HI) << 8);
481
482	return 2;
483}
484
485/*
486==============================================================================
487   DIGITAL OUTPUT MODE0, 818 cards
488
489   only one sample per call is supported
490*/
491static int pcl818_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
492	comedi_insn * insn, unsigned int * data)
493{
494	if (insn->n != 2)
495		return -EINVAL;
496
497	s->state &= ~data[0];
498	s->state |= (data[0] & data[1]);
499
500	outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
501	outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
502
503	data[1] = s->state;
504
505	return 2;
506}
507
508/*
509==============================================================================
510   analog input interrupt mode 1 & 3, 818 cards
511   one sample per interrupt version
512*/
513static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
514{
515	struct comedi_device *dev = d;
516	struct comedi_subdevice *s = dev->subdevices + 0;
517	int low;
518	int timeout = 50;	/* wait max 50us */
519
520	while (timeout--) {
521		if (inb(dev->iobase + PCL818_STATUS) & 0x10)
522			goto conv_finish;
523		comedi_udelay(1);
524	}
525	outb(0, dev->iobase + PCL818_STATUS);	/* clear INT request */
526	comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
527	pcl818_ai_cancel(dev, s);
528	s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
529	comedi_event(dev, s);
530	return IRQ_HANDLED;
531
532      conv_finish:
533	low = inb(dev->iobase + PCL818_AD_LO);
534	comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4)));	// get one sample
535	outb(0, dev->iobase + PCL818_CLRINT);	/* clear INT request */
536
537	if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) {	// dropout!
538		rt_printk
539			("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
540			(low & 0xf),
541			devpriv->act_chanlist[devpriv->act_chanlist_pos]);
542		pcl818_ai_cancel(dev, s);
543		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
544		comedi_event(dev, s);
545		return IRQ_HANDLED;
546	}
547	if (s->async->cur_chan == 0) {
548		// rt_printk("E");
549		devpriv->ai_act_scan--;
550	}
551
552	if (!devpriv->neverending_ai) {
553		if (devpriv->ai_act_scan == 0) {	/* all data sampled */
554			pcl818_ai_cancel(dev, s);
555			s->async->events |= COMEDI_CB_EOA;
556		}
557	}
558	comedi_event(dev, s);
559	return IRQ_HANDLED;
560}
561
562/*
563==============================================================================
564   analog input dma mode 1 & 3, 818 cards
565*/
566static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
567{
568	struct comedi_device *dev = d;
569	struct comedi_subdevice *s = dev->subdevices + 0;
570	int i, len, bufptr;
571	unsigned long flags;
572	short *ptr;
573
574	disable_dma(devpriv->dma);
575	devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
576	if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) {	// switch dma bufs
577		set_dma_mode(devpriv->dma, DMA_MODE_READ);
578		flags = claim_dma_lock();
579		set_dma_addr(devpriv->dma,
580			devpriv->hwdmaptr[devpriv->next_dma_buf]);
581		if (devpriv->dma_runs_to_end || devpriv->neverending_ai) {
582			set_dma_count(devpriv->dma,
583				devpriv->hwdmasize[devpriv->next_dma_buf]);
584		} else {
585			set_dma_count(devpriv->dma, devpriv->last_dma_run);
586		}
587		release_dma_lock(flags);
588		enable_dma(devpriv->dma);
589	}
590	rt_printk("comedi: A/D mode1/3 IRQ \n");
591
592	devpriv->dma_runs_to_end--;
593	outb(0, dev->iobase + PCL818_CLRINT);	/* clear INT request */
594	ptr = (short *) devpriv->dmabuf[1 - devpriv->next_dma_buf];
595
596	len = devpriv->hwdmasize[0] >> 1;
597	bufptr = 0;
598
599	for (i = 0; i < len; i++) {
600		if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) {	// dropout!
601			rt_printk
602				("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
603				(ptr[bufptr] & 0xf),
604				devpriv->act_chanlist[devpriv->
605					act_chanlist_pos],
606				devpriv->act_chanlist_pos);
607			pcl818_ai_cancel(dev, s);
608			s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
609			comedi_event(dev, s);
610			return IRQ_HANDLED;
611		}
612
613		comedi_buf_put(s->async, ptr[bufptr++] >> 4);	// get one sample
614
615		devpriv->act_chanlist_pos++;
616		if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) {
617			devpriv->ai_act_scan--;
618			devpriv->act_chanlist_pos = 0;
619		}
620
621		if (!devpriv->neverending_ai)
622			if (devpriv->ai_act_scan == 0) {	/* all data sampled */
623				pcl818_ai_cancel(dev, s);
624				s->async->events |= COMEDI_CB_EOA;
625				comedi_event(dev, s);
626				// printk("done int ai13 dma\n");
627				return IRQ_HANDLED;
628			}
629	}
630
631	if (len > 0)
632		comedi_event(dev, s);
633	return IRQ_HANDLED;
634}
635
636#ifdef unused
637/*
638==============================================================================
639   analog input dma mode 1 & 3 over RTC, 818 cards
640*/
641static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d)
642{
643	struct comedi_device *dev = d;
644	struct comedi_subdevice *s = dev->subdevices + 0;
645	unsigned long tmp;
646	unsigned int top1, top2, i, bufptr;
647	long ofs_dats;
648	short *dmabuf = (short *) devpriv->dmabuf[0];
649
650	//outb(2,0x378);
651	switch (devpriv->ai_mode) {
652	case INT_TYPE_AI1_DMA_RTC:
653	case INT_TYPE_AI3_DMA_RTC:
654		tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
655		mod_timer(&devpriv->rtc_irq_timer,
656			jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
657
658		for (i = 0; i < 10; i++) {
659			top1 = get_dma_residue(devpriv->dma);
660			top2 = get_dma_residue(devpriv->dma);
661			if (top1 == top2)
662				break;
663		}
664
665		if (top1 != top2)
666			return IRQ_HANDLED;
667		top1 = devpriv->hwdmasize[0] - top1;	// where is now DMA in buffer
668		top1 >>= 1;
669		ofs_dats = top1 - devpriv->last_top_dma;	// new samples from last call
670		if (ofs_dats < 0)
671			ofs_dats = (devpriv->dmasamplsize) + ofs_dats;
672		if (!ofs_dats)
673			return IRQ_HANDLED;	// exit=no new samples from last call
674		// obsluz data
675		i = devpriv->last_top_dma - 1;
676		i &= (devpriv->dmasamplsize - 1);
677
678		if (dmabuf[i] != MAGIC_DMA_WORD) {	// DMA overflow!
679			comedi_error(dev, "A/D mode1/3 DMA buffer overflow!");
680			//rt_printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize);
681			pcl818_ai_cancel(dev, s);
682			s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
683			comedi_event(dev, s);
684			return IRQ_HANDLED;
685		}
686		//rt_printk("r %ld ",ofs_dats);
687
688		bufptr = devpriv->last_top_dma;
689
690		for (i = 0; i < ofs_dats; i++) {
691			if ((dmabuf[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) {	// dropout!
692				rt_printk
693					("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",
694					(dmabuf[bufptr] & 0xf),
695					devpriv->act_chanlist[devpriv->
696						act_chanlist_pos]);
697				pcl818_ai_cancel(dev, s);
698				s->async->events |=
699					COMEDI_CB_EOA | COMEDI_CB_ERROR;
700				comedi_event(dev, s);
701				return IRQ_HANDLED;
702			}
703
704			comedi_buf_put(s->async, dmabuf[bufptr++] >> 4);	// get one sample
705			bufptr &= (devpriv->dmasamplsize - 1);
706
707			if (s->async->cur_chan == 0) {
708				devpriv->ai_act_scan--;
709			}
710
711			if (!devpriv->neverending_ai)
712				if (devpriv->ai_act_scan == 0) {	/* all data sampled */
713					pcl818_ai_cancel(dev, s);
714					s->async->events |= COMEDI_CB_EOA;
715					comedi_event(dev, s);
716					//printk("done int ai13 dma\n");
717					return IRQ_HANDLED;
718				}
719		}
720
721		devpriv->last_top_dma = bufptr;
722		bufptr--;
723		bufptr &= (devpriv->dmasamplsize - 1);
724		dmabuf[bufptr] = MAGIC_DMA_WORD;
725		comedi_event(dev, s);
726		//outb(0,0x378);
727		return IRQ_HANDLED;
728	}
729
730	//outb(0,0x378);
731	return IRQ_HANDLED;
732}
733#endif
734
735/*
736==============================================================================
737   analog input interrupt mode 1 & 3, 818HD/HG cards
738*/
739static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
740{
741	struct comedi_device *dev = d;
742	struct comedi_subdevice *s = dev->subdevices + 0;
743	int i, len, lo;
744
745	outb(0, dev->iobase + PCL818_FI_INTCLR);	// clear fifo int request
746
747	lo = inb(dev->iobase + PCL818_FI_STATUS);
748
749	if (lo & 4) {
750		comedi_error(dev, "A/D mode1/3 FIFO overflow!");
751		pcl818_ai_cancel(dev, s);
752		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
753		comedi_event(dev, s);
754		return IRQ_HANDLED;
755	}
756
757	if (lo & 1) {
758		comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!");
759		pcl818_ai_cancel(dev, s);
760		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
761		comedi_event(dev, s);
762		return IRQ_HANDLED;
763	}
764
765	if (lo & 2) {
766		len = 512;
767	} else {
768		len = 0;
769	}
770
771	for (i = 0; i < len; i++) {
772		lo = inb(dev->iobase + PCL818_FI_DATALO);
773		if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) {	// dropout!
774			rt_printk
775				("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
776				(lo & 0xf),
777				devpriv->act_chanlist[devpriv->
778					act_chanlist_pos]);
779			pcl818_ai_cancel(dev, s);
780			s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
781			comedi_event(dev, s);
782			return IRQ_HANDLED;
783		}
784
785		comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4));	// get one sample
786
787		if (s->async->cur_chan == 0) {
788			devpriv->ai_act_scan--;
789		}
790
791		if (!devpriv->neverending_ai)
792			if (devpriv->ai_act_scan == 0) {	/* all data sampled */
793				pcl818_ai_cancel(dev, s);
794				s->async->events |= COMEDI_CB_EOA;
795				comedi_event(dev, s);
796				return IRQ_HANDLED;
797			}
798	}
799
800	if (len > 0)
801		comedi_event(dev, s);
802	return IRQ_HANDLED;
803}
804
805/*
806==============================================================================
807    INT procedure
808*/
809static irqreturn_t interrupt_pcl818(int irq, void *d PT_REGS_ARG)
810{
811	struct comedi_device *dev = d;
812
813	if (!dev->attached) {
814		comedi_error(dev, "premature interrupt");
815		return IRQ_HANDLED;
816	}
817	//rt_printk("I\n");
818
819	switch (devpriv->ai_mode) {
820	case INT_TYPE_AI1_DMA:
821	case INT_TYPE_AI3_DMA:
822		return interrupt_pcl818_ai_mode13_dma(irq, d);
823	case INT_TYPE_AI1_INT:
824	case INT_TYPE_AI3_INT:
825		return interrupt_pcl818_ai_mode13_int(irq, d);
826	case INT_TYPE_AI1_FIFO:
827	case INT_TYPE_AI3_FIFO:
828		return interrupt_pcl818_ai_mode13_fifo(irq, d);
829#ifdef PCL818_MODE13_AO
830	case INT_TYPE_AO1_INT:
831	case INT_TYPE_AO3_INT:
832		return interrupt_pcl818_ao_mode13_int(irq, d);
833#endif
834	default:
835		break;
836	}
837
838	outb(0, dev->iobase + PCL818_CLRINT);	/* clear INT request */
839
840	if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked)
841		|| (!devpriv->ai_mode)) {
842		if (devpriv->irq_was_now_closed) {
843			if (devpriv->neverending_ai &&
844				(devpriv->ai_mode == INT_TYPE_AI1_DMA
845					|| devpriv->ai_mode ==
846					INT_TYPE_AI3_DMA)) {
847				/* we had neverending ai but ai_cancel() has been called
848				   the cleanup from ai_cancel() has been delayed until know
849				   because the card doesn't seem to like being reprogrammed
850				   while a DMA transfer is in progress
851				 */
852				struct comedi_subdevice *s = dev->subdevices + 0;
853				devpriv->ai_mode = devpriv->irq_was_now_closed;
854				devpriv->irq_was_now_closed = 0;
855				devpriv->neverending_ai = 0;
856				pcl818_ai_cancel(dev, s);
857			}
858			devpriv->irq_was_now_closed = 0;
859			return IRQ_HANDLED;
860		}
861		comedi_error(dev, "bad IRQ!");
862		return IRQ_NONE;
863	}
864
865	comedi_error(dev, "IRQ from unknow source!");
866	return IRQ_NONE;
867}
868
869/*
870==============================================================================
871   ANALOG INPUT MODE 1 or 3 DMA , 818 cards
872*/
873static void pcl818_ai_mode13dma_int(int mode, struct comedi_device * dev,
874	struct comedi_subdevice * s)
875{
876	unsigned int flags;
877	unsigned int bytes;
878
879	rt_printk("mode13dma_int, mode: %d\n", mode);
880	disable_dma(devpriv->dma);	// disable dma
881	bytes = devpriv->hwdmasize[0];
882	if (!devpriv->neverending_ai) {
883		bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short);	// how many
884		devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0];	// how many DMA pages we must fiil
885		devpriv->last_dma_run = bytes % devpriv->hwdmasize[0];	//on last dma transfer must be moved
886		devpriv->dma_runs_to_end--;
887		if (devpriv->dma_runs_to_end >= 0)
888			bytes = devpriv->hwdmasize[0];
889	}
890
891	devpriv->next_dma_buf = 0;
892	set_dma_mode(devpriv->dma, DMA_MODE_READ);
893	flags = claim_dma_lock();
894	clear_dma_ff(devpriv->dma);
895	set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
896	set_dma_count(devpriv->dma, bytes);
897	release_dma_lock(flags);
898	enable_dma(devpriv->dma);
899
900	if (mode == 1) {
901		devpriv->ai_mode = INT_TYPE_AI1_DMA;
902		outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);	/* Pacer+IRQ+DMA */
903	} else {
904		devpriv->ai_mode = INT_TYPE_AI3_DMA;
905		outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);	/* Ext trig+IRQ+DMA */
906	};
907}
908
909#ifdef unused
910/*
911==============================================================================
912   ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards
913*/
914static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device * dev,
915	struct comedi_subdevice * s)
916{
917	unsigned int flags;
918	short *pole;
919
920	set_dma_mode(devpriv->dma, DMA_MODE_READ | DMA_AUTOINIT);
921	flags = claim_dma_lock();
922	clear_dma_ff(devpriv->dma);
923	set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
924	set_dma_count(devpriv->dma, devpriv->hwdmasize[0]);
925	release_dma_lock(flags);
926	enable_dma(devpriv->dma);
927	devpriv->last_top_dma = 0;	//devpriv->hwdmasize[0];
928	pole = (short *) devpriv->dmabuf[0];
929	devpriv->dmasamplsize = devpriv->hwdmasize[0] / 2;
930	pole[devpriv->dmasamplsize - 1] = MAGIC_DMA_WORD;
931#ifdef unused
932	devpriv->rtc_freq = rtc_setfreq_irq(2048);
933	devpriv->rtc_irq_timer.expires =
934		jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100;
935	devpriv->rtc_irq_timer.data = (unsigned long)dev;
936	devpriv->rtc_irq_timer.function = rtc_dropped_irq;
937
938	add_timer(&devpriv->rtc_irq_timer);
939#endif
940
941	if (mode == 1) {
942		devpriv->int818_mode = INT_TYPE_AI1_DMA_RTC;
943		outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);	/* Pacer+DMA */
944	} else {
945		devpriv->int818_mode = INT_TYPE_AI3_DMA_RTC;
946		outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);	/* Ext trig+DMA */
947	};
948}
949#endif
950
951/*
952==============================================================================
953   ANALOG INPUT MODE 1 or 3, 818 cards
954*/
955static int pcl818_ai_cmd_mode(int mode, struct comedi_device * dev,
956	struct comedi_subdevice * s)
957{
958	comedi_cmd *cmd = &s->async->cmd;
959	int divisor1, divisor2;
960	unsigned int seglen;
961
962	rt_printk("pcl818_ai_cmd_mode()\n");
963	if ((!dev->irq) && (!devpriv->dma_rtc)) {
964		comedi_error(dev, "IRQ not defined!");
965		return -EINVAL;
966	}
967
968	if (devpriv->irq_blocked)
969		return -EBUSY;
970
971	start_pacer(dev, -1, 0, 0);	// stop pacer
972
973	seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
974		devpriv->ai_n_chan);
975	if (seglen < 1)
976		return -EINVAL;
977	setup_channel_list(dev, s, devpriv->ai_chanlist,
978		devpriv->ai_n_chan, seglen);
979
980	comedi_udelay(1);
981
982	devpriv->ai_act_scan = devpriv->ai_scans;
983	devpriv->ai_act_chan = 0;
984	devpriv->irq_blocked = 1;
985	devpriv->irq_was_now_closed = 0;
986	devpriv->neverending_ai = 0;
987	devpriv->act_chanlist_pos = 0;
988	devpriv->dma_runs_to_end = 0;
989
990	if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
991		devpriv->neverending_ai = 1;	//well, user want neverending
992
993	if (mode == 1) {
994		i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
995			&divisor2, &cmd->convert_arg, TRIG_ROUND_NEAREST);
996		if (divisor1 == 1) {	/* PCL718/818 crash if any divisor is set to 1 */
997			divisor1 = 2;
998			divisor2 /= 2;
999		}
1000		if (divisor2 == 1) {
1001			divisor2 = 2;
1002			divisor1 /= 2;
1003		}
1004	}
1005
1006	outb(0, dev->iobase + PCL818_CNTENABLE);	/* enable pacer */
1007
1008	switch (devpriv->dma) {
1009	case 1:		// DMA
1010	case 3:
1011		if (devpriv->dma_rtc == 0) {
1012			pcl818_ai_mode13dma_int(mode, dev, s);
1013		}
1014#ifdef unused
1015		else {
1016			pcl818_ai_mode13dma_rtc(mode, dev, s);
1017		}
1018#else
1019		else {
1020			return -EINVAL;
1021		}
1022#endif
1023		break;
1024	case 0:		// IRQ
1025		// rt_printk("IRQ\n");
1026		if (mode == 1) {
1027			devpriv->ai_mode = INT_TYPE_AI1_INT;
1028			outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);	/* Pacer+IRQ */
1029		} else {
1030			devpriv->ai_mode = INT_TYPE_AI3_INT;
1031			outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);	/* Ext trig+IRQ */
1032		};
1033		break;
1034	case -1:		// FIFO
1035		outb(1, dev->iobase + PCL818_FI_ENABLE);	// enable FIFO
1036		if (mode == 1) {
1037			devpriv->ai_mode = INT_TYPE_AI1_FIFO;
1038			outb(0x03, dev->iobase + PCL818_CONTROL);	/* Pacer */
1039		} else {
1040			devpriv->ai_mode = INT_TYPE_AI3_FIFO;
1041			outb(0x02, dev->iobase + PCL818_CONTROL);
1042		};		/* Ext trig */
1043		break;
1044	}
1045
1046	start_pacer(dev, mode, divisor1, divisor2);
1047
1048#ifdef unused
1049	switch (devpriv->ai_mode) {
1050	case INT_TYPE_AI1_DMA_RTC:
1051	case INT_TYPE_AI3_DMA_RTC:
1052		set_rtc_irq_bit(1);	/* start RTC */
1053		break;
1054	}
1055#endif
1056	rt_printk("pcl818_ai_cmd_mode() end\n");
1057	return 0;
1058}
1059
1060#ifdef unused
1061/*
1062==============================================================================
1063   ANALOG OUTPUT MODE 1 or 3, 818 cards
1064*/
1065#ifdef PCL818_MODE13_AO
1066static int pcl818_ao_mode13(int mode, struct comedi_device * dev, struct comedi_subdevice * s,
1067	comedi_trig * it)
1068{
1069	int divisor1, divisor2;
1070
1071	if (!dev->irq) {
1072		comedi_error(dev, "IRQ not defined!");
1073		return -EINVAL;
1074	}
1075
1076	if (devpriv->irq_blocked)
1077		return -EBUSY;
1078
1079	start_pacer(dev, -1, 0, 0);	// stop pacer
1080
1081	devpriv->int13_act_scan = it->n;
1082	devpriv->int13_act_chan = 0;
1083	devpriv->irq_blocked = 1;
1084	devpriv->irq_was_now_closed = 0;
1085	devpriv->neverending_ai = 0;
1086	devpriv->act_chanlist_pos = 0;
1087
1088	if (mode == 1) {
1089		i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1090			&divisor2, &it->trigvar, TRIG_ROUND_NEAREST);
1091		if (divisor1 == 1) {	/* PCL818 crash if any divisor is set to 1 */
1092			divisor1 = 2;
1093			divisor2 /= 2;
1094		}
1095		if (divisor2 == 1) {
1096			divisor2 = 2;
1097			divisor1 /= 2;
1098		}
1099	}
1100
1101	outb(0, dev->iobase + PCL818_CNTENABLE);	/* enable pacer */
1102	if (mode == 1) {
1103		devpriv->int818_mode = INT_TYPE_AO1_INT;
1104		outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);	/* Pacer+IRQ */
1105	} else {
1106		devpriv->int818_mode = INT_TYPE_AO3_INT;
1107		outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);	/* Ext trig+IRQ */
1108	};
1109
1110	start_pacer(dev, mode, divisor1, divisor2);
1111
1112	return 0;
1113}
1114
1115/*
1116==============================================================================
1117   ANALOG OUTPUT MODE 1, 818 cards
1118*/
1119static int pcl818_ao_mode1(struct comedi_device * dev, struct comedi_subdevice * s,
1120	comedi_trig * it)
1121{
1122	return pcl818_ao_mode13(1, dev, s, it);
1123}
1124
1125/*
1126==============================================================================
1127   ANALOG OUTPUT MODE 3, 818 cards
1128*/
1129static int pcl818_ao_mode3(struct comedi_device * dev, struct comedi_subdevice * s,
1130	comedi_trig * it)
1131{
1132	return pcl818_ao_mode13(3, dev, s, it);
1133}
1134#endif
1135#endif
1136
1137/*
1138==============================================================================
1139 Start/stop pacer onboard pacer
1140*/
1141static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1,
1142	unsigned int divisor2)
1143{
1144	outb(0xb4, dev->iobase + PCL818_CTRCTL);
1145	outb(0x74, dev->iobase + PCL818_CTRCTL);
1146	comedi_udelay(1);
1147
1148	if (mode == 1) {
1149		outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
1150		outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
1151		outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
1152		outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
1153	}
1154}
1155
1156/*
1157==============================================================================
1158 Check if channel list from user is builded correctly
1159 If it's ok, then program scan/gain logic
1160*/
1161static int check_channel_list(struct comedi_device * dev, struct comedi_subdevice * s,
1162	unsigned int *chanlist, unsigned int n_chan)
1163{
1164	unsigned int chansegment[16];
1165	unsigned int i, nowmustbechan, seglen, segpos;
1166
1167	/* correct channel and range number check itself comedi/range.c */
1168	if (n_chan < 1) {
1169		comedi_error(dev, "range/channel list is empty!");
1170		return 0;
1171	}
1172
1173	if (n_chan > 1) {
1174		// first channel is everytime ok
1175		chansegment[0] = chanlist[0];
1176		// build part of chanlist
1177		for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
1178			// rt_printk("%d. %d %d\n",i,CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));
1179			// we detect loop, this must by finish
1180			if (chanlist[0] == chanlist[i])
1181				break;
1182			nowmustbechan =
1183				(CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1184			if (nowmustbechan != CR_CHAN(chanlist[i])) {	// channel list isn't continous :-(
1185				rt_printk
1186					("comedi%d: pcl818: channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1187					dev->minor, i, CR_CHAN(chanlist[i]),
1188					nowmustbechan, CR_CHAN(chanlist[0]));
1189				return 0;
1190			}
1191			// well, this is next correct channel in list
1192			chansegment[i] = chanlist[i];
1193		}
1194
1195		// check whole chanlist
1196		for (i = 0, segpos = 0; i < n_chan; i++) {
1197			//rt_printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));
1198			if (chanlist[i] != chansegment[i % seglen]) {
1199				rt_printk
1200					("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1201					dev->minor, i, CR_CHAN(chansegment[i]),
1202					CR_RANGE(chansegment[i]),
1203					CR_AREF(chansegment[i]),
1204					CR_CHAN(chanlist[i % seglen]),
1205					CR_RANGE(chanlist[i % seglen]),
1206					CR_AREF(chansegment[i % seglen]));
1207				return 0;	// chan/gain list is strange
1208			}
1209		}
1210	} else {
1211		seglen = 1;
1212	}
1213	rt_printk("check_channel_list: seglen %d\n", seglen);
1214	return seglen;
1215}
1216
1217static void setup_channel_list(struct comedi_device * dev, struct comedi_subdevice * s,
1218	unsigned int *chanlist, unsigned int n_chan, unsigned int seglen)
1219{
1220	int i;
1221
1222	devpriv->act_chanlist_len = seglen;
1223	devpriv->act_chanlist_pos = 0;
1224
1225	for (i = 0; i < seglen; i++) {	// store range list to card
1226		devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
1227		outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX);	/* select channel */
1228		outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE);	/* select gain */
1229	}
1230
1231	comedi_udelay(1);
1232
1233	/* select channel interval to scan */
1234	outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen -
1235				1] << 4), dev->iobase + PCL818_MUX);
1236}
1237
1238/*
1239==============================================================================
1240 Check if board is switched to SE (1) or DIFF(0) mode
1241*/
1242static int check_single_ended(unsigned int port)
1243{
1244	if (inb(port + PCL818_STATUS) & 0x20) {
1245		return 1;
1246	} else {
1247		return 0;
1248	}
1249}
1250
1251/*
1252==============================================================================
1253*/
1254static int ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s,
1255	comedi_cmd * cmd)
1256{
1257	int err = 0;
1258	int tmp, divisor1, divisor2;
1259
1260	/* step 1: make sure trigger sources are trivially valid */
1261
1262	tmp = cmd->start_src;
1263	cmd->start_src &= TRIG_NOW;
1264	if (!cmd->start_src || tmp != cmd->start_src)
1265		err++;
1266
1267	tmp = cmd->scan_begin_src;
1268	cmd->scan_begin_src &= TRIG_FOLLOW;
1269	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1270		err++;
1271
1272	tmp = cmd->convert_src;
1273	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
1274	if (!cmd->convert_src || tmp != cmd->convert_src)
1275		err++;
1276
1277	tmp = cmd->scan_end_src;
1278	cmd->scan_end_src &= TRIG_COUNT;
1279	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1280		err++;
1281
1282	tmp = cmd->stop_src;
1283	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
1284	if (!cmd->stop_src || tmp != cmd->stop_src)
1285		err++;
1286
1287	if (err) {
1288		return 1;
1289	}
1290
1291	/* step 2: make sure trigger sources are unique and mutually compatible */
1292
1293	if (cmd->start_src != TRIG_NOW) {
1294		cmd->start_src = TRIG_NOW;
1295		err++;
1296	}
1297	if (cmd->scan_begin_src != TRIG_FOLLOW) {
1298		cmd->scan_begin_src = TRIG_FOLLOW;
1299		err++;
1300	}
1301	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
1302		err++;
1303
1304	if (cmd->scan_end_src != TRIG_COUNT) {
1305		cmd->scan_end_src = TRIG_COUNT;
1306		err++;
1307	}
1308
1309	if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
1310		err++;
1311
1312	if (err) {
1313		return 2;
1314	}
1315
1316	/* step 3: make sure arguments are trivially compatible */
1317
1318	if (cmd->start_arg != 0) {
1319		cmd->start_arg = 0;
1320		err++;
1321	}
1322
1323	if (cmd->scan_begin_arg != 0) {
1324		cmd->scan_begin_arg = 0;
1325		err++;
1326	}
1327
1328	if (cmd->convert_src == TRIG_TIMER) {
1329		if (cmd->convert_arg < this_board->ns_min) {
1330			cmd->convert_arg = this_board->ns_min;
1331			err++;
1332		}
1333	} else {		/* TRIG_EXT */
1334		if (cmd->convert_arg != 0) {
1335			cmd->convert_arg = 0;
1336			err++;
1337		}
1338	}
1339
1340	if (!cmd->chanlist_len) {
1341		cmd->chanlist_len = 1;
1342		err++;
1343	}
1344	if (cmd->chanlist_len > s->n_chan) {
1345		cmd->chanlist_len = s->n_chan;
1346		err++;
1347	}
1348	if (cmd->scan_end_arg != cmd->chanlist_len) {
1349		cmd->scan_end_arg = cmd->chanlist_len;
1350		err++;
1351	}
1352	if (cmd->stop_src == TRIG_COUNT) {
1353		if (!cmd->stop_arg) {
1354			cmd->stop_arg = 1;
1355			err++;
1356		}
1357	} else {		/* TRIG_NONE */
1358		if (cmd->stop_arg != 0) {
1359			cmd->stop_arg = 0;
1360			err++;
1361		}
1362	}
1363
1364	if (err) {
1365		return 3;
1366	}
1367
1368	/* step 4: fix up any arguments */
1369
1370	if (cmd->convert_src == TRIG_TIMER) {
1371		tmp = cmd->convert_arg;
1372		i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1373			&divisor2, &cmd->convert_arg,
1374			cmd->flags & TRIG_ROUND_MASK);
1375		if (cmd->convert_arg < this_board->ns_min)
1376			cmd->convert_arg = this_board->ns_min;
1377		if (tmp != cmd->convert_arg)
1378			err++;
1379	}
1380
1381	if (err) {
1382		return 4;
1383	}
1384
1385	/* step 5: complain about special chanlist considerations */
1386
1387	if (cmd->chanlist) {
1388		if (!check_channel_list(dev, s, cmd->chanlist,
1389				cmd->chanlist_len))
1390			return 5;	// incorrect channels list
1391	}
1392
1393	return 0;
1394}
1395
1396/*
1397==============================================================================
1398*/
1399static int ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s)
1400{
1401	comedi_cmd *cmd = &s->async->cmd;
1402	int retval;
1403
1404	rt_printk("pcl818_ai_cmd()\n");
1405	devpriv->ai_n_chan = cmd->chanlist_len;
1406	devpriv->ai_chanlist = cmd->chanlist;
1407	devpriv->ai_flags = cmd->flags;
1408	devpriv->ai_data_len = s->async->prealloc_bufsz;
1409	devpriv->ai_data = s->async->prealloc_buf;
1410	devpriv->ai_timer1 = 0;
1411	devpriv->ai_timer2 = 0;
1412
1413	if (cmd->stop_src == TRIG_COUNT) {
1414		devpriv->ai_scans = cmd->stop_arg;
1415	} else {
1416		devpriv->ai_scans = 0;
1417	}
1418
1419	if (cmd->scan_begin_src == TRIG_FOLLOW) {	// mode 1, 3
1420		if (cmd->convert_src == TRIG_TIMER) {	// mode 1
1421			devpriv->ai_timer1 = cmd->convert_arg;
1422			retval = pcl818_ai_cmd_mode(1, dev, s);
1423			rt_printk("pcl818_ai_cmd() end\n");
1424			return retval;
1425		}
1426		if (cmd->convert_src == TRIG_EXT) {	// mode 3
1427			return pcl818_ai_cmd_mode(3, dev, s);
1428		}
1429	}
1430
1431	return -1;
1432}
1433
1434/*
1435==============================================================================
1436 cancel any mode 1-4 AI
1437*/
1438static int pcl818_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s)
1439{
1440	if (devpriv->irq_blocked > 0) {
1441		rt_printk("pcl818_ai_cancel()\n");
1442		devpriv->irq_was_now_closed = devpriv->ai_mode;
1443		devpriv->ai_mode = 0;
1444
1445		switch (devpriv->irq_was_now_closed) {
1446#ifdef unused
1447		case INT_TYPE_AI1_DMA_RTC:
1448		case INT_TYPE_AI3_DMA_RTC:
1449			set_rtc_irq_bit(0);	// stop RTC
1450			del_timer(&devpriv->rtc_irq_timer);
1451#endif
1452		case INT_TYPE_AI1_DMA:
1453		case INT_TYPE_AI3_DMA:
1454			if (devpriv->neverending_ai) {
1455				/* wait for running dma transfer to end, do cleanup in interrupt */
1456				goto end;
1457			}
1458			disable_dma(devpriv->dma);
1459		case INT_TYPE_AI1_INT:
1460		case INT_TYPE_AI3_INT:
1461		case INT_TYPE_AI1_FIFO:
1462		case INT_TYPE_AI3_FIFO:
1463#ifdef PCL818_MODE13_AO
1464		case INT_TYPE_AO1_INT:
1465		case INT_TYPE_AO3_INT:
1466#endif
1467			outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL);	/* Stop A/D */
1468			comedi_udelay(1);
1469			start_pacer(dev, -1, 0, 0);
1470			outb(0, dev->iobase + PCL818_AD_LO);
1471			inb(dev->iobase + PCL818_AD_LO);
1472			inb(dev->iobase + PCL818_AD_HI);
1473			outb(0, dev->iobase + PCL818_CLRINT);	/* clear INT request */
1474			outb(0, dev->iobase + PCL818_CONTROL);	/* Stop A/D */
1475			if (devpriv->usefifo) {	// FIFO shutdown
1476				outb(0, dev->iobase + PCL818_FI_INTCLR);
1477				outb(0, dev->iobase + PCL818_FI_FLUSH);
1478				outb(0, dev->iobase + PCL818_FI_ENABLE);
1479			}
1480			devpriv->irq_blocked = 0;
1481			devpriv->last_int_sub = s;
1482			devpriv->neverending_ai = 0;
1483			break;
1484		}
1485	}
1486
1487      end:
1488	rt_printk("pcl818_ai_cancel() end\n");
1489	return 0;
1490}
1491
1492/*
1493==============================================================================
1494 chech for PCL818
1495*/
1496static int pcl818_check(unsigned long iobase)
1497{
1498	outb(0x00, iobase + PCL818_MUX);
1499	comedi_udelay(1);
1500	if (inb(iobase + PCL818_MUX) != 0x00)
1501		return 1;	//there isn't card
1502	outb(0x55, iobase + PCL818_MUX);
1503	comedi_udelay(1);
1504	if (inb(iobase + PCL818_MUX) != 0x55)
1505		return 1;	//there isn't card
1506	outb(0x00, iobase + PCL818_MUX);
1507	comedi_udelay(1);
1508	outb(0x18, iobase + PCL818_CONTROL);
1509	comedi_udelay(1);
1510	if (inb(iobase + PCL818_CONTROL) != 0x18)
1511		return 1;	//there isn't card
1512	return 0;		// ok, card exist
1513}
1514
1515/*
1516==============================================================================
1517 reset whole PCL-818 cards
1518*/
1519static void pcl818_reset(struct comedi_device * dev)
1520{
1521	if (devpriv->usefifo) {	// FIFO shutdown
1522		outb(0, dev->iobase + PCL818_FI_INTCLR);
1523		outb(0, dev->iobase + PCL818_FI_FLUSH);
1524		outb(0, dev->iobase + PCL818_FI_ENABLE);
1525	}
1526	outb(0, dev->iobase + PCL818_DA_LO);	// DAC=0V
1527	outb(0, dev->iobase + PCL818_DA_HI);
1528	comedi_udelay(1);
1529	outb(0, dev->iobase + PCL818_DO_HI);	// DO=$0000
1530	outb(0, dev->iobase + PCL818_DO_LO);
1531	comedi_udelay(1);
1532	outb(0, dev->iobase + PCL818_CONTROL);
1533	outb(0, dev->iobase + PCL818_CNTENABLE);
1534	outb(0, dev->iobase + PCL818_MUX);
1535	outb(0, dev->iobase + PCL818_CLRINT);
1536	outb(0xb0, dev->iobase + PCL818_CTRCTL);	/* Stop pacer */
1537	outb(0x70, dev->iobase + PCL818_CTRCTL);
1538	outb(0x30, dev->iobase + PCL818_CTRCTL);
1539	if (this_board->is_818) {
1540		outb(0, dev->iobase + PCL818_RANGE);
1541	} else {
1542		outb(0, dev->iobase + PCL718_DA2_LO);
1543		outb(0, dev->iobase + PCL718_DA2_HI);
1544	}
1545}
1546
1547#ifdef unused
1548/*
1549==============================================================================
1550  Enable(1)/disable(0) periodic interrupts from RTC
1551*/
1552static int set_rtc_irq_bit(unsigned char bit)
1553{
1554	unsigned char val;
1555	unsigned long flags;
1556
1557	if (bit == 1) {
1558		RTC_timer_lock++;
1559		if (RTC_timer_lock > 1)
1560			return 0;
1561	} else {
1562		RTC_timer_lock--;
1563		if (RTC_timer_lock < 0)
1564			RTC_timer_lock = 0;
1565		if (RTC_timer_lock > 0)
1566			return 0;
1567	}
1568
1569	save_flags(flags);
1570	cli();
1571	val = CMOS_READ(RTC_CONTROL);
1572	if (bit) {
1573		val |= RTC_PIE;
1574	} else {
1575		val &= ~RTC_PIE;
1576	}
1577	CMOS_WRITE(val, RTC_CONTROL);
1578	CMOS_READ(RTC_INTR_FLAGS);
1579	restore_flags(flags);
1580	return 0;
1581}
1582
1583/*
1584==============================================================================
1585  Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers)
1586*/
1587static void rtc_dropped_irq(unsigned long data)
1588{
1589	struct comedi_device *dev = (void *)data;
1590	unsigned long flags, tmp;
1591
1592	switch (devpriv->int818_mode) {
1593	case INT_TYPE_AI1_DMA_RTC:
1594	case INT_TYPE_AI3_DMA_RTC:
1595		mod_timer(&devpriv->rtc_irq_timer,
1596			jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
1597		save_flags(flags);
1598		cli();
1599		tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);	/* restart */
1600		restore_flags(flags);
1601		break;
1602	};
1603}
1604
1605/*
1606==============================================================================
1607  Set frequency of interrupts from RTC
1608*/
1609static int rtc_setfreq_irq(int freq)
1610{
1611	int tmp = 0;
1612	int rtc_freq;
1613	unsigned char val;
1614	unsigned long flags;
1615
1616	if (freq < 2)
1617		freq = 2;
1618	if (freq > 8192)
1619		freq = 8192;
1620
1621	while (freq > (1 << tmp))
1622		tmp++;
1623
1624	rtc_freq = 1 << tmp;
1625
1626	save_flags(flags);
1627	cli();
1628	val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
1629	val |= (16 - tmp);
1630	CMOS_WRITE(val, RTC_FREQ_SELECT);
1631	restore_flags(flags);
1632	return rtc_freq;
1633}
1634#endif
1635
1636/*
1637==============================================================================
1638  Free any resources that we have claimed
1639*/
1640static void free_resources(struct comedi_device * dev)
1641{
1642	//rt_printk("free_resource()\n");
1643	if (dev->private) {
1644		pcl818_ai_cancel(dev, devpriv->sub_ai);
1645		pcl818_reset(dev);
1646		if (devpriv->dma)
1647			free_dma(devpriv->dma);
1648		if (devpriv->dmabuf[0])
1649			free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1650		if (devpriv->dmabuf[1])
1651			free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1652#ifdef unused
1653		if (devpriv->rtc_irq)
1654			comedi_free_irq(devpriv->rtc_irq, dev);
1655		if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1656			if (devpriv->rtc_iobase)
1657				release_region(devpriv->rtc_iobase,
1658					devpriv->rtc_iosize);
1659		}
1660		if (devpriv->dma_rtc)
1661			RTC_lock--;
1662#endif
1663	}
1664
1665	if (dev->irq)
1666		free_irq(dev->irq, dev);
1667	if (dev->iobase)
1668		release_region(dev->iobase, devpriv->io_range);
1669	//rt_printk("free_resource() end\n");
1670}
1671
1672/*
1673==============================================================================
1674
1675   Initialization
1676
1677*/
1678static int pcl818_attach(struct comedi_device * dev, comedi_devconfig * it)
1679{
1680	int ret;
1681	unsigned long iobase;
1682	unsigned int irq, dma;
1683	unsigned long pages;
1684	struct comedi_subdevice *s;
1685
1686	if ((ret = alloc_private(dev, sizeof(pcl818_private))) < 0)
1687		return ret;	/* Can't alloc mem */
1688
1689	/* claim our I/O space */
1690	iobase = it->options[0];
1691	printk("comedi%d: pcl818:  board=%s, ioport=0x%03lx",
1692		dev->minor, this_board->name, iobase);
1693	devpriv->io_range = this_board->io_range;
1694	if ((this_board->fifo) && (it->options[2] == -1)) {	// we've board with FIFO and we want to use FIFO
1695		devpriv->io_range = PCLx1xFIFO_RANGE;
1696		devpriv->usefifo = 1;
1697	}
1698	if (!request_region(iobase, devpriv->io_range, "pcl818")) {
1699		rt_printk("I/O port conflict\n");
1700		return -EIO;
1701	}
1702
1703	dev->iobase = iobase;
1704
1705	if (pcl818_check(iobase)) {
1706		rt_printk(", I can't detect board. FAIL!\n");
1707		return -EIO;
1708	}
1709
1710	/* set up some name stuff */
1711	dev->board_name = this_board->name;
1712	/* grab our IRQ */
1713	irq = 0;
1714	if (this_board->IRQbits != 0) {	/* board support IRQ */
1715		irq = it->options[1];
1716		if (irq) {	/* we want to use IRQ */
1717			if (((1 << irq) & this_board->IRQbits) == 0) {
1718				rt_printk
1719					(", IRQ %u is out of allowed range, DISABLING IT",
1720					irq);
1721				irq = 0;	/* Bad IRQ */
1722			} else {
1723				if (comedi_request_irq(irq, interrupt_pcl818, 0,
1724						"pcl818", dev)) {
1725					rt_printk
1726						(", unable to allocate IRQ %u, DISABLING IT",
1727						irq);
1728					irq = 0;	/* Can't use IRQ */
1729				} else {
1730					rt_printk(", irq=%u", irq);
1731				}
1732			}
1733		}
1734	}
1735
1736	dev->irq = irq;
1737	if (irq) {
1738		devpriv->irq_free = 1;
1739	} /* 1=we have allocated irq */
1740	else {
1741		devpriv->irq_free = 0;
1742	}
1743	devpriv->irq_blocked = 0;	/* number of subdevice which use IRQ */
1744	devpriv->ai_mode = 0;	/* mode of irq */
1745
1746#ifdef unused
1747	/* grab RTC for DMA operations */
1748	devpriv->dma_rtc = 0;
1749	if (it->options[2] > 0) {	// we want to use DMA
1750		if (RTC_lock == 0) {
1751			if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
1752					"pcl818 (RTC)"))
1753				goto no_rtc;
1754		}
1755		devpriv->rtc_iobase = RTC_PORT(0);
1756		devpriv->rtc_iosize = RTC_IO_EXTENT;
1757		RTC_lock++;
1758		if (!comedi_request_irq(RTC_IRQ,
1759				interrupt_pcl818_ai_mode13_dma_rtc, 0,
1760				"pcl818 DMA (RTC)", dev)) {
1761			devpriv->dma_rtc = 1;
1762			devpriv->rtc_irq = RTC_IRQ;
1763			rt_printk(", dma_irq=%u", devpriv->rtc_irq);
1764		} else {
1765			RTC_lock--;
1766			if (RTC_lock == 0) {
1767				if (devpriv->rtc_iobase)
1768					release_region(devpriv->rtc_iobase,
1769						devpriv->rtc_iosize);
1770			}
1771			devpriv->rtc_iobase = 0;
1772			devpriv->rtc_iosize = 0;
1773		}
1774	}
1775
1776      no_rtc:
1777#endif
1778	/* grab our DMA */
1779	dma = 0;
1780	devpriv->dma = dma;
1781	if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1782		goto no_dma;	/* if we haven't IRQ, we can't use DMA */
1783	if (this_board->DMAbits != 0) {	/* board support DMA */
1784		dma = it->options[2];
1785		if (dma < 1)
1786			goto no_dma;	/* DMA disabled */
1787		if (((1 << dma) & this_board->DMAbits) == 0) {
1788			rt_printk(", DMA is out of allowed range, FAIL!\n");
1789			return -EINVAL;	/* Bad DMA */
1790		}
1791		ret = request_dma(dma, "pcl818");
1792		if (ret) {
1793			rt_printk(", unable to allocate DMA %u, FAIL!\n", dma);
1794			return -EBUSY;	/* DMA isn't free */
1795		}
1796		devpriv->dma = dma;
1797		rt_printk(", dma=%u", dma);
1798		pages = 2;	/* we need 16KB */
1799		devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1800		if (!devpriv->dmabuf[0]) {
1801			rt_printk(", unable to allocate DMA buffer, FAIL!\n");
1802			/* maybe experiment with try_to_free_pages() will help .... */
1803			return -EBUSY;	/* no buffer :-( */
1804		}
1805		devpriv->dmapages[0] = pages;
1806		devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1807		devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
1808		//rt_printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE);
1809		if (devpriv->dma_rtc == 0) {	// we must do duble buff :-(
1810			devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1811			if (!devpriv->dmabuf[1]) {
1812				rt_printk
1813					(", unable to allocate DMA buffer, FAIL!\n");
1814				return -EBUSY;
1815			}
1816			devpriv->dmapages[1] = pages;
1817			devpriv->hwdmaptr[1] =
1818				virt_to_bus((void *)devpriv->dmabuf[1]);
1819			devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1820		}
1821	}
1822
1823      no_dma:
1824
1825	if ((ret = alloc_subdevices(dev, 4)) < 0)
1826		return ret;
1827
1828	s = dev->subdevices + 0;
1829	if (!this_board->n_aichan_se) {
1830		s->type = COMEDI_SUBD_UNUSED;
1831	} else {
1832		s->type = COMEDI_SUBD_AI;
1833		devpriv->sub_ai = s;
1834		s->subdev_flags = SDF_READABLE;
1835		if (check_single_ended(dev->iobase)) {
1836			s->n_chan = this_board->n_aichan_se;
1837			s->subdev_flags |= SDF_COMMON | SDF_GROUND;
1838			printk(", %dchans S.E. DAC", s->n_chan);
1839		} else {
1840			s->n_chan = this_board->n_aichan_diff;
1841			s->subdev_flags |= SDF_DIFF;
1842			printk(", %dchans DIFF DAC", s->n_chan);
1843		}
1844		s->maxdata = this_board->ai_maxdata;
1845		s->len_chanlist = s->n_chan;
1846		s->range_table = this_board->ai_range_type;
1847		s->cancel = pcl818_ai_cancel;
1848		s->insn_read = pcl818_ai_insn_read;
1849		if ((irq) || (devpriv->dma_rtc)) {
1850			dev->read_subdev = s;
1851			s->subdev_flags |= SDF_CMD_READ;
1852			s->do_cmdtest = ai_cmdtest;
1853			s->do_cmd = ai_cmd;
1854		}
1855		if (this_board->is_818) {
1856			if ((it->options[4] == 1) || (it->options[4] == 10))
1857				s->range_table = &range_pcl818l_h_ai;	// secondary range list jumper selectable
1858		} else {
1859			switch (it->options[4]) {
1860			case 0:
1861				s->range_table = &range_bipolar10;
1862				break;
1863			case 1:
1864				s->range_table = &range_bipolar5;
1865				break;
1866			case 2:
1867				s->range_table = &range_bipolar2_5;
1868				break;
1869			case 3:
1870				s->range_table = &range718_bipolar1;
1871				break;
1872			case 4:
1873				s->range_table = &range718_bipolar0_5;
1874				break;
1875			case 6:
1876				s->range_table = &range_unipolar10;
1877				break;
1878			case 7:
1879				s->range_table = &range_unipolar5;
1880				break;
1881			case 8:
1882				s->range_table = &range718_unipolar2;
1883				break;
1884			case 9:
1885				s->range_table = &range718_unipolar1;
1886				break;
1887			default:
1888				s->range_table = &range_unknown;
1889				break;
1890			}
1891		}
1892	}
1893
1894	s = dev->subdevices + 1;
1895	if (!this_board->n_aochan) {
1896		s->type = COMEDI_SUBD_UNUSED;
1897	} else {
1898		s->type = COMEDI_SUBD_AO;
1899		s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1900		s->n_chan = this_board->n_aochan;
1901		s->maxdata = this_board->ao_maxdata;
1902		s->len_chanlist = this_board->n_aochan;
1903		s->range_table = this_board->ao_range_type;
1904		s->insn_read = pcl818_ao_insn_read;
1905		s->insn_write = pcl818_ao_insn_write;
1906#ifdef unused
1907#ifdef PCL818_MODE13_AO
1908		if (irq) {
1909			s->trig[1] = pcl818_ao_mode1;
1910			s->trig[3] = pcl818_ao_mode3;
1911		}
1912#endif
1913#endif
1914		if (this_board->is_818) {
1915			if ((it->options[4] == 1) || (it->options[4] == 10))
1916				s->range_table = &range_unipolar10;
1917			if (it->options[4] == 2)
1918				s->range_table = &range_unknown;
1919		} else {
1920			if ((it->options[5] == 1) || (it->options[5] == 10))
1921				s->range_table = &range_unipolar10;
1922			if (it->options[5] == 2)
1923				s->range_table = &range_unknown;
1924		}
1925	}
1926
1927	s = dev->subdevices + 2;
1928	if (!this_board->n_dichan) {
1929		s->type = COMEDI_SUBD_UNUSED;
1930	} else {
1931		s->type = COMEDI_SUBD_DI;
1932		s->subdev_flags = SDF_READABLE;
1933		s->n_chan = this_board->n_dichan;
1934		s->maxdata = 1;
1935		s->len_chanlist = this_board->n_dichan;
1936		s->range_table = &range_digital;
1937		s->insn_bits = pcl818_di_insn_bits;
1938	}
1939
1940	s = dev->subdevices + 3;
1941	if (!this_board->n_dochan) {
1942		s->type = COMEDI_SUBD_UNUSED;
1943	} else {
1944		s->type = COMEDI_SUBD_DO;
1945		s->subdev_flags = SDF_WRITABLE;
1946		s->n_chan = this_board->n_dochan;
1947		s->maxdata = 1;
1948		s->len_chanlist = this_board->n_dochan;
1949		s->range_table = &range_digital;
1950		s->insn_bits = pcl818_do_insn_bits;
1951	}
1952
1953	/* select 1/10MHz oscilator */
1954	if ((it->options[3] == 0) || (it->options[3] == 10)) {
1955		devpriv->i8253_osc_base = 100;
1956	} else {
1957		devpriv->i8253_osc_base = 1000;
1958	}
1959
1960	/* max sampling speed */
1961	devpriv->ns_min = this_board->ns_min;
1962
1963	if (!this_board->is_818) {
1964		if ((it->options[6] == 1) || (it->options[6] == 100))
1965			devpriv->ns_min = 10000;	/* extended PCL718 to 100kHz DAC */
1966	}
1967
1968	pcl818_reset(dev);
1969
1970	rt_printk("\n");
1971
1972	return 0;
1973}
1974
1975/*
1976==============================================================================
1977  Removes device
1978 */
1979static int pcl818_detach(struct comedi_device * dev)
1980{
1981	//  rt_printk("comedi%d: pcl818: remove\n", dev->minor);
1982	free_resources(dev);
1983	return 0;
1984}
1985