pcl812.c revision 51091b5420c564093d721d2dad99a55bbb22d0d0
1/*
2 * comedi/drivers/pcl812.c
3 *
4 * Author: Michal Dobes <dobes@tesnet.cz>
5 *
6 * hardware driver for Advantech cards
7 *  card:   PCL-812, PCL-812PG, PCL-813, PCL-813B
8 *  driver: pcl812,  pcl812pg,  pcl813,  pcl813b
9 * and for ADlink cards
10 *  card:   ACL-8112DG, ACL-8112HG, ACL-8112PG, ACL-8113, ACL-8216
11 *  driver: acl8112dg,  acl8112hg,  acl8112pg,  acl8113,  acl8216
12 * and for ICP DAS cards
13 *  card:   ISO-813, A-821PGH, A-821PGL, A-821PGL-NDA, A-822PGH, A-822PGL,
14 *  driver: iso813,  a821pgh,  a-821pgl, a-821pglnda,  a822pgh,  a822pgl,
15 *  card:   A-823PGH, A-823PGL, A-826PG
16 * driver:  a823pgh,  a823pgl,  a826pg
17 */
18/*
19Driver: pcl812
20Description: Advantech PCL-812/PG, PCL-813/B,
21             ADLink ACL-8112DG/HG/PG, ACL-8113, ACL-8216,
22             ICP DAS A-821PGH/PGL/PGL-NDA, A-822PGH/PGL, A-823PGH/PGL, A-826PG,
23             ICP DAS ISO-813
24Author: Michal Dobes <dobes@tesnet.cz>
25Devices: [Advantech] PCL-812 (pcl812), PCL-812PG (pcl812pg),
26  PCL-813 (pcl813), PCL-813B (pcl813b), [ADLink] ACL-8112DG (acl8112dg),
27  ACL-8112HG (acl8112hg), ACL-8113 (acl-8113), ACL-8216 (acl8216),
28  [ICP] ISO-813 (iso813), A-821PGH (a821pgh), A-821PGL (a821pgl),
29  A-821PGL-NDA (a821pclnda), A-822PGH (a822pgh), A-822PGL (a822pgl),
30  A-823PGH (a823pgh), A-823PGL (a823pgl), A-826PG (a826pg)
31Updated: Mon, 06 Aug 2007 12:03:15 +0100
32Status: works (I hope. My board fire up under my hands
33               and I cann't test all features.)
34
35This driver supports insn and cmd interfaces. Some boards support only insn
36becouse their hardware don't allow more (PCL-813/B, ACL-8113, ISO-813).
37Data transfer over DMA is supported only when you measure only one
38channel, this is too hardware limitation of these boards.
39
40Options for PCL-812:
41  [0] - IO Base
42  [1] - IRQ  (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
43  [2] - DMA  (0=disable, 1, 3)
44  [3] - 0=trigger source is internal 8253 with 2MHz clock
45        1=trigger source is external
46  [4] - 0=A/D input range is +/-10V
47        1=A/D input range is +/-5V
48        2=A/D input range is +/-2.5V
49        3=A/D input range is +/-1.25V
50        4=A/D input range is +/-0.625V
51        5=A/D input range is +/-0.3125V
52  [5] - 0=D/A outputs 0-5V  (internal reference -5V)
53        1=D/A outputs 0-10V (internal reference -10V)
54        2=D/A outputs unknow (external reference)
55
56Options for PCL-812PG, ACL-8112PG:
57  [0] - IO Base
58  [1] - IRQ  (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
59  [2] - DMA  (0=disable, 1, 3)
60  [3] - 0=trigger source is internal 8253 with 2MHz clock
61        1=trigger source is external
62  [4] - 0=A/D have max +/-5V input
63        1=A/D have max +/-10V input
64  [5] - 0=D/A outputs 0-5V  (internal reference -5V)
65        1=D/A outputs 0-10V (internal reference -10V)
66        2=D/A outputs unknow (external reference)
67
68Options for ACL-8112DG/HG, A-822PGL/PGH, A-823PGL/PGH, ACL-8216, A-826PG:
69  [0] - IO Base
70  [1] - IRQ  (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
71  [2] - DMA  (0=disable, 1, 3)
72  [3] - 0=trigger source is internal 8253 with 2MHz clock
73        1=trigger source is external
74  [4] - 0=A/D channels are S.E.
75        1=A/D channels are DIFF
76  [5] - 0=D/A outputs 0-5V  (internal reference -5V)
77        1=D/A outputs 0-10V (internal reference -10V)
78        2=D/A outputs unknow (external reference)
79
80Options for A-821PGL/PGH:
81  [0] - IO Base
82  [1] - IRQ  (0=disable, 2, 3, 4, 5, 6, 7)
83  [2] - 0=A/D channels are S.E.
84        1=A/D channels are DIFF
85  [3] - 0=D/A output 0-5V  (internal reference -5V)
86        1=D/A output 0-10V (internal reference -10V)
87
88Options for A-821PGL-NDA:
89  [0] - IO Base
90  [1] - IRQ  (0=disable, 2, 3, 4, 5, 6, 7)
91  [2] - 0=A/D channels are S.E.
92        1=A/D channels are DIFF
93
94Options for PCL-813:
95  [0] - IO Base
96
97Options for PCL-813B:
98  [0] - IO Base
99  [1] - 0= bipolar inputs
100        1= unipolar inputs
101
102Options for ACL-8113, ISO-813:
103  [0] - IO Base
104  [1] - 0= 10V bipolar inputs
105        1= 10V unipolar inputs
106        2= 20V bipolar inputs
107        3= 20V unipolar inputs
108*/
109
110#include "../comedidev.h"
111
112#include <linux/delay.h>
113#include <linux/ioport.h>
114#include <asm/dma.h>
115
116#include "8253.h"
117
118#undef PCL812_EXTDEBUG		/* if this is defined then a lot of messages is printed */
119
120// hardware types of the cards
121#define boardPCL812PG 		 0	/* and ACL-8112PG */
122#define boardPCL813B 		 1
123#define boardPCL812		 2
124#define boardPCL813 		 3
125#define boardISO813 		 5
126#define boardACL8113 		 6
127#define boardACL8112 		 7	/* ACL-8112DG/HG, A-822PGL/PGH, A-823PGL/PGH */
128#define boardACL8216		 8	/* and ICP DAS A-826PG */
129#define boardA821		 9	/* PGH, PGL, PGL/NDA versions */
130
131#define PCLx1x_IORANGE 		16
132
133#define PCL812_CTR0		 0
134#define PCL812_CTR1		 1
135#define PCL812_CTR2		 2
136#define PCL812_CTRCTL		 3
137#define PCL812_AD_LO		 4
138#define PCL812_DA1_LO		 4
139#define PCL812_AD_HI		 5
140#define PCL812_DA1_HI		 5
141#define PCL812_DA2_LO		 6
142#define PCL812_DI_LO		 6
143#define PCL812_DA2_HI		 7
144#define PCL812_DI_HI		 7
145#define PCL812_CLRINT		 8
146#define PCL812_GAIN		 9
147#define PCL812_MUX		10
148#define PCL812_MODE		11
149#define PCL812_CNTENABLE 	10
150#define PCL812_SOFTTRIG 	12
151#define PCL812_DO_LO		13
152#define PCL812_DO_HI 		14
153
154#define PCL812_DRDY 		0x10	/* =0 data ready */
155
156#define ACL8216_STATUS 		 8	/* 5. bit signalize data ready */
157
158#define ACL8216_DRDY 		0x20	/* =0 data ready */
159
160#define MAX_CHANLIST_LEN	256	/* length of scan list */
161
162static const struct comedi_lrange range_pcl812pg_ai = { 5, {
163			BIP_RANGE(5),
164			BIP_RANGE(2.5),
165			BIP_RANGE(1.25),
166			BIP_RANGE(0.625),
167			BIP_RANGE(0.3125),
168	}
169};
170static const struct comedi_lrange range_pcl812pg2_ai = { 5, {
171			BIP_RANGE(10),
172			BIP_RANGE(5),
173			BIP_RANGE(2.5),
174			BIP_RANGE(1.25),
175			BIP_RANGE(0.625),
176	}
177};
178static const struct comedi_lrange range812_bipolar1_25 = { 1, {
179			BIP_RANGE(1.25),
180	}
181};
182static const struct comedi_lrange range812_bipolar0_625 = { 1, {
183			BIP_RANGE(0.625),
184	}
185};
186static const struct comedi_lrange range812_bipolar0_3125 = { 1, {
187			BIP_RANGE(0.3125),
188	}
189};
190static const struct comedi_lrange range_pcl813b_ai = { 4, {
191			BIP_RANGE(5),
192			BIP_RANGE(2.5),
193			BIP_RANGE(1.25),
194			BIP_RANGE(0.625),
195	}
196};
197static const struct comedi_lrange range_pcl813b2_ai = { 4, {
198			UNI_RANGE(10),
199			UNI_RANGE(5),
200			UNI_RANGE(2.5),
201			UNI_RANGE(1.25),
202	}
203};
204static const struct comedi_lrange range_iso813_1_ai = { 5, {
205			BIP_RANGE(5),
206			BIP_RANGE(2.5),
207			BIP_RANGE(1.25),
208			BIP_RANGE(0.625),
209			BIP_RANGE(0.3125),
210	}
211};
212static const struct comedi_lrange range_iso813_1_2_ai = { 5, {
213			UNI_RANGE(10),
214			UNI_RANGE(5),
215			UNI_RANGE(2.5),
216			UNI_RANGE(1.25),
217			UNI_RANGE(0.625),
218	}
219};
220static const struct comedi_lrange range_iso813_2_ai = { 4, {
221			BIP_RANGE(5),
222			BIP_RANGE(2.5),
223			BIP_RANGE(1.25),
224			BIP_RANGE(0.625),
225	}
226};
227static const struct comedi_lrange range_iso813_2_2_ai = { 4, {
228			UNI_RANGE(10),
229			UNI_RANGE(5),
230			UNI_RANGE(2.5),
231			UNI_RANGE(1.25),
232	}
233};
234static const struct comedi_lrange range_acl8113_1_ai = { 4, {
235			BIP_RANGE(5),
236			BIP_RANGE(2.5),
237			BIP_RANGE(1.25),
238			BIP_RANGE(0.625),
239	}
240};
241static const struct comedi_lrange range_acl8113_1_2_ai = { 4, {
242			UNI_RANGE(10),
243			UNI_RANGE(5),
244			UNI_RANGE(2.5),
245			UNI_RANGE(1.25),
246	}
247};
248static const struct comedi_lrange range_acl8113_2_ai = { 3, {
249			BIP_RANGE(5),
250			BIP_RANGE(2.5),
251			BIP_RANGE(1.25),
252	}
253};
254static const struct comedi_lrange range_acl8113_2_2_ai = { 3, {
255			UNI_RANGE(10),
256			UNI_RANGE(5),
257			UNI_RANGE(2.5),
258	}
259};
260static const struct comedi_lrange range_acl8112dg_ai = { 9, {
261			BIP_RANGE(5),
262			BIP_RANGE(2.5),
263			BIP_RANGE(1.25),
264			BIP_RANGE(0.625),
265			UNI_RANGE(10),
266			UNI_RANGE(5),
267			UNI_RANGE(2.5),
268			UNI_RANGE(1.25),
269			BIP_RANGE(10),
270	}
271};
272static const struct comedi_lrange range_acl8112hg_ai = { 12, {
273			BIP_RANGE(5),
274			BIP_RANGE(0.5),
275			BIP_RANGE(0.05),
276			BIP_RANGE(0.005),
277			UNI_RANGE(10),
278			UNI_RANGE(1),
279			UNI_RANGE(0.1),
280			UNI_RANGE(0.01),
281			BIP_RANGE(10),
282			BIP_RANGE(1),
283			BIP_RANGE(0.1),
284			BIP_RANGE(0.01),
285	}
286};
287static const struct comedi_lrange range_a821pgh_ai = { 4, {
288			BIP_RANGE(5),
289			BIP_RANGE(0.5),
290			BIP_RANGE(0.05),
291			BIP_RANGE(0.005),
292	}
293};
294
295static int pcl812_attach(struct comedi_device * dev, struct comedi_devconfig * it);
296static int pcl812_detach(struct comedi_device * dev);
297
298typedef struct {
299	const char *name;	// board name
300	int board_type;		// type of this board
301	int n_aichan;		// num of AI chans in S.E.
302	int n_aichan_diff;	// DIFF num of chans
303	int n_aochan;		// num of DA chans
304	int n_dichan;		// DI and DO chans
305	int n_dochan;
306	int ai_maxdata;		// AI resolution
307	unsigned int ai_ns_min;	// max sample speed of card v ns
308	unsigned int i8254_osc_base;	// clock base
309	const struct comedi_lrange *rangelist_ai;	// rangelist for A/D
310	const struct comedi_lrange *rangelist_ao;	// rangelist for D/A
311	unsigned int IRQbits;	// allowed IRQ
312	unsigned char DMAbits;	// allowed DMA chans
313	unsigned char io_range;	// iorange for this board
314	unsigned char haveMPC508;	// 1=board use MPC508A multiplexor
315} boardtype;
316
317static const boardtype boardtypes[] = {
318	{"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff,
319			33000, 500, &range_bipolar10, &range_unipolar5,
320		0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
321	{"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
322			33000, 500, &range_pcl812pg_ai, &range_unipolar5,
323		0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
324	{"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
325			10000, 500, &range_pcl812pg_ai, &range_unipolar5,
326		0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
327	{"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
328			10000, 500, &range_acl8112dg_ai, &range_unipolar5,
329		0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
330	{"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
331			10000, 500, &range_acl8112hg_ai, &range_unipolar5,
332		0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
333	{"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff,
334			10000, 500, &range_pcl813b_ai, &range_unipolar5,
335		0x000c, 0x00, PCLx1x_IORANGE, 0},
336	{"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff,
337			10000, 500, &range_pcl813b_ai, NULL,
338		0x000c, 0x00, PCLx1x_IORANGE, 0},
339	{"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff,
340			10000, 500, &range_a821pgh_ai, &range_unipolar5,
341		0x000c, 0x00, PCLx1x_IORANGE, 0},
342	{"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
343			10000, 500, &range_acl8112dg_ai, &range_unipolar5,
344		0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
345	{"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
346			10000, 500, &range_acl8112hg_ai, &range_unipolar5,
347		0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
348	{"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
349			8000, 500, &range_acl8112dg_ai, &range_unipolar5,
350		0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
351	{"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
352			8000, 500, &range_acl8112hg_ai, &range_unipolar5,
353		0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
354	{"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff,
355			0, 0, &range_pcl813b_ai, NULL,
356		0x0000, 0x00, PCLx1x_IORANGE, 0},
357	{"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff,
358			0, 0, &range_pcl813b_ai, NULL,
359		0x0000, 0x00, PCLx1x_IORANGE, 0},
360	{"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff,
361			0, 0, &range_acl8113_1_ai, NULL,
362		0x0000, 0x00, PCLx1x_IORANGE, 0},
363	{"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff,
364			0, 0, &range_iso813_1_ai, NULL,
365		0x0000, 0x00, PCLx1x_IORANGE, 0},
366	{"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
367			10000, 500, &range_pcl813b2_ai, &range_unipolar5,
368		0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
369	{"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
370			10000, 500, &range_pcl813b2_ai, &range_unipolar5,
371		0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
372};
373
374#define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype))
375#define this_board ((const boardtype *)dev->board_ptr)
376
377static struct comedi_driver driver_pcl812 = {
378      driver_name:"pcl812",
379      module:THIS_MODULE,
380      attach:pcl812_attach,
381      detach:pcl812_detach,
382      board_name:&boardtypes[0].name,
383      num_names:n_boardtypes,
384      offset:sizeof(boardtype),
385};
386
387COMEDI_INITCLEANUP(driver_pcl812);
388
389struct pcl812_private {
390
391	unsigned char valid;	// =1 device is OK
392	unsigned char dma;	// >0 use dma ( usedDMA channel)
393	unsigned char use_diff;	// =1 diff inputs
394	unsigned char use_MPC;	// 1=board uses MPC508A multiplexor
395	unsigned char use_ext_trg;	// 1=board uses external trigger
396	unsigned char range_correction;	// =1 we must add 1 to range number
397	unsigned char old_chan_reg;	// lastly used chan/gain pair
398	unsigned char old_gain_reg;
399	unsigned char mode_reg_int;	// there is stored INT number for some card
400	unsigned char ai_neverending;	// =1 we do unlimited AI
401	unsigned char ai_eos;	// 1=EOS wake up
402	unsigned char ai_dma;	// =1 we use DMA
403	unsigned int ai_poll_ptr;	// how many sampes transfer poll
404	unsigned int ai_scans;	// len of scanlist
405	unsigned int ai_act_scan;	// how many scans we finished
406	unsigned int ai_chanlist[MAX_CHANLIST_LEN];	// our copy of channel/range list
407	unsigned int ai_n_chan;	// how many channels is measured
408	unsigned int ai_flags;	// flaglist
409	unsigned int ai_data_len;	// len of data buffer
410	short *ai_data;	// data buffer
411	unsigned int ai_is16b;	// =1 we have 16 bit card
412	unsigned long dmabuf[2];	// PTR to DMA buf
413	unsigned int dmapages[2];	// how many pages we have allocated
414	unsigned int hwdmaptr[2];	// HW PTR to DMA buf
415	unsigned int hwdmasize[2];	// DMA buf size in bytes
416	unsigned int dmabytestomove[2];	// how many bytes DMA transfer
417	int next_dma_buf;	// which buffer is next to use
418	unsigned int dma_runs_to_end;	// how many times we must switch DMA buffers
419	unsigned int last_dma_run;	// how many bytes to transfer on last DMA buffer
420	unsigned int max_812_ai_mode0_rangewait;	// setling time for gain
421	unsigned int ao_readback[2];	// data for AO readback
422};
423
424
425#define devpriv ((struct pcl812_private *)dev->private)
426
427/*
428==============================================================================
429*/
430static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1,
431	unsigned int divisor2);
432static void setup_range_channel(struct comedi_device * dev, struct comedi_subdevice * s,
433	unsigned int rangechan, char wait);
434static int pcl812_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s);
435/*
436==============================================================================
437*/
438static int pcl812_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
439	struct comedi_insn * insn, unsigned int * data)
440{
441	int n;
442	int timeout, hi;
443
444	outb(devpriv->mode_reg_int | 1, dev->iobase + PCL812_MODE);	/* select software trigger */
445	setup_range_channel(dev, s, insn->chanspec, 1);	// select channel and renge
446	for (n = 0; n < insn->n; n++) {
447		outb(255, dev->iobase + PCL812_SOFTTRIG);	/* start conversion */
448		comedi_udelay(5);
449		timeout = 50;	/* wait max 50us, it must finish under 33us */
450		while (timeout--) {
451			hi = inb(dev->iobase + PCL812_AD_HI);
452			if (!(hi & PCL812_DRDY))
453				goto conv_finish;
454			comedi_udelay(1);
455		}
456		rt_printk
457			("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n",
458			dev->minor, dev->board_name, dev->iobase);
459		outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
460		return -ETIME;
461
462	      conv_finish:
463		data[n] = ((hi & 0xf) << 8) | inb(dev->iobase + PCL812_AD_LO);
464	}
465	outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
466	return n;
467}
468
469/*
470==============================================================================
471*/
472static int acl8216_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
473	struct comedi_insn * insn, unsigned int * data)
474{
475	int n;
476	int timeout;
477
478	outb(1, dev->iobase + PCL812_MODE);	/* select software trigger */
479	setup_range_channel(dev, s, insn->chanspec, 1);	// select channel and renge
480	for (n = 0; n < insn->n; n++) {
481		outb(255, dev->iobase + PCL812_SOFTTRIG);	/* start conversion */
482		comedi_udelay(5);
483		timeout = 50;	/* wait max 50us, it must finish under 33us */
484		while (timeout--) {
485			if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY))
486				goto conv_finish;
487			comedi_udelay(1);
488		}
489		rt_printk
490			("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n",
491			dev->minor, dev->board_name, dev->iobase);
492		outb(0, dev->iobase + PCL812_MODE);
493		return -ETIME;
494
495	      conv_finish:
496		data[n] =
497			(inb(dev->iobase +
498				PCL812_AD_HI) << 8) | inb(dev->iobase +
499			PCL812_AD_LO);
500	}
501	outb(0, dev->iobase + PCL812_MODE);
502	return n;
503}
504
505/*
506==============================================================================
507*/
508static int pcl812_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s,
509	struct comedi_insn * insn, unsigned int * data)
510{
511	int chan = CR_CHAN(insn->chanspec);
512	int i;
513
514	for (i = 0; i < insn->n; i++) {
515		outb((data[i] & 0xff),
516			dev->iobase + (chan ? PCL812_DA2_LO : PCL812_DA1_LO));
517		outb((data[i] >> 8) & 0x0f,
518			dev->iobase + (chan ? PCL812_DA2_HI : PCL812_DA1_HI));
519		devpriv->ao_readback[chan] = data[i];
520	}
521
522	return i;
523}
524
525/*
526==============================================================================
527*/
528static int pcl812_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
529	struct comedi_insn * insn, unsigned int * data)
530{
531	int chan = CR_CHAN(insn->chanspec);
532	int i;
533
534	for (i = 0; i < insn->n; i++) {
535		data[i] = devpriv->ao_readback[chan];
536	}
537
538	return i;
539}
540
541/*
542==============================================================================
543*/
544static int pcl812_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
545	struct comedi_insn * insn, unsigned int * data)
546{
547	if (insn->n != 2)
548		return -EINVAL;
549
550	data[1] = inb(dev->iobase + PCL812_DI_LO);
551	data[1] |= inb(dev->iobase + PCL812_DI_HI) << 8;
552
553	return 2;
554}
555
556/*
557==============================================================================
558*/
559static int pcl812_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
560	struct comedi_insn * insn, unsigned int * data)
561{
562	if (insn->n != 2)
563		return -EINVAL;
564
565	if (data[0]) {
566		s->state &= ~data[0];
567		s->state |= data[0] & data[1];
568		outb(s->state & 0xff, dev->iobase + PCL812_DO_LO);
569		outb((s->state >> 8), dev->iobase + PCL812_DO_HI);
570	}
571	data[1] = s->state;
572
573	return 2;
574}
575
576#ifdef PCL812_EXTDEBUG
577/*
578==============================================================================
579*/
580static void pcl812_cmdtest_out(int e, struct comedi_cmd * cmd)
581{
582	rt_printk("pcl812 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
583		cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
584	rt_printk("pcl812 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
585		cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
586	rt_printk("pcl812 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src,
587		cmd->scan_end_src);
588	rt_printk("pcl812 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n", e,
589		cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
590}
591#endif
592
593/*
594==============================================================================
595*/
596static int pcl812_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s,
597	struct comedi_cmd * cmd)
598{
599	int err = 0;
600	int tmp, divisor1, divisor2;
601
602#ifdef PCL812_EXTDEBUG
603	rt_printk("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...)\n");
604	pcl812_cmdtest_out(-1, cmd);
605#endif
606	/* step 1: make sure trigger sources are trivially valid */
607
608	tmp = cmd->start_src;
609	cmd->start_src &= TRIG_NOW;
610	if (!cmd->start_src || tmp != cmd->start_src)
611		err++;
612
613	tmp = cmd->scan_begin_src;
614	cmd->scan_begin_src &= TRIG_FOLLOW;
615	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
616		err++;
617
618	tmp = cmd->convert_src;
619	if (devpriv->use_ext_trg) {
620		cmd->convert_src &= TRIG_EXT;
621	} else {
622		cmd->convert_src &= TRIG_TIMER;
623	}
624	if (!cmd->convert_src || tmp != cmd->convert_src)
625		err++;
626
627	tmp = cmd->scan_end_src;
628	cmd->scan_end_src &= TRIG_COUNT;
629	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
630		err++;
631
632	tmp = cmd->stop_src;
633	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
634	if (!cmd->stop_src || tmp != cmd->stop_src)
635		err++;
636
637	if (err) {
638#ifdef PCL812_EXTDEBUG
639		pcl812_cmdtest_out(1, cmd);
640		rt_printk
641			("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=1\n",
642			err);
643#endif
644		return 1;
645	}
646
647	/* step 2: make sure trigger sources are unique and mutually compatible */
648
649	if (cmd->start_src != TRIG_NOW) {
650		cmd->start_src = TRIG_NOW;
651		err++;
652	}
653
654	if (cmd->scan_begin_src != TRIG_FOLLOW) {
655		cmd->scan_begin_src = TRIG_FOLLOW;
656		err++;
657	}
658
659	if (devpriv->use_ext_trg) {
660		if (cmd->convert_src != TRIG_EXT) {
661			cmd->convert_src = TRIG_EXT;
662			err++;
663		}
664	} else {
665		if (cmd->convert_src != TRIG_TIMER) {
666			cmd->convert_src = TRIG_TIMER;
667			err++;
668		}
669	}
670
671	if (cmd->scan_end_src != TRIG_COUNT) {
672		cmd->scan_end_src = TRIG_COUNT;
673		err++;
674	}
675
676	if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
677		err++;
678
679	if (err) {
680#ifdef PCL812_EXTDEBUG
681		pcl812_cmdtest_out(2, cmd);
682		rt_printk
683			("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=2\n",
684			err);
685#endif
686		return 2;
687	}
688
689	/* step 3: make sure arguments are trivially compatible */
690
691	if (cmd->start_arg != 0) {
692		cmd->start_arg = 0;
693		err++;
694	}
695
696	if (cmd->scan_begin_arg != 0) {
697		cmd->scan_begin_arg = 0;
698		err++;
699	}
700
701	if (cmd->convert_src == TRIG_TIMER) {
702		if (cmd->convert_arg < this_board->ai_ns_min) {
703			cmd->convert_arg = this_board->ai_ns_min;
704			err++;
705		}
706	} else {		/* TRIG_EXT */
707		if (cmd->convert_arg != 0) {
708			cmd->convert_arg = 0;
709			err++;
710		}
711	}
712
713	if (!cmd->chanlist_len) {
714		cmd->chanlist_len = 1;
715		err++;
716	}
717	if (cmd->chanlist_len > MAX_CHANLIST_LEN) {
718		cmd->chanlist_len = this_board->n_aichan;
719		err++;
720	}
721	if (cmd->scan_end_arg != cmd->chanlist_len) {
722		cmd->scan_end_arg = cmd->chanlist_len;
723		err++;
724	}
725	if (cmd->stop_src == TRIG_COUNT) {
726		if (!cmd->stop_arg) {
727			cmd->stop_arg = 1;
728			err++;
729		}
730	} else {		/* TRIG_NONE */
731		if (cmd->stop_arg != 0) {
732			cmd->stop_arg = 0;
733			err++;
734		}
735	}
736
737	if (err) {
738#ifdef PCL812_EXTDEBUG
739		pcl812_cmdtest_out(3, cmd);
740		rt_printk
741			("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=3\n",
742			err);
743#endif
744		return 3;
745	}
746
747	/* step 4: fix up any arguments */
748
749	if (cmd->convert_src == TRIG_TIMER) {
750		tmp = cmd->convert_arg;
751		i8253_cascade_ns_to_timer(this_board->i8254_osc_base, &divisor1,
752			&divisor2, &cmd->convert_arg,
753			cmd->flags & TRIG_ROUND_MASK);
754		if (cmd->convert_arg < this_board->ai_ns_min)
755			cmd->convert_arg = this_board->ai_ns_min;
756		if (tmp != cmd->convert_arg)
757			err++;
758	}
759
760	if (err) {
761#ifdef PCL812_EXTDEBUG
762		rt_printk
763			("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=4\n",
764			err);
765#endif
766		return 4;
767	}
768
769	return 0;
770}
771
772/*
773==============================================================================
774*/
775static int pcl812_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s)
776{
777	unsigned int divisor1 = 0, divisor2 = 0, i, dma_flags, bytes;
778	struct comedi_cmd *cmd = &s->async->cmd;
779
780#ifdef PCL812_EXTDEBUG
781	rt_printk("pcl812 EDBG: BGN: pcl812_ai_cmd(...)\n");
782#endif
783
784	if (cmd->start_src != TRIG_NOW)
785		return -EINVAL;
786	if (cmd->scan_begin_src != TRIG_FOLLOW)
787		return -EINVAL;
788	if (devpriv->use_ext_trg) {
789		if (cmd->convert_src != TRIG_EXT)
790			return -EINVAL;
791	} else {
792		if (cmd->convert_src != TRIG_TIMER)
793			return -EINVAL;
794	}
795	if (cmd->scan_end_src != TRIG_COUNT)
796		return -EINVAL;
797	if (cmd->scan_end_arg != cmd->chanlist_len)
798		return -EINVAL;
799	if (cmd->chanlist_len > MAX_CHANLIST_LEN)
800		return -EINVAL;
801
802	if (cmd->convert_src == TRIG_TIMER) {
803		if (cmd->convert_arg < this_board->ai_ns_min)
804			cmd->convert_arg = this_board->ai_ns_min;
805		i8253_cascade_ns_to_timer(this_board->i8254_osc_base,
806			&divisor1, &divisor2, &cmd->convert_arg,
807			cmd->flags & TRIG_ROUND_MASK);
808	}
809
810	start_pacer(dev, -1, 0, 0);	// stop pacer
811
812	devpriv->ai_n_chan = cmd->chanlist_len;
813	memcpy(devpriv->ai_chanlist, cmd->chanlist,
814		sizeof(unsigned int) * cmd->scan_end_arg);
815	setup_range_channel(dev, s, devpriv->ai_chanlist[0], 1);	// select first channel and range
816
817	if (devpriv->dma) {	// check if we can use DMA transfer
818		devpriv->ai_dma = 1;
819		for (i = 1; i < devpriv->ai_n_chan; i++)
820			if (devpriv->ai_chanlist[0] != devpriv->ai_chanlist[i]) {
821				devpriv->ai_dma = 0;	// we cann't use DMA :-(
822				break;
823			}
824	} else
825		devpriv->ai_dma = 0;
826
827	devpriv->ai_flags = cmd->flags;
828	devpriv->ai_data_len = s->async->prealloc_bufsz;
829	devpriv->ai_data = s->async->prealloc_buf;
830	if (cmd->stop_src == TRIG_COUNT) {
831		devpriv->ai_scans = cmd->stop_arg;
832		devpriv->ai_neverending = 0;
833	} else {
834		devpriv->ai_scans = 0;
835		devpriv->ai_neverending = 1;
836	}
837
838	devpriv->ai_act_scan = 0;
839	devpriv->ai_poll_ptr = 0;
840	s->async->cur_chan = 0;
841
842	if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {	// don't we want wake up every scan?
843		devpriv->ai_eos = 1;
844		if (devpriv->ai_n_chan == 1)
845			devpriv->ai_dma = 0;	// DMA is useless for this situation
846	}
847
848	if (devpriv->ai_dma) {
849		if (devpriv->ai_eos) {	// we use EOS, so adapt DMA buffer to one scan
850			devpriv->dmabytestomove[0] =
851				devpriv->ai_n_chan * sizeof(short);
852			devpriv->dmabytestomove[1] =
853				devpriv->ai_n_chan * sizeof(short);
854			devpriv->dma_runs_to_end = 1;
855		} else {
856			devpriv->dmabytestomove[0] = devpriv->hwdmasize[0];
857			devpriv->dmabytestomove[1] = devpriv->hwdmasize[1];
858			if (devpriv->ai_data_len < devpriv->hwdmasize[0])
859				devpriv->dmabytestomove[0] =
860					devpriv->ai_data_len;
861			if (devpriv->ai_data_len < devpriv->hwdmasize[1])
862				devpriv->dmabytestomove[1] =
863					devpriv->ai_data_len;
864			if (devpriv->ai_neverending) {
865				devpriv->dma_runs_to_end = 1;
866			} else {
867				bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short);	// how many samples we must transfer?
868				devpriv->dma_runs_to_end = bytes / devpriv->dmabytestomove[0];	// how many DMA pages we must fill
869				devpriv->last_dma_run = bytes % devpriv->dmabytestomove[0];	//on last dma transfer must be moved
870				if (devpriv->dma_runs_to_end == 0)
871					devpriv->dmabytestomove[0] =
872						devpriv->last_dma_run;
873				devpriv->dma_runs_to_end--;
874			}
875		}
876		if (devpriv->dmabytestomove[0] > devpriv->hwdmasize[0]) {
877			devpriv->dmabytestomove[0] = devpriv->hwdmasize[0];
878			devpriv->ai_eos = 0;
879		}
880		if (devpriv->dmabytestomove[1] > devpriv->hwdmasize[1]) {
881			devpriv->dmabytestomove[1] = devpriv->hwdmasize[1];
882			devpriv->ai_eos = 0;
883		}
884		devpriv->next_dma_buf = 0;
885		set_dma_mode(devpriv->dma, DMA_MODE_READ);
886		dma_flags = claim_dma_lock();
887		clear_dma_ff(devpriv->dma);
888		set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
889		set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]);
890		release_dma_lock(dma_flags);
891		enable_dma(devpriv->dma);
892#ifdef PCL812_EXTDEBUG
893		rt_printk
894			("pcl812 EDBG:   DMA %d PTR 0x%0x/0x%0x LEN %u/%u EOS %d\n",
895			devpriv->dma, devpriv->hwdmaptr[0],
896			devpriv->hwdmaptr[1], devpriv->dmabytestomove[0],
897			devpriv->dmabytestomove[1], devpriv->ai_eos);
898#endif
899	}
900
901	switch (cmd->convert_src) {
902	case TRIG_TIMER:
903		start_pacer(dev, 1, divisor1, divisor2);
904		break;
905	}
906
907	if (devpriv->ai_dma) {
908		outb(devpriv->mode_reg_int | 2, dev->iobase + PCL812_MODE);	// let's go!
909	} else {
910		outb(devpriv->mode_reg_int | 6, dev->iobase + PCL812_MODE);	// let's go!
911	}
912
913#ifdef PCL812_EXTDEBUG
914	rt_printk("pcl812 EDBG: END: pcl812_ai_cmd(...)\n");
915#endif
916
917	return 0;
918}
919
920/*
921==============================================================================
922*/
923static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d)
924{
925	char err = 1;
926	unsigned int mask, timeout;
927	struct comedi_device *dev = d;
928	struct comedi_subdevice *s = dev->subdevices + 0;
929
930	s->async->events = 0;
931
932	timeout = 50;		/* wait max 50us, it must finish under 33us */
933	if (devpriv->ai_is16b) {
934		mask = 0xffff;
935		while (timeout--) {
936			if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) {
937				err = 0;
938				break;
939			}
940			comedi_udelay(1);
941		}
942	} else {
943		mask = 0x0fff;
944		while (timeout--) {
945			if (!(inb(dev->iobase + PCL812_AD_HI) & PCL812_DRDY)) {
946				err = 0;
947				break;
948			}
949			comedi_udelay(1);
950		}
951	}
952
953	if (err) {
954		rt_printk
955			("comedi%d: pcl812: (%s at 0x%lx) A/D cmd IRQ without DRDY!\n",
956			dev->minor, dev->board_name, dev->iobase);
957		pcl812_ai_cancel(dev, s);
958		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
959		comedi_event(dev, s);
960		return IRQ_HANDLED;
961	}
962
963	comedi_buf_put(s->async,
964		((inb(dev->iobase + PCL812_AD_HI) << 8) | inb(dev->iobase +
965				PCL812_AD_LO)) & mask);
966
967	outb(0, dev->iobase + PCL812_CLRINT);	/* clear INT request */
968
969	if (s->async->cur_chan == 0) {	/* one scan done */
970		devpriv->ai_act_scan++;
971		if (!(devpriv->ai_neverending))
972			if (devpriv->ai_act_scan >= devpriv->ai_scans) {	/* all data sampled */
973				pcl812_ai_cancel(dev, s);
974				s->async->events |= COMEDI_CB_EOA;
975			}
976	}
977
978	comedi_event(dev, s);
979	return IRQ_HANDLED;
980}
981
982/*
983==============================================================================
984*/
985static void transfer_from_dma_buf(struct comedi_device * dev, struct comedi_subdevice * s,
986	short * ptr, unsigned int bufptr, unsigned int len)
987{
988	unsigned int i;
989
990	s->async->events = 0;
991	for (i = len; i; i--) {
992		comedi_buf_put(s->async, ptr[bufptr++]);	// get one sample
993
994		if (s->async->cur_chan == 0) {
995			devpriv->ai_act_scan++;
996			if (!devpriv->ai_neverending)
997				if (devpriv->ai_act_scan >= devpriv->ai_scans) {	/* all data sampled */
998					pcl812_ai_cancel(dev, s);
999					s->async->events |= COMEDI_CB_EOA;
1000					break;
1001				}
1002		}
1003	}
1004
1005	comedi_event(dev, s);
1006}
1007
1008/*
1009==============================================================================
1010*/
1011static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d)
1012{
1013	struct comedi_device *dev = d;
1014	struct comedi_subdevice *s = dev->subdevices + 0;
1015	unsigned long dma_flags;
1016	int len, bufptr;
1017	short *ptr;
1018
1019#ifdef PCL812_EXTDEBUG
1020	rt_printk("pcl812 EDBG: BGN: interrupt_pcl812_ai_dma(...)\n");
1021#endif
1022	ptr = (short *) devpriv->dmabuf[devpriv->next_dma_buf];
1023	len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) -
1024		devpriv->ai_poll_ptr;
1025
1026	devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
1027	disable_dma(devpriv->dma);
1028	set_dma_mode(devpriv->dma, DMA_MODE_READ);
1029	dma_flags = claim_dma_lock();
1030	set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]);
1031	if (devpriv->ai_eos) {
1032		set_dma_count(devpriv->dma,
1033			devpriv->dmabytestomove[devpriv->next_dma_buf]);
1034	} else {
1035		if (devpriv->dma_runs_to_end) {
1036			set_dma_count(devpriv->dma,
1037				devpriv->dmabytestomove[devpriv->next_dma_buf]);
1038		} else {
1039			set_dma_count(devpriv->dma, devpriv->last_dma_run);
1040		}
1041		devpriv->dma_runs_to_end--;
1042	}
1043	release_dma_lock(dma_flags);
1044	enable_dma(devpriv->dma);
1045
1046	outb(0, dev->iobase + PCL812_CLRINT);	/* clear INT request */
1047
1048	bufptr = devpriv->ai_poll_ptr;
1049	devpriv->ai_poll_ptr = 0;
1050
1051	transfer_from_dma_buf(dev, s, ptr, bufptr, len);
1052
1053#ifdef PCL812_EXTDEBUG
1054	rt_printk("pcl812 EDBG: END: interrupt_pcl812_ai_dma(...)\n");
1055#endif
1056	return IRQ_HANDLED;
1057}
1058
1059/*
1060==============================================================================
1061*/
1062static irqreturn_t interrupt_pcl812(int irq, void *d PT_REGS_ARG)
1063{
1064	struct comedi_device *dev = d;
1065
1066	if (!dev->attached) {
1067		comedi_error(dev, "spurious interrupt");
1068		return IRQ_HANDLED;
1069	}
1070	if (devpriv->ai_dma) {
1071		return interrupt_pcl812_ai_dma(irq, d);
1072	} else {
1073		return interrupt_pcl812_ai_int(irq, d);
1074	};
1075}
1076
1077/*
1078==============================================================================
1079*/
1080static int pcl812_ai_poll(struct comedi_device * dev, struct comedi_subdevice * s)
1081{
1082	unsigned long flags;
1083	unsigned int top1, top2, i;
1084
1085	if (!devpriv->ai_dma)
1086		return 0;	// poll is valid only for DMA transfer
1087
1088	comedi_spin_lock_irqsave(&dev->spinlock, flags);
1089
1090	for (i = 0; i < 10; i++) {
1091		top1 = get_dma_residue(devpriv->ai_dma);	// where is now DMA
1092		top2 = get_dma_residue(devpriv->ai_dma);
1093		if (top1 == top2)
1094			break;
1095	}
1096
1097	if (top1 != top2) {
1098		comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
1099		return 0;
1100	}
1101
1102	top1 = devpriv->dmabytestomove[1 - devpriv->next_dma_buf] - top1;	// where is now DMA in buffer
1103	top1 >>= 1;		// sample position
1104	top2 = top1 - devpriv->ai_poll_ptr;
1105	if (top2 < 1) {		// no new samples
1106		comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
1107		return 0;
1108	}
1109
1110	transfer_from_dma_buf(dev, s,
1111		(void *)devpriv->dmabuf[1 - devpriv->next_dma_buf],
1112		devpriv->ai_poll_ptr, top2);
1113
1114	devpriv->ai_poll_ptr = top1;	// new buffer position
1115
1116	comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
1117
1118	return s->async->buf_write_count - s->async->buf_read_count;
1119}
1120
1121/*
1122==============================================================================
1123*/
1124static void setup_range_channel(struct comedi_device * dev, struct comedi_subdevice * s,
1125	unsigned int rangechan, char wait)
1126{
1127	unsigned char chan_reg = CR_CHAN(rangechan);	// normal board
1128	unsigned char gain_reg = CR_RANGE(rangechan) + devpriv->range_correction;	// gain index
1129
1130	if ((chan_reg == devpriv->old_chan_reg)
1131		&& (gain_reg == devpriv->old_gain_reg))
1132		return;		// we can return, no change
1133
1134	devpriv->old_chan_reg = chan_reg;
1135	devpriv->old_gain_reg = gain_reg;
1136
1137	if (devpriv->use_MPC) {
1138		if (devpriv->use_diff) {
1139			chan_reg = chan_reg | 0x30;	// DIFF inputs
1140		} else {
1141			if (chan_reg & 0x80) {
1142				chan_reg = chan_reg | 0x20;	// SE inputs 8-15
1143			} else {
1144				chan_reg = chan_reg | 0x10;	// SE inputs 0-7
1145			}
1146		}
1147	}
1148
1149	outb(chan_reg, dev->iobase + PCL812_MUX);	/* select channel */
1150	outb(gain_reg, dev->iobase + PCL812_GAIN);	/* select gain */
1151
1152	if (wait) {
1153		comedi_udelay(devpriv->max_812_ai_mode0_rangewait);	// XXX this depends on selected range and can be very long for some high gain ranges!
1154	}
1155}
1156
1157/*
1158==============================================================================
1159*/
1160static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1,
1161	unsigned int divisor2)
1162{
1163#ifdef PCL812_EXTDEBUG
1164	rt_printk("pcl812 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode, divisor1,
1165		divisor2);
1166#endif
1167	outb(0xb4, dev->iobase + PCL812_CTRCTL);
1168	outb(0x74, dev->iobase + PCL812_CTRCTL);
1169	comedi_udelay(1);
1170
1171	if (mode == 1) {
1172		outb(divisor2 & 0xff, dev->iobase + PCL812_CTR2);
1173		outb((divisor2 >> 8) & 0xff, dev->iobase + PCL812_CTR2);
1174		outb(divisor1 & 0xff, dev->iobase + PCL812_CTR1);
1175		outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1);
1176	}
1177#ifdef PCL812_EXTDEBUG
1178	rt_printk("pcl812 EDBG: END: start_pacer(...)\n");
1179#endif
1180}
1181
1182/*
1183==============================================================================
1184*/
1185static void free_resources(struct comedi_device * dev)
1186{
1187
1188	if (dev->private) {
1189		if (devpriv->dmabuf[0])
1190			free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1191		if (devpriv->dmabuf[1])
1192			free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1193		if (devpriv->dma)
1194			free_dma(devpriv->dma);
1195	}
1196	if (dev->irq)
1197		comedi_free_irq(dev->irq, dev);
1198	if (dev->iobase)
1199		release_region(dev->iobase, this_board->io_range);
1200}
1201
1202/*
1203==============================================================================
1204*/
1205static int pcl812_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s)
1206{
1207#ifdef PCL812_EXTDEBUG
1208	rt_printk("pcl812 EDBG: BGN: pcl812_ai_cancel(...)\n");
1209#endif
1210	if (devpriv->ai_dma)
1211		disable_dma(devpriv->dma);
1212	outb(0, dev->iobase + PCL812_CLRINT);	/* clear INT request */
1213	outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);	/* Stop A/D */
1214	start_pacer(dev, -1, 0, 0);	// stop 8254
1215	outb(0, dev->iobase + PCL812_CLRINT);	/* clear INT request */
1216#ifdef PCL812_EXTDEBUG
1217	rt_printk("pcl812 EDBG: END: pcl812_ai_cancel(...)\n");
1218#endif
1219	return 0;
1220}
1221
1222/*
1223==============================================================================
1224*/
1225static void pcl812_reset(struct comedi_device * dev)
1226{
1227#ifdef PCL812_EXTDEBUG
1228	rt_printk("pcl812 EDBG: BGN: pcl812_reset(...)\n");
1229#endif
1230	outb(0, dev->iobase + PCL812_MUX);
1231	outb(0 + devpriv->range_correction, dev->iobase + PCL812_GAIN);
1232	devpriv->old_chan_reg = -1;	// invalidate chain/gain memory
1233	devpriv->old_gain_reg = -1;
1234
1235	switch (this_board->board_type) {
1236	case boardPCL812PG:
1237	case boardPCL812:
1238	case boardACL8112:
1239	case boardACL8216:
1240		outb(0, dev->iobase + PCL812_DA2_LO);
1241		outb(0, dev->iobase + PCL812_DA2_HI);
1242	case boardA821:
1243		outb(0, dev->iobase + PCL812_DA1_LO);
1244		outb(0, dev->iobase + PCL812_DA1_HI);
1245		start_pacer(dev, -1, 0, 0);	// stop 8254
1246		outb(0, dev->iobase + PCL812_DO_HI);
1247		outb(0, dev->iobase + PCL812_DO_LO);
1248		outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
1249		outb(0, dev->iobase + PCL812_CLRINT);
1250		break;
1251	case boardPCL813B:
1252	case boardPCL813:
1253	case boardISO813:
1254	case boardACL8113:
1255		comedi_udelay(5);
1256		break;
1257	}
1258	comedi_udelay(5);
1259#ifdef PCL812_EXTDEBUG
1260	rt_printk("pcl812 EDBG: END: pcl812_reset(...)\n");
1261#endif
1262}
1263
1264/*
1265==============================================================================
1266*/
1267static int pcl812_attach(struct comedi_device * dev, struct comedi_devconfig * it)
1268{
1269	int ret, subdev;
1270	unsigned long iobase;
1271	unsigned int irq;
1272	unsigned int dma;
1273	unsigned long pages;
1274	struct comedi_subdevice *s;
1275	int n_subdevices;
1276
1277	iobase = it->options[0];
1278	printk("comedi%d: pcl812:  board=%s, ioport=0x%03lx", dev->minor,
1279		this_board->name, iobase);
1280
1281	if (!request_region(iobase, this_board->io_range, "pcl812")) {
1282		printk("I/O port conflict\n");
1283		return -EIO;
1284	}
1285	dev->iobase = iobase;
1286
1287	if ((ret = alloc_private(dev, sizeof(struct pcl812_private))) < 0) {
1288		free_resources(dev);
1289		return ret;	/* Can't alloc mem */
1290	}
1291
1292	dev->board_name = this_board->name;
1293
1294	irq = 0;
1295	if (this_board->IRQbits != 0) {	/* board support IRQ */
1296		irq = it->options[1];
1297		if (irq) {	/* we want to use IRQ */
1298			if (((1 << irq) & this_board->IRQbits) == 0) {
1299				printk(", IRQ %u is out of allowed range, DISABLING IT", irq);
1300				irq = 0;	/* Bad IRQ */
1301			} else {
1302				if (comedi_request_irq(irq, interrupt_pcl812, 0,
1303						"pcl812", dev)) {
1304					printk(", unable to allocate IRQ %u, DISABLING IT", irq);
1305					irq = 0;	/* Can't use IRQ */
1306				} else {
1307					printk(", irq=%u", irq);
1308				}
1309			}
1310		}
1311	}
1312
1313	dev->irq = irq;
1314
1315	dma = 0;
1316	devpriv->dma = dma;
1317	if (!dev->irq)
1318		goto no_dma;	/* if we haven't IRQ, we can't use DMA */
1319	if (this_board->DMAbits != 0) {	/* board support DMA */
1320		dma = it->options[2];
1321		if (((1 << dma) & this_board->DMAbits) == 0) {
1322			printk(", DMA is out of allowed range, FAIL!\n");
1323			return -EINVAL;	/* Bad DMA */
1324		}
1325		ret = request_dma(dma, "pcl812");
1326		if (ret) {
1327			printk(", unable to allocate DMA %u, FAIL!\n", dma);
1328			return -EBUSY;	/* DMA isn't free */
1329		}
1330		devpriv->dma = dma;
1331		printk(", dma=%u", dma);
1332		pages = 1;	/* we want 8KB */
1333		devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1334		if (!devpriv->dmabuf[0]) {
1335			printk(", unable to allocate DMA buffer, FAIL!\n");
1336			/* maybe experiment with try_to_free_pages() will help .... */
1337			free_resources(dev);
1338			return -EBUSY;	/* no buffer :-( */
1339		}
1340		devpriv->dmapages[0] = pages;
1341		devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1342		devpriv->hwdmasize[0] = PAGE_SIZE * (1 << pages);
1343		devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1344		if (!devpriv->dmabuf[1]) {
1345			printk(", unable to allocate DMA buffer, FAIL!\n");
1346			free_resources(dev);
1347			return -EBUSY;
1348		}
1349		devpriv->dmapages[1] = pages;
1350		devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
1351		devpriv->hwdmasize[1] = PAGE_SIZE * (1 << pages);
1352	}
1353      no_dma:
1354
1355	n_subdevices = 0;
1356	if (this_board->n_aichan > 0)
1357		n_subdevices++;
1358	if (this_board->n_aochan > 0)
1359		n_subdevices++;
1360	if (this_board->n_dichan > 0)
1361		n_subdevices++;
1362	if (this_board->n_dochan > 0)
1363		n_subdevices++;
1364
1365	if ((ret = alloc_subdevices(dev, n_subdevices)) < 0) {
1366		free_resources(dev);
1367		return ret;
1368	}
1369
1370	subdev = 0;
1371
1372	/* analog input */
1373	if (this_board->n_aichan > 0) {
1374		s = dev->subdevices + subdev;
1375		s->type = COMEDI_SUBD_AI;
1376		s->subdev_flags = SDF_READABLE;
1377		switch (this_board->board_type) {
1378		case boardA821:
1379			if (it->options[2] == 1) {
1380				s->n_chan = this_board->n_aichan_diff;
1381				s->subdev_flags |= SDF_DIFF;
1382				devpriv->use_diff = 1;
1383			} else {
1384				s->n_chan = this_board->n_aichan;
1385				s->subdev_flags |= SDF_GROUND;
1386			}
1387			break;
1388		case boardACL8112:
1389		case boardACL8216:
1390			if (it->options[4] == 1) {
1391				s->n_chan = this_board->n_aichan_diff;
1392				s->subdev_flags |= SDF_DIFF;
1393				devpriv->use_diff = 1;
1394			} else {
1395				s->n_chan = this_board->n_aichan;
1396				s->subdev_flags |= SDF_GROUND;
1397			}
1398			break;
1399		default:
1400			s->n_chan = this_board->n_aichan;
1401			s->subdev_flags |= SDF_GROUND;
1402			break;
1403		}
1404		s->maxdata = this_board->ai_maxdata;
1405		s->len_chanlist = MAX_CHANLIST_LEN;
1406		s->range_table = this_board->rangelist_ai;
1407		if (this_board->board_type == boardACL8216) {
1408			s->insn_read = acl8216_ai_insn_read;
1409		} else {
1410			s->insn_read = pcl812_ai_insn_read;
1411		}
1412		devpriv->use_MPC = this_board->haveMPC508;
1413		s->cancel = pcl812_ai_cancel;
1414		if (dev->irq) {
1415			dev->read_subdev = s;
1416			s->subdev_flags |= SDF_CMD_READ;
1417			s->do_cmdtest = pcl812_ai_cmdtest;
1418			s->do_cmd = pcl812_ai_cmd;
1419			s->poll = pcl812_ai_poll;
1420		}
1421		switch (this_board->board_type) {
1422		case boardPCL812PG:
1423			if (it->options[4] == 1)
1424				s->range_table = &range_pcl812pg2_ai;
1425			break;
1426		case boardPCL812:
1427			switch (it->options[4]) {
1428			case 0:
1429				s->range_table = &range_bipolar10;
1430				break;
1431			case 1:
1432				s->range_table = &range_bipolar5;
1433				break;
1434			case 2:
1435				s->range_table = &range_bipolar2_5;
1436				break;
1437			case 3:
1438				s->range_table = &range812_bipolar1_25;
1439				break;
1440			case 4:
1441				s->range_table = &range812_bipolar0_625;
1442				break;
1443			case 5:
1444				s->range_table = &range812_bipolar0_3125;
1445				break;
1446			default:
1447				s->range_table = &range_bipolar10;
1448				break;
1449				printk(", incorrect range number %d, changing to 0 (+/-10V)", it->options[4]);
1450				break;
1451			}
1452			break;
1453			break;
1454		case boardPCL813B:
1455			if (it->options[1] == 1)
1456				s->range_table = &range_pcl813b2_ai;
1457			break;
1458		case boardISO813:
1459			switch (it->options[1]) {
1460			case 0:
1461				s->range_table = &range_iso813_1_ai;
1462				break;
1463			case 1:
1464				s->range_table = &range_iso813_1_2_ai;
1465				break;
1466			case 2:
1467				s->range_table = &range_iso813_2_ai;
1468				devpriv->range_correction = 1;
1469				break;
1470			case 3:
1471				s->range_table = &range_iso813_2_2_ai;
1472				devpriv->range_correction = 1;
1473				break;
1474			default:
1475				s->range_table = &range_iso813_1_ai;
1476				break;
1477				printk(", incorrect range number %d, changing to 0 ", it->options[1]);
1478				break;
1479			}
1480			break;
1481		case boardACL8113:
1482			switch (it->options[1]) {
1483			case 0:
1484				s->range_table = &range_acl8113_1_ai;
1485				break;
1486			case 1:
1487				s->range_table = &range_acl8113_1_2_ai;
1488				break;
1489			case 2:
1490				s->range_table = &range_acl8113_2_ai;
1491				devpriv->range_correction = 1;
1492				break;
1493			case 3:
1494				s->range_table = &range_acl8113_2_2_ai;
1495				devpriv->range_correction = 1;
1496				break;
1497			default:
1498				s->range_table = &range_acl8113_1_ai;
1499				break;
1500				printk(", incorrect range number %d, changing to 0 ", it->options[1]);
1501				break;
1502			}
1503			break;
1504		}
1505		subdev++;
1506	}
1507
1508	/* analog output */
1509	if (this_board->n_aochan > 0) {
1510		s = dev->subdevices + subdev;
1511		s->type = COMEDI_SUBD_AO;
1512		s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1513		s->n_chan = this_board->n_aochan;
1514		s->maxdata = 0xfff;
1515		s->len_chanlist = 1;
1516		s->range_table = this_board->rangelist_ao;
1517		s->insn_read = pcl812_ao_insn_read;
1518		s->insn_write = pcl812_ao_insn_write;
1519		switch (this_board->board_type) {
1520		case boardA821:
1521			if (it->options[3] == 1)
1522				s->range_table = &range_unipolar10;
1523			break;
1524		case boardPCL812:
1525		case boardACL8112:
1526		case boardPCL812PG:
1527		case boardACL8216:
1528			if (it->options[5] == 1)
1529				s->range_table = &range_unipolar10;
1530			if (it->options[5] == 2)
1531				s->range_table = &range_unknown;
1532			break;
1533		}
1534		subdev++;
1535	}
1536
1537	/* digital input */
1538	if (this_board->n_dichan > 0) {
1539		s = dev->subdevices + subdev;
1540		s->type = COMEDI_SUBD_DI;
1541		s->subdev_flags = SDF_READABLE;
1542		s->n_chan = this_board->n_dichan;
1543		s->maxdata = 1;
1544		s->len_chanlist = this_board->n_dichan;
1545		s->range_table = &range_digital;
1546		s->insn_bits = pcl812_di_insn_bits;
1547		subdev++;
1548	}
1549
1550	/* digital output */
1551	if (this_board->n_dochan > 0) {
1552		s = dev->subdevices + subdev;
1553		s->type = COMEDI_SUBD_DO;
1554		s->subdev_flags = SDF_WRITABLE;
1555		s->n_chan = this_board->n_dochan;
1556		s->maxdata = 1;
1557		s->len_chanlist = this_board->n_dochan;
1558		s->range_table = &range_digital;
1559		s->insn_bits = pcl812_do_insn_bits;
1560		subdev++;
1561	}
1562
1563	switch (this_board->board_type) {
1564	case boardACL8216:
1565		devpriv->ai_is16b = 1;
1566	case boardPCL812PG:
1567	case boardPCL812:
1568	case boardACL8112:
1569		devpriv->max_812_ai_mode0_rangewait = 1;
1570		if (it->options[3] > 0)
1571			devpriv->use_ext_trg = 1;	// we use external trigger
1572	case boardA821:
1573		devpriv->max_812_ai_mode0_rangewait = 1;
1574		devpriv->mode_reg_int = (irq << 4) & 0xf0;
1575		break;
1576	case boardPCL813B:
1577	case boardPCL813:
1578	case boardISO813:
1579	case boardACL8113:
1580		devpriv->max_812_ai_mode0_rangewait = 5;	/* maybe there must by greatest timeout */
1581		break;
1582	}
1583
1584	printk("\n");
1585	devpriv->valid = 1;
1586
1587	pcl812_reset(dev);
1588
1589	return 0;
1590}
1591
1592/*
1593==============================================================================
1594 */
1595static int pcl812_detach(struct comedi_device * dev)
1596{
1597
1598#ifdef PCL812_EXTDEBUG
1599	rt_printk("comedi%d: pcl812: remove\n", dev->minor);
1600#endif
1601	free_resources(dev);
1602	return 0;
1603}
1604