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