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