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 unknown (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 unknown (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 unknown (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 unknown (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 <linux/module.h>
102#include <linux/gfp.h>
103#include <linux/delay.h>
104#include <linux/io.h>
105#include <linux/interrupt.h>
106#include <asm/dma.h>
107
108#include "../comedidev.h"
109
110#include "comedi_fc.h"
111#include "8253.h"
112
113/* boards constants */
114
115#define boardPCL818L 0
116#define boardPCL818H 1
117#define boardPCL818HD 2
118#define boardPCL818HG 3
119#define boardPCL818 4
120#define boardPCL718 5
121
122/*
123 * Register I/O map
124 */
125#define PCL818_AI_LSB_REG			0x00
126#define PCL818_AI_MSB_REG			0x01
127#define PCL818_RANGE_REG			0x01
128#define PCL818_MUX_REG				0x02
129#define PCL818_MUX_SCAN(_first, _last)		(((_last) << 4) | (_first))
130#define PCL818_DO_DI_LSB_REG			0x03
131#define PCL818_AO_LSB_REG(x)			(0x04 + ((x) * 2))
132#define PCL818_AO_MSB_REG(x)			(0x05 + ((x) * 2))
133#define PCL818_STATUS_REG			0x08
134#define PCL818_STATUS_NEXT_CHAN_MASK		(0xf << 0)
135#define PCL818_STATUS_INT			(1 << 4)
136#define PCL818_STATUS_MUX			(1 << 5)
137#define PCL818_STATUS_UNI			(1 << 6)
138#define PCL818_STATUS_EOC			(1 << 7)
139#define PCL818_CTRL_REG				0x09
140#define PCL818_CTRL_DISABLE_TRIG		(0 << 0)
141#define PCL818_CTRL_SOFT_TRIG			(1 << 0)
142#define PCL818_CTRL_EXT_TRIG			(2 << 0)
143#define PCL818_CTRL_PACER_TRIG			(3 << 0)
144#define PCL818_CTRL_DMAE			(1 << 2)
145#define PCL818_CTRL_IRQ(x)			((x) << 4)
146#define PCL818_CTRL_INTE			(1 << 7)
147#define PCL818_CNTENABLE_REG			0x0a
148#define PCL818_CNTENABLE_PACER_ENA		(0 << 0)
149#define PCL818_CNTENABLE_PACER_TRIG0		(1 << 0)
150#define PCL818_CNTENABLE_CNT0_EXT_CLK		(0 << 1)
151#define PCL818_CNTENABLE_CNT0_INT_CLK		(1 << 1)
152#define PCL818_DO_DI_MSB_REG			0x0b
153#define PCL818_TIMER_BASE			0x0c
154
155/* W: fifo enable/disable */
156#define PCL818_FI_ENABLE 6
157/* W: fifo interrupt clear */
158#define PCL818_FI_INTCLR 20
159/* W: fifo interrupt clear */
160#define PCL818_FI_FLUSH 25
161/* R: fifo status */
162#define PCL818_FI_STATUS 25
163/* R: one record from FIFO */
164#define PCL818_FI_DATALO 23
165#define PCL818_FI_DATAHI 24
166
167#define MAGIC_DMA_WORD 0x5a5a
168
169static const struct comedi_lrange range_pcl818h_ai = {
170	9, {
171		BIP_RANGE(5),
172		BIP_RANGE(2.5),
173		BIP_RANGE(1.25),
174		BIP_RANGE(0.625),
175		UNI_RANGE(10),
176		UNI_RANGE(5),
177		UNI_RANGE(2.5),
178		UNI_RANGE(1.25),
179		BIP_RANGE(10)
180	}
181};
182
183static const struct comedi_lrange range_pcl818hg_ai = {
184	10, {
185		BIP_RANGE(5),
186		BIP_RANGE(0.5),
187		BIP_RANGE(0.05),
188		BIP_RANGE(0.005),
189		UNI_RANGE(10),
190		UNI_RANGE(1),
191		UNI_RANGE(0.1),
192		UNI_RANGE(0.01),
193		BIP_RANGE(10),
194		BIP_RANGE(1),
195		BIP_RANGE(0.1),
196		BIP_RANGE(0.01)
197	}
198};
199
200static const struct comedi_lrange range_pcl818l_l_ai = {
201	4, {
202		BIP_RANGE(5),
203		BIP_RANGE(2.5),
204		BIP_RANGE(1.25),
205		BIP_RANGE(0.625)
206	}
207};
208
209static const struct comedi_lrange range_pcl818l_h_ai = {
210	4, {
211		BIP_RANGE(10),
212		BIP_RANGE(5),
213		BIP_RANGE(2.5),
214		BIP_RANGE(1.25)
215	}
216};
217
218static const struct comedi_lrange range718_bipolar1 = {
219	1, {
220		BIP_RANGE(1)
221	}
222};
223
224static const struct comedi_lrange range718_bipolar0_5 = {
225	1, {
226		BIP_RANGE(0.5)
227	}
228};
229
230static const struct comedi_lrange range718_unipolar2 = {
231	1, {
232		UNI_RANGE(2)
233	}
234};
235
236static const struct comedi_lrange range718_unipolar1 = {
237	1, {
238		BIP_RANGE(1)
239	}
240};
241
242struct pcl818_board {
243	const char *name;
244	unsigned int ns_min;
245	int n_aochan;
246	const struct comedi_lrange *ai_range_type;
247	unsigned int has_dma:1;
248	unsigned int has_fifo:1;
249	unsigned int is_818:1;
250};
251
252static const struct pcl818_board boardtypes[] = {
253	{
254		.name		= "pcl818l",
255		.ns_min		= 25000,
256		.n_aochan	= 1,
257		.ai_range_type	= &range_pcl818l_l_ai,
258		.has_dma	= 1,
259		.is_818		= 1,
260	}, {
261		.name		= "pcl818h",
262		.ns_min		= 10000,
263		.n_aochan	= 1,
264		.ai_range_type	= &range_pcl818h_ai,
265		.has_dma	= 1,
266		.is_818		= 1,
267	}, {
268		.name		= "pcl818hd",
269		.ns_min		= 10000,
270		.n_aochan	= 1,
271		.ai_range_type	= &range_pcl818h_ai,
272		.has_dma	= 1,
273		.has_fifo	= 1,
274		.is_818		= 1,
275	}, {
276		.name		= "pcl818hg",
277		.ns_min		= 10000,
278		.n_aochan	= 1,
279		.ai_range_type	= &range_pcl818hg_ai,
280		.has_dma	= 1,
281		.has_fifo	= 1,
282		.is_818		= 1,
283	}, {
284		.name		= "pcl818",
285		.ns_min		= 10000,
286		.n_aochan	= 2,
287		.ai_range_type	= &range_pcl818h_ai,
288		.has_dma	= 1,
289		.is_818		= 1,
290	}, {
291		.name		= "pcl718",
292		.ns_min		= 16000,
293		.n_aochan	= 2,
294		.ai_range_type	= &range_unipolar5,
295		.has_dma	= 1,
296	}, {
297		.name		= "pcm3718",
298		.ns_min		= 10000,
299		.ai_range_type	= &range_pcl818h_ai,
300		.has_dma	= 1,
301		.is_818		= 1,
302	},
303};
304
305struct pcl818_private {
306	unsigned int dma;	/*  used DMA, 0=don't use DMA */
307	unsigned int dmapages;
308	unsigned int hwdmasize;
309	unsigned long dmabuf[2];	/*  pointers to begin of DMA buffers */
310	unsigned int hwdmaptr[2];	/*  hardware address of DMA buffers */
311	int next_dma_buf;	/*  which DMA buffer will be used next round */
312	long dma_runs_to_end;	/*  how many we must permorm DMA transfer to end of record */
313	unsigned long last_dma_run;	/*  how many bytes we must transfer on last DMA page */
314	unsigned int ns_min;	/*  manimal allowed delay between samples (in us) for actual card */
315	int i8253_osc_base;	/*  1/frequency of on board oscilator in ns */
316	int ai_act_scan;	/*  how many scans we finished */
317	int ai_act_chan;	/*  actual position in actual scan */
318	unsigned int act_chanlist[16];	/*  MUX setting for actual AI operations */
319	unsigned int act_chanlist_len;	/*  how long is actual MUX list */
320	unsigned int act_chanlist_pos;	/*  actual position in MUX list */
321	unsigned int ai_data_len;	/*  len of data buffer */
322	unsigned int divisor1;
323	unsigned int divisor2;
324	unsigned int usefifo:1;
325	unsigned int ai_cmd_running:1;
326	unsigned int ai_cmd_canceled:1;
327};
328
329static void pcl818_start_pacer(struct comedi_device *dev, bool load_counters)
330{
331	struct pcl818_private *devpriv = dev->private;
332	unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE;
333
334	i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
335	i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
336	udelay(1);
337
338	if (load_counters) {
339		i8254_write(timer_base, 0, 2, devpriv->divisor2);
340		i8254_write(timer_base, 0, 1, devpriv->divisor1);
341	}
342}
343
344static void pcl818_ai_setup_dma(struct comedi_device *dev,
345				struct comedi_subdevice *s)
346{
347	struct pcl818_private *devpriv = dev->private;
348	struct comedi_cmd *cmd = &s->async->cmd;
349	unsigned int flags;
350	unsigned int bytes;
351
352	disable_dma(devpriv->dma);	/*  disable dma */
353	bytes = devpriv->hwdmasize;
354	if (cmd->stop_src == TRIG_COUNT) {
355		bytes = cmd->stop_arg * cfc_bytes_per_scan(s);
356		devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize;
357		devpriv->last_dma_run = bytes % devpriv->hwdmasize;
358		devpriv->dma_runs_to_end--;
359		if (devpriv->dma_runs_to_end >= 0)
360			bytes = devpriv->hwdmasize;
361	}
362
363	devpriv->next_dma_buf = 0;
364	set_dma_mode(devpriv->dma, DMA_MODE_READ);
365	flags = claim_dma_lock();
366	clear_dma_ff(devpriv->dma);
367	set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
368	set_dma_count(devpriv->dma, bytes);
369	release_dma_lock(flags);
370	enable_dma(devpriv->dma);
371}
372
373static void pcl818_ai_setup_next_dma(struct comedi_device *dev,
374				     struct comedi_subdevice *s)
375{
376	struct pcl818_private *devpriv = dev->private;
377	struct comedi_cmd *cmd = &s->async->cmd;
378	unsigned long flags;
379
380	disable_dma(devpriv->dma);
381	devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
382	if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) {
383		/* switch dma bufs */
384		set_dma_mode(devpriv->dma, DMA_MODE_READ);
385		flags = claim_dma_lock();
386		set_dma_addr(devpriv->dma,
387			     devpriv->hwdmaptr[devpriv->next_dma_buf]);
388		if (devpriv->dma_runs_to_end || cmd->stop_src == TRIG_NONE)
389			set_dma_count(devpriv->dma, devpriv->hwdmasize);
390		else
391			set_dma_count(devpriv->dma, devpriv->last_dma_run);
392		release_dma_lock(flags);
393		enable_dma(devpriv->dma);
394	}
395
396	devpriv->dma_runs_to_end--;
397}
398
399static void pcl818_ai_set_chan_range(struct comedi_device *dev,
400				     unsigned int chan,
401				     unsigned int range)
402{
403	outb(chan, dev->iobase + PCL818_MUX_REG);
404	outb(range, dev->iobase + PCL818_RANGE_REG);
405}
406
407static void pcl818_ai_set_chan_scan(struct comedi_device *dev,
408				    unsigned int first_chan,
409				    unsigned int last_chan)
410{
411	outb(PCL818_MUX_SCAN(first_chan, last_chan),
412	     dev->iobase + PCL818_MUX_REG);
413}
414
415static void pcl818_ai_setup_chanlist(struct comedi_device *dev,
416				     unsigned int *chanlist,
417				     unsigned int seglen)
418{
419	struct pcl818_private *devpriv = dev->private;
420	unsigned int first_chan = CR_CHAN(chanlist[0]);
421	unsigned int last_chan;
422	unsigned int range;
423	int i;
424
425	devpriv->act_chanlist_len = seglen;
426	devpriv->act_chanlist_pos = 0;
427
428	/* store range list to card */
429	for (i = 0; i < seglen; i++) {
430		last_chan = CR_CHAN(chanlist[i]);
431		range = CR_RANGE(chanlist[i]);
432
433		devpriv->act_chanlist[i] = last_chan;
434
435		pcl818_ai_set_chan_range(dev, last_chan, range);
436	}
437
438	udelay(1);
439
440	pcl818_ai_set_chan_scan(dev, first_chan, last_chan);
441}
442
443static void pcl818_ai_clear_eoc(struct comedi_device *dev)
444{
445	/* writing any value clears the interrupt request */
446	outb(0, dev->iobase + PCL818_STATUS_REG);
447}
448
449static void pcl818_ai_soft_trig(struct comedi_device *dev)
450{
451	/* writing any value triggers a software conversion */
452	outb(0, dev->iobase + PCL818_AI_LSB_REG);
453}
454
455static unsigned int pcl818_ai_get_fifo_sample(struct comedi_device *dev,
456					      struct comedi_subdevice *s,
457					      unsigned int *chan)
458{
459	unsigned int val;
460
461	val = inb(dev->iobase + PCL818_FI_DATALO);
462	val |= (inb(dev->iobase + PCL818_FI_DATAHI) << 8);
463
464	if (chan)
465		*chan = val & 0xf;
466
467	return (val >> 4) & s->maxdata;
468}
469
470static unsigned int pcl818_ai_get_sample(struct comedi_device *dev,
471					 struct comedi_subdevice *s,
472					 unsigned int *chan)
473{
474	unsigned int val;
475
476	val = inb(dev->iobase + PCL818_AI_MSB_REG) << 8;
477	val |= inb(dev->iobase + PCL818_AI_LSB_REG);
478
479	if (chan)
480		*chan = val & 0xf;
481
482	return (val >> 4) & s->maxdata;
483}
484
485static int pcl818_ai_eoc(struct comedi_device *dev,
486			 struct comedi_subdevice *s,
487			 struct comedi_insn *insn,
488			 unsigned long context)
489{
490	unsigned int status;
491
492	status = inb(dev->iobase + PCL818_STATUS_REG);
493	if (status & PCL818_STATUS_INT)
494		return 0;
495	return -EBUSY;
496}
497
498static bool pcl818_ai_dropout(struct comedi_device *dev,
499			      struct comedi_subdevice *s,
500			      unsigned int chan)
501{
502	struct pcl818_private *devpriv = dev->private;
503	unsigned int expected_chan;
504
505	expected_chan = devpriv->act_chanlist[devpriv->act_chanlist_pos];
506	if (chan != expected_chan) {
507		dev_dbg(dev->class_dev,
508			"A/D mode1/3 %s - channel dropout %d!=%d !\n",
509			(devpriv->dma) ? "DMA" :
510			(devpriv->usefifo) ? "FIFO" : "IRQ",
511			chan, expected_chan);
512		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
513		return true;
514	}
515	return false;
516}
517
518static bool pcl818_ai_next_chan(struct comedi_device *dev,
519				struct comedi_subdevice *s)
520{
521	struct pcl818_private *devpriv = dev->private;
522	struct comedi_cmd *cmd = &s->async->cmd;
523
524	s->async->events |= COMEDI_CB_BLOCK;
525
526	devpriv->act_chanlist_pos++;
527	if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
528		devpriv->act_chanlist_pos = 0;
529
530	s->async->cur_chan++;
531	if (s->async->cur_chan >= cmd->chanlist_len) {
532		s->async->cur_chan = 0;
533		devpriv->ai_act_scan--;
534		s->async->events |= COMEDI_CB_EOS;
535	}
536
537	if (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan == 0) {
538		/* all data sampled */
539		s->async->events |= COMEDI_CB_EOA;
540		return false;
541	}
542
543	return true;
544}
545
546static void pcl818_handle_eoc(struct comedi_device *dev,
547			      struct comedi_subdevice *s)
548{
549	unsigned int chan;
550	unsigned int val;
551
552	if (pcl818_ai_eoc(dev, s, NULL, 0)) {
553		dev_err(dev->class_dev, "A/D mode1/3 IRQ without DRDY!\n");
554		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
555		return;
556	}
557
558	val = pcl818_ai_get_sample(dev, s, &chan);
559
560	if (pcl818_ai_dropout(dev, s, chan))
561		return;
562
563	comedi_buf_put(s, val);
564
565	pcl818_ai_next_chan(dev, s);
566}
567
568static void pcl818_handle_dma(struct comedi_device *dev,
569			      struct comedi_subdevice *s)
570{
571	struct pcl818_private *devpriv = dev->private;
572	unsigned short *ptr;
573	unsigned int chan;
574	unsigned int val;
575	int i, len, bufptr;
576
577	pcl818_ai_setup_next_dma(dev, s);
578
579	ptr = (unsigned short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
580
581	len = devpriv->hwdmasize >> 1;
582	bufptr = 0;
583
584	for (i = 0; i < len; i++) {
585		val = ptr[bufptr++];
586		chan = val & 0xf;
587		val = (val >> 4) & s->maxdata;
588
589		if (pcl818_ai_dropout(dev, s, chan))
590			break;
591
592		comedi_buf_put(s, val);
593
594		if (!pcl818_ai_next_chan(dev, s))
595			break;
596	}
597}
598
599static void pcl818_handle_fifo(struct comedi_device *dev,
600			       struct comedi_subdevice *s)
601{
602	unsigned int status;
603	unsigned int chan;
604	unsigned int val;
605	int i, len;
606
607	status = inb(dev->iobase + PCL818_FI_STATUS);
608
609	if (status & 4) {
610		dev_err(dev->class_dev, "A/D mode1/3 FIFO overflow!\n");
611		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
612		return;
613	}
614
615	if (status & 1) {
616		dev_err(dev->class_dev,
617			"A/D mode1/3 FIFO interrupt without data!\n");
618		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
619		return;
620	}
621
622	if (status & 2)
623		len = 512;
624	else
625		len = 0;
626
627	for (i = 0; i < len; i++) {
628		val = pcl818_ai_get_fifo_sample(dev, s, &chan);
629
630		if (pcl818_ai_dropout(dev, s, chan))
631			break;
632
633		comedi_buf_put(s, val);
634
635		if (!pcl818_ai_next_chan(dev, s))
636			break;
637	}
638}
639
640static irqreturn_t pcl818_interrupt(int irq, void *d)
641{
642	struct comedi_device *dev = d;
643	struct pcl818_private *devpriv = dev->private;
644	struct comedi_subdevice *s = dev->read_subdev;
645
646	if (!dev->attached || !devpriv->ai_cmd_running) {
647		pcl818_ai_clear_eoc(dev);
648		return IRQ_HANDLED;
649	}
650
651	if (devpriv->ai_cmd_canceled) {
652		/*
653		 * The cleanup from ai_cancel() has been delayed
654		 * until now because the card doesn't seem to like
655		 * being reprogrammed while a DMA transfer is in
656		 * progress.
657		 */
658		devpriv->ai_act_scan = 0;
659		s->cancel(dev, s);
660		return IRQ_HANDLED;
661	}
662
663	if (devpriv->dma)
664		pcl818_handle_dma(dev, s);
665	else if (devpriv->usefifo)
666		pcl818_handle_fifo(dev, s);
667	else
668		pcl818_handle_eoc(dev, s);
669
670	pcl818_ai_clear_eoc(dev);
671
672	cfc_handle_events(dev, s);
673	return IRQ_HANDLED;
674}
675
676static int check_channel_list(struct comedi_device *dev,
677			      struct comedi_subdevice *s,
678			      unsigned int *chanlist, unsigned int n_chan)
679{
680	unsigned int chansegment[16];
681	unsigned int i, nowmustbechan, seglen, segpos;
682
683	/* correct channel and range number check itself comedi/range.c */
684	if (n_chan < 1) {
685		dev_err(dev->class_dev, "range/channel list is empty!\n");
686		return 0;
687	}
688
689	if (n_chan > 1) {
690		/*  first channel is every time ok */
691		chansegment[0] = chanlist[0];
692		/*  build part of chanlist */
693		for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
694			/* we detect loop, this must by finish */
695
696			if (chanlist[0] == chanlist[i])
697				break;
698			nowmustbechan =
699			    (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
700			if (nowmustbechan != CR_CHAN(chanlist[i])) {	/*  channel list isn't continuous :-( */
701				dev_dbg(dev->class_dev,
702					"channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
703					i, CR_CHAN(chanlist[i]), nowmustbechan,
704					CR_CHAN(chanlist[0]));
705				return 0;
706			}
707			/*  well, this is next correct channel in list */
708			chansegment[i] = chanlist[i];
709		}
710
711		/*  check whole chanlist */
712		for (i = 0, segpos = 0; i < n_chan; i++) {
713			if (chanlist[i] != chansegment[i % seglen]) {
714				dev_dbg(dev->class_dev,
715					"bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
716					i, CR_CHAN(chansegment[i]),
717					CR_RANGE(chansegment[i]),
718					CR_AREF(chansegment[i]),
719					CR_CHAN(chanlist[i % seglen]),
720					CR_RANGE(chanlist[i % seglen]),
721					CR_AREF(chansegment[i % seglen]));
722				return 0;	/*  chan/gain list is strange */
723			}
724		}
725	} else {
726		seglen = 1;
727	}
728	return seglen;
729}
730
731static int check_single_ended(unsigned int port)
732{
733	if (inb(port + PCL818_STATUS_REG) & PCL818_STATUS_MUX)
734		return 1;
735	return 0;
736}
737
738static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
739		      struct comedi_cmd *cmd)
740{
741	const struct pcl818_board *board = dev->board_ptr;
742	struct pcl818_private *devpriv = dev->private;
743	int err = 0;
744	unsigned int arg;
745
746	/* Step 1 : check if triggers are trivially valid */
747
748	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
749	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
750	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
751	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
752	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
753
754	if (err)
755		return 1;
756
757	/* Step 2a : make sure trigger sources are unique */
758
759	err |= cfc_check_trigger_is_unique(cmd->convert_src);
760	err |= cfc_check_trigger_is_unique(cmd->stop_src);
761
762	/* Step 2b : and mutually compatible */
763
764	if (err)
765		return 2;
766
767	/* Step 3: check if arguments are trivially valid */
768
769	err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
770	err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
771
772	if (cmd->convert_src == TRIG_TIMER)
773		err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
774						 board->ns_min);
775	else	/* TRIG_EXT */
776		err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
777
778	err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
779
780	if (cmd->stop_src == TRIG_COUNT)
781		err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
782	else	/* TRIG_NONE */
783		err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
784
785	if (err)
786		return 3;
787
788	/* step 4: fix up any arguments */
789
790	if (cmd->convert_src == TRIG_TIMER) {
791		arg = cmd->convert_arg;
792		i8253_cascade_ns_to_timer(devpriv->i8253_osc_base,
793					  &devpriv->divisor1,
794					  &devpriv->divisor2,
795					  &arg, cmd->flags);
796		err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
797	}
798
799	if (err)
800		return 4;
801
802	/* step 5: complain about special chanlist considerations */
803
804	if (cmd->chanlist) {
805		if (!check_channel_list(dev, s, cmd->chanlist,
806					cmd->chanlist_len))
807			return 5;	/*  incorrect channels list */
808	}
809
810	return 0;
811}
812
813static int pcl818_ai_cmd(struct comedi_device *dev,
814			 struct comedi_subdevice *s)
815{
816	struct pcl818_private *devpriv = dev->private;
817	struct comedi_cmd *cmd = &s->async->cmd;
818	unsigned int ctrl = 0;
819	unsigned int seglen;
820
821	if (devpriv->ai_cmd_running)
822		return -EBUSY;
823
824	pcl818_start_pacer(dev, false);
825
826	seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len);
827	if (seglen < 1)
828		return -EINVAL;
829	pcl818_ai_setup_chanlist(dev, cmd->chanlist, seglen);
830
831	devpriv->ai_data_len = s->async->prealloc_bufsz;
832	devpriv->ai_act_scan = cmd->stop_arg;
833	devpriv->ai_act_chan = 0;
834	devpriv->ai_cmd_running = 1;
835	devpriv->ai_cmd_canceled = 0;
836	devpriv->act_chanlist_pos = 0;
837	devpriv->dma_runs_to_end = 0;
838
839	if (cmd->convert_src == TRIG_TIMER)
840		ctrl |= PCL818_CTRL_PACER_TRIG;
841	else
842		ctrl |= PCL818_CTRL_EXT_TRIG;
843
844	outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG);
845
846	if (devpriv->dma) {
847		pcl818_ai_setup_dma(dev, s);
848
849		ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq) |
850			PCL818_CTRL_DMAE;
851	} else if (devpriv->usefifo) {
852		/* enable FIFO */
853		outb(1, dev->iobase + PCL818_FI_ENABLE);
854	} else {
855		ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq);
856	}
857	outb(ctrl, dev->iobase + PCL818_CTRL_REG);
858
859	if (cmd->convert_src == TRIG_TIMER)
860		pcl818_start_pacer(dev, true);
861
862	return 0;
863}
864
865static int pcl818_ai_cancel(struct comedi_device *dev,
866			    struct comedi_subdevice *s)
867{
868	struct pcl818_private *devpriv = dev->private;
869	struct comedi_cmd *cmd = &s->async->cmd;
870
871	if (!devpriv->ai_cmd_running)
872		return 0;
873
874	if (devpriv->dma) {
875		if (cmd->stop_src == TRIG_NONE ||
876		    (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan > 0)) {
877			if (!devpriv->ai_cmd_canceled) {
878				/*
879				* Wait for running dma transfer to end,
880				* do cleanup in interrupt.
881				*/
882				devpriv->ai_cmd_canceled = 1;
883				return 0;
884			}
885		}
886		disable_dma(devpriv->dma);
887	}
888
889	outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG);
890	pcl818_start_pacer(dev, false);
891	pcl818_ai_clear_eoc(dev);
892
893	if (devpriv->usefifo) {	/*  FIFO shutdown */
894		outb(0, dev->iobase + PCL818_FI_INTCLR);
895		outb(0, dev->iobase + PCL818_FI_FLUSH);
896		outb(0, dev->iobase + PCL818_FI_ENABLE);
897	}
898	devpriv->ai_cmd_running = 0;
899	devpriv->ai_cmd_canceled = 0;
900
901	return 0;
902}
903
904static int pcl818_ai_insn_read(struct comedi_device *dev,
905			       struct comedi_subdevice *s,
906			       struct comedi_insn *insn,
907			       unsigned int *data)
908{
909	unsigned int chan = CR_CHAN(insn->chanspec);
910	unsigned int range = CR_RANGE(insn->chanspec);
911	int ret = 0;
912	int i;
913
914	outb(PCL818_CTRL_SOFT_TRIG, dev->iobase + PCL818_CTRL_REG);
915
916	pcl818_ai_set_chan_range(dev, chan, range);
917	pcl818_ai_set_chan_scan(dev, chan, chan);
918
919	for (i = 0; i < insn->n; i++) {
920		pcl818_ai_clear_eoc(dev);
921		pcl818_ai_soft_trig(dev);
922
923		ret = comedi_timeout(dev, s, insn, pcl818_ai_eoc, 0);
924		if (ret)
925			break;
926
927		data[i] = pcl818_ai_get_sample(dev, s, NULL);
928	}
929	pcl818_ai_clear_eoc(dev);
930
931	return ret ? ret : insn->n;
932}
933
934static int pcl818_ao_insn_write(struct comedi_device *dev,
935				struct comedi_subdevice *s,
936				struct comedi_insn *insn,
937				unsigned int *data)
938{
939	unsigned int chan = CR_CHAN(insn->chanspec);
940	unsigned int val = s->readback[chan];
941	int i;
942
943	for (i = 0; i < insn->n; i++) {
944		val = data[i];
945		outb((val & 0x000f) << 4,
946		     dev->iobase + PCL818_AO_LSB_REG(chan));
947		outb((val & 0x0ff0) >> 4,
948		     dev->iobase + PCL818_AO_MSB_REG(chan));
949	}
950	s->readback[chan] = val;
951
952	return insn->n;
953}
954
955static int pcl818_di_insn_bits(struct comedi_device *dev,
956			       struct comedi_subdevice *s,
957			       struct comedi_insn *insn,
958			       unsigned int *data)
959{
960	data[1] = inb(dev->iobase + PCL818_DO_DI_LSB_REG) |
961		  (inb(dev->iobase + PCL818_DO_DI_MSB_REG) << 8);
962
963	return insn->n;
964}
965
966static int pcl818_do_insn_bits(struct comedi_device *dev,
967			       struct comedi_subdevice *s,
968			       struct comedi_insn *insn,
969			       unsigned int *data)
970{
971	if (comedi_dio_update_state(s, data)) {
972		outb(s->state & 0xff, dev->iobase + PCL818_DO_DI_LSB_REG);
973		outb((s->state >> 8), dev->iobase + PCL818_DO_DI_MSB_REG);
974	}
975
976	data[1] = s->state;
977
978	return insn->n;
979}
980
981static void pcl818_reset(struct comedi_device *dev)
982{
983	const struct pcl818_board *board = dev->board_ptr;
984	unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE;
985	unsigned int chan;
986
987	/* flush and disable the FIFO */
988	if (board->has_fifo) {
989		outb(0, dev->iobase + PCL818_FI_INTCLR);
990		outb(0, dev->iobase + PCL818_FI_FLUSH);
991		outb(0, dev->iobase + PCL818_FI_ENABLE);
992	}
993
994	/* disable analog input trigger */
995	outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG);
996	pcl818_ai_clear_eoc(dev);
997
998	pcl818_ai_set_chan_range(dev, 0, 0);
999
1000	/* stop pacer */
1001	outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG);
1002	i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY);
1003	i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY);
1004	i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY);
1005
1006	/* set analog output channels to 0V */
1007	for (chan = 0; chan < board->n_aochan; chan++) {
1008		outb(0, dev->iobase + PCL818_AO_LSB_REG(chan));
1009		outb(0, dev->iobase + PCL818_AO_MSB_REG(chan));
1010	}
1011
1012	/* set all digital outputs low */
1013	outb(0, dev->iobase + PCL818_DO_DI_MSB_REG);
1014	outb(0, dev->iobase + PCL818_DO_DI_LSB_REG);
1015}
1016
1017static void pcl818_set_ai_range_table(struct comedi_device *dev,
1018				      struct comedi_subdevice *s,
1019				      struct comedi_devconfig *it)
1020{
1021	const struct pcl818_board *board = dev->board_ptr;
1022
1023	/* default to the range table from the boardinfo */
1024	s->range_table = board->ai_range_type;
1025
1026	/* now check the user config option based on the boardtype */
1027	if (board->is_818) {
1028		if (it->options[4] == 1 || it->options[4] == 10) {
1029			/* secondary range list jumper selectable */
1030			s->range_table = &range_pcl818l_h_ai;
1031		}
1032	} else {
1033		switch (it->options[4]) {
1034		case 0:
1035			s->range_table = &range_bipolar10;
1036			break;
1037		case 1:
1038			s->range_table = &range_bipolar5;
1039			break;
1040		case 2:
1041			s->range_table = &range_bipolar2_5;
1042			break;
1043		case 3:
1044			s->range_table = &range718_bipolar1;
1045			break;
1046		case 4:
1047			s->range_table = &range718_bipolar0_5;
1048			break;
1049		case 6:
1050			s->range_table = &range_unipolar10;
1051			break;
1052		case 7:
1053			s->range_table = &range_unipolar5;
1054			break;
1055		case 8:
1056			s->range_table = &range718_unipolar2;
1057			break;
1058		case 9:
1059			s->range_table = &range718_unipolar1;
1060			break;
1061		default:
1062			s->range_table = &range_unknown;
1063			break;
1064		}
1065	}
1066}
1067
1068static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1069{
1070	const struct pcl818_board *board = dev->board_ptr;
1071	struct pcl818_private *devpriv;
1072	struct comedi_subdevice *s;
1073	int ret;
1074	int i;
1075
1076	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1077	if (!devpriv)
1078		return -ENOMEM;
1079
1080	ret = comedi_request_region(dev, it->options[0],
1081				    board->has_fifo ? 0x20 : 0x10);
1082	if (ret)
1083		return ret;
1084
1085	/* we can use IRQ 2-7 for async command support */
1086	if (it->options[1] >= 2 && it->options[1] <= 7) {
1087		ret = request_irq(it->options[1], pcl818_interrupt, 0,
1088				  dev->board_name, dev);
1089		if (ret == 0)
1090			dev->irq = it->options[1];
1091	}
1092
1093	/* should we use the FIFO? */
1094	if (dev->irq && board->has_fifo && it->options[2] == -1)
1095		devpriv->usefifo = 1;
1096
1097	/* we need an IRQ to do DMA on channel 3 or 1 */
1098	if (dev->irq && board->has_dma &&
1099	    (it->options[2] == 3 || it->options[2] == 1)) {
1100		ret = request_dma(it->options[2], dev->board_name);
1101		if (ret) {
1102			dev_err(dev->class_dev,
1103				"unable to request DMA channel %d\n",
1104				it->options[2]);
1105			return -EBUSY;
1106		}
1107		devpriv->dma = it->options[2];
1108
1109		devpriv->dmapages = 2;	/* we need 16KB */
1110		devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
1111
1112		for (i = 0; i < 2; i++) {
1113			unsigned long dmabuf;
1114
1115			dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
1116			if (!dmabuf)
1117				return -ENOMEM;
1118
1119			devpriv->dmabuf[i] = dmabuf;
1120			devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
1121		}
1122	}
1123
1124	ret = comedi_alloc_subdevices(dev, 4);
1125	if (ret)
1126		return ret;
1127
1128	s = &dev->subdevices[0];
1129	s->type		= COMEDI_SUBD_AI;
1130	s->subdev_flags	= SDF_READABLE;
1131	if (check_single_ended(dev->iobase)) {
1132		s->n_chan	= 16;
1133		s->subdev_flags	|= SDF_COMMON | SDF_GROUND;
1134	} else {
1135		s->n_chan	= 8;
1136		s->subdev_flags	|= SDF_DIFF;
1137	}
1138	s->maxdata	= 0x0fff;
1139
1140	pcl818_set_ai_range_table(dev, s, it);
1141
1142	s->insn_read	= pcl818_ai_insn_read;
1143	if (dev->irq) {
1144		dev->read_subdev = s;
1145		s->subdev_flags	|= SDF_CMD_READ;
1146		s->len_chanlist	= s->n_chan;
1147		s->do_cmdtest	= ai_cmdtest;
1148		s->do_cmd	= pcl818_ai_cmd;
1149		s->cancel	= pcl818_ai_cancel;
1150	}
1151
1152	/* Analog Output subdevice */
1153	s = &dev->subdevices[1];
1154	if (board->n_aochan) {
1155		s->type		= COMEDI_SUBD_AO;
1156		s->subdev_flags	= SDF_WRITABLE | SDF_GROUND;
1157		s->n_chan	= board->n_aochan;
1158		s->maxdata	= 0x0fff;
1159		s->range_table	= &range_unipolar5;
1160		if (board->is_818) {
1161			if ((it->options[4] == 1) || (it->options[4] == 10))
1162				s->range_table = &range_unipolar10;
1163			if (it->options[4] == 2)
1164				s->range_table = &range_unknown;
1165		} else {
1166			if ((it->options[5] == 1) || (it->options[5] == 10))
1167				s->range_table = &range_unipolar10;
1168			if (it->options[5] == 2)
1169				s->range_table = &range_unknown;
1170		}
1171		s->insn_write	= pcl818_ao_insn_write;
1172		s->insn_read	= comedi_readback_insn_read;
1173
1174		ret = comedi_alloc_subdev_readback(s);
1175		if (ret)
1176			return ret;
1177	} else {
1178		s->type		= COMEDI_SUBD_UNUSED;
1179	}
1180
1181	/* Digital Input subdevice */
1182	s = &dev->subdevices[2];
1183	s->type		= COMEDI_SUBD_DI;
1184	s->subdev_flags	= SDF_READABLE;
1185	s->n_chan	= 16;
1186	s->maxdata	= 1;
1187	s->range_table	= &range_digital;
1188	s->insn_bits	= pcl818_di_insn_bits;
1189
1190	/* Digital Output subdevice */
1191	s = &dev->subdevices[3];
1192	s->type		= COMEDI_SUBD_DO;
1193	s->subdev_flags	= SDF_WRITABLE;
1194	s->n_chan	= 16;
1195	s->maxdata	= 1;
1196	s->range_table	= &range_digital;
1197	s->insn_bits	= pcl818_do_insn_bits;
1198
1199	/* select 1/10MHz oscilator */
1200	if ((it->options[3] == 0) || (it->options[3] == 10))
1201		devpriv->i8253_osc_base = I8254_OSC_BASE_10MHZ;
1202	else
1203		devpriv->i8253_osc_base = I8254_OSC_BASE_1MHZ;
1204
1205	/* max sampling speed */
1206	devpriv->ns_min = board->ns_min;
1207
1208	if (!board->is_818) {
1209		if ((it->options[6] == 1) || (it->options[6] == 100))
1210			devpriv->ns_min = 10000;	/* extended PCL718 to 100kHz DAC */
1211	}
1212
1213	pcl818_reset(dev);
1214
1215	return 0;
1216}
1217
1218static void pcl818_detach(struct comedi_device *dev)
1219{
1220	struct pcl818_private *devpriv = dev->private;
1221
1222	if (devpriv) {
1223		pcl818_ai_cancel(dev, dev->read_subdev);
1224		pcl818_reset(dev);
1225		if (devpriv->dma)
1226			free_dma(devpriv->dma);
1227		if (devpriv->dmabuf[0])
1228			free_pages(devpriv->dmabuf[0], devpriv->dmapages);
1229		if (devpriv->dmabuf[1])
1230			free_pages(devpriv->dmabuf[1], devpriv->dmapages);
1231	}
1232	comedi_legacy_detach(dev);
1233}
1234
1235static struct comedi_driver pcl818_driver = {
1236	.driver_name	= "pcl818",
1237	.module		= THIS_MODULE,
1238	.attach		= pcl818_attach,
1239	.detach		= pcl818_detach,
1240	.board_name	= &boardtypes[0].name,
1241	.num_names	= ARRAY_SIZE(boardtypes),
1242	.offset		= sizeof(struct pcl818_board),
1243};
1244module_comedi_driver(pcl818_driver);
1245
1246MODULE_AUTHOR("Comedi http://www.comedi.org");
1247MODULE_DESCRIPTION("Comedi low-level driver");
1248MODULE_LICENSE("GPL");
1249