pcl812.c revision 0a85b6f0ab0d2edb0d41b32697111ce0e4f43496
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 <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	if (s->async->cur_chan == 0) {	/* one scan done */
999		devpriv->ai_act_scan++;
1000		if (!(devpriv->ai_neverending))
1001			if (devpriv->ai_act_scan >= devpriv->ai_scans) {	/* all data sampled */
1002				pcl812_ai_cancel(dev, s);
1003				s->async->events |= COMEDI_CB_EOA;
1004			}
1005	}
1006
1007	comedi_event(dev, s);
1008	return IRQ_HANDLED;
1009}
1010
1011/*
1012==============================================================================
1013*/
1014static void transfer_from_dma_buf(struct comedi_device *dev,
1015				  struct comedi_subdevice *s, short *ptr,
1016				  unsigned int bufptr, unsigned int len)
1017{
1018	unsigned int i;
1019
1020	s->async->events = 0;
1021	for (i = len; i; i--) {
1022		comedi_buf_put(s->async, ptr[bufptr++]);	/*  get one sample */
1023
1024		if (s->async->cur_chan == 0) {
1025			devpriv->ai_act_scan++;
1026			if (!devpriv->ai_neverending)
1027				if (devpriv->ai_act_scan >= devpriv->ai_scans) {	/* all data sampled */
1028					pcl812_ai_cancel(dev, s);
1029					s->async->events |= COMEDI_CB_EOA;
1030					break;
1031				}
1032		}
1033	}
1034
1035	comedi_event(dev, s);
1036}
1037
1038/*
1039==============================================================================
1040*/
1041static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d)
1042{
1043	struct comedi_device *dev = d;
1044	struct comedi_subdevice *s = dev->subdevices + 0;
1045	unsigned long dma_flags;
1046	int len, bufptr;
1047	short *ptr;
1048
1049#ifdef PCL812_EXTDEBUG
1050	printk("pcl812 EDBG: BGN: interrupt_pcl812_ai_dma(...)\n");
1051#endif
1052	ptr = (short *)devpriv->dmabuf[devpriv->next_dma_buf];
1053	len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) -
1054	    devpriv->ai_poll_ptr;
1055
1056	devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
1057	disable_dma(devpriv->dma);
1058	set_dma_mode(devpriv->dma, DMA_MODE_READ);
1059	dma_flags = claim_dma_lock();
1060	set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]);
1061	if (devpriv->ai_eos) {
1062		set_dma_count(devpriv->dma,
1063			      devpriv->dmabytestomove[devpriv->next_dma_buf]);
1064	} else {
1065		if (devpriv->dma_runs_to_end) {
1066			set_dma_count(devpriv->dma,
1067				      devpriv->dmabytestomove[devpriv->
1068							      next_dma_buf]);
1069		} else {
1070			set_dma_count(devpriv->dma, devpriv->last_dma_run);
1071		}
1072		devpriv->dma_runs_to_end--;
1073	}
1074	release_dma_lock(dma_flags);
1075	enable_dma(devpriv->dma);
1076
1077	outb(0, dev->iobase + PCL812_CLRINT);	/* clear INT request */
1078
1079	bufptr = devpriv->ai_poll_ptr;
1080	devpriv->ai_poll_ptr = 0;
1081
1082	transfer_from_dma_buf(dev, s, ptr, bufptr, len);
1083
1084#ifdef PCL812_EXTDEBUG
1085	printk("pcl812 EDBG: END: interrupt_pcl812_ai_dma(...)\n");
1086#endif
1087	return IRQ_HANDLED;
1088}
1089
1090/*
1091==============================================================================
1092*/
1093static irqreturn_t interrupt_pcl812(int irq, void *d)
1094{
1095	struct comedi_device *dev = d;
1096
1097	if (!dev->attached) {
1098		comedi_error(dev, "spurious interrupt");
1099		return IRQ_HANDLED;
1100	}
1101	if (devpriv->ai_dma) {
1102		return interrupt_pcl812_ai_dma(irq, d);
1103	} else {
1104		return interrupt_pcl812_ai_int(irq, d);
1105	};
1106}
1107
1108/*
1109==============================================================================
1110*/
1111static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
1112{
1113	unsigned long flags;
1114	unsigned int top1, top2, i;
1115
1116	if (!devpriv->ai_dma)
1117		return 0;	/*  poll is valid only for DMA transfer */
1118
1119	spin_lock_irqsave(&dev->spinlock, flags);
1120
1121	for (i = 0; i < 10; i++) {
1122		top1 = get_dma_residue(devpriv->ai_dma);	/*  where is now DMA */
1123		top2 = get_dma_residue(devpriv->ai_dma);
1124		if (top1 == top2)
1125			break;
1126	}
1127
1128	if (top1 != top2) {
1129		spin_unlock_irqrestore(&dev->spinlock, flags);
1130		return 0;
1131	}
1132
1133	top1 = devpriv->dmabytestomove[1 - devpriv->next_dma_buf] - top1;	/*  where is now DMA in buffer */
1134	top1 >>= 1;		/*  sample position */
1135	top2 = top1 - devpriv->ai_poll_ptr;
1136	if (top2 < 1) {		/*  no new samples */
1137		spin_unlock_irqrestore(&dev->spinlock, flags);
1138		return 0;
1139	}
1140
1141	transfer_from_dma_buf(dev, s,
1142			      (void *)devpriv->dmabuf[1 -
1143						      devpriv->next_dma_buf],
1144			      devpriv->ai_poll_ptr, top2);
1145
1146	devpriv->ai_poll_ptr = top1;	/*  new buffer position */
1147
1148	spin_unlock_irqrestore(&dev->spinlock, flags);
1149
1150	return s->async->buf_write_count - s->async->buf_read_count;
1151}
1152
1153/*
1154==============================================================================
1155*/
1156static void setup_range_channel(struct comedi_device *dev,
1157				struct comedi_subdevice *s,
1158				unsigned int rangechan, char wait)
1159{
1160	unsigned char chan_reg = CR_CHAN(rangechan);	/*  normal board */
1161	unsigned char gain_reg = CR_RANGE(rangechan) + devpriv->range_correction;	/*  gain index */
1162
1163	if ((chan_reg == devpriv->old_chan_reg)
1164	    && (gain_reg == devpriv->old_gain_reg))
1165		return;		/*  we can return, no change */
1166
1167	devpriv->old_chan_reg = chan_reg;
1168	devpriv->old_gain_reg = gain_reg;
1169
1170	if (devpriv->use_MPC) {
1171		if (devpriv->use_diff) {
1172			chan_reg = chan_reg | 0x30;	/*  DIFF inputs */
1173		} else {
1174			if (chan_reg & 0x80) {
1175				chan_reg = chan_reg | 0x20;	/*  SE inputs 8-15 */
1176			} else {
1177				chan_reg = chan_reg | 0x10;	/*  SE inputs 0-7 */
1178			}
1179		}
1180	}
1181
1182	outb(chan_reg, dev->iobase + PCL812_MUX);	/* select channel */
1183	outb(gain_reg, dev->iobase + PCL812_GAIN);	/* select gain */
1184
1185	if (wait) {
1186		udelay(devpriv->max_812_ai_mode0_rangewait);	/*  XXX this depends on selected range and can be very long for some high gain ranges! */
1187	}
1188}
1189
1190/*
1191==============================================================================
1192*/
1193static void start_pacer(struct comedi_device *dev, int mode,
1194			unsigned int divisor1, unsigned int divisor2)
1195{
1196#ifdef PCL812_EXTDEBUG
1197	printk("pcl812 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode, divisor1,
1198	       divisor2);
1199#endif
1200	outb(0xb4, dev->iobase + PCL812_CTRCTL);
1201	outb(0x74, dev->iobase + PCL812_CTRCTL);
1202	udelay(1);
1203
1204	if (mode == 1) {
1205		outb(divisor2 & 0xff, dev->iobase + PCL812_CTR2);
1206		outb((divisor2 >> 8) & 0xff, dev->iobase + PCL812_CTR2);
1207		outb(divisor1 & 0xff, dev->iobase + PCL812_CTR1);
1208		outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1);
1209	}
1210#ifdef PCL812_EXTDEBUG
1211	printk("pcl812 EDBG: END: start_pacer(...)\n");
1212#endif
1213}
1214
1215/*
1216==============================================================================
1217*/
1218static void free_resources(struct comedi_device *dev)
1219{
1220
1221	if (dev->private) {
1222		if (devpriv->dmabuf[0])
1223			free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1224		if (devpriv->dmabuf[1])
1225			free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1226		if (devpriv->dma)
1227			free_dma(devpriv->dma);
1228	}
1229	if (dev->irq)
1230		free_irq(dev->irq, dev);
1231	if (dev->iobase)
1232		release_region(dev->iobase, this_board->io_range);
1233}
1234
1235/*
1236==============================================================================
1237*/
1238static int pcl812_ai_cancel(struct comedi_device *dev,
1239			    struct comedi_subdevice *s)
1240{
1241#ifdef PCL812_EXTDEBUG
1242	printk("pcl812 EDBG: BGN: pcl812_ai_cancel(...)\n");
1243#endif
1244	if (devpriv->ai_dma)
1245		disable_dma(devpriv->dma);
1246	outb(0, dev->iobase + PCL812_CLRINT);	/* clear INT request */
1247	outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);	/* Stop A/D */
1248	start_pacer(dev, -1, 0, 0);	/*  stop 8254 */
1249	outb(0, dev->iobase + PCL812_CLRINT);	/* clear INT request */
1250#ifdef PCL812_EXTDEBUG
1251	printk("pcl812 EDBG: END: pcl812_ai_cancel(...)\n");
1252#endif
1253	return 0;
1254}
1255
1256/*
1257==============================================================================
1258*/
1259static void pcl812_reset(struct comedi_device *dev)
1260{
1261#ifdef PCL812_EXTDEBUG
1262	printk("pcl812 EDBG: BGN: pcl812_reset(...)\n");
1263#endif
1264	outb(0, dev->iobase + PCL812_MUX);
1265	outb(0 + devpriv->range_correction, dev->iobase + PCL812_GAIN);
1266	devpriv->old_chan_reg = -1;	/*  invalidate chain/gain memory */
1267	devpriv->old_gain_reg = -1;
1268
1269	switch (this_board->board_type) {
1270	case boardPCL812PG:
1271	case boardPCL812:
1272	case boardACL8112:
1273	case boardACL8216:
1274		outb(0, dev->iobase + PCL812_DA2_LO);
1275		outb(0, dev->iobase + PCL812_DA2_HI);
1276	case boardA821:
1277		outb(0, dev->iobase + PCL812_DA1_LO);
1278		outb(0, dev->iobase + PCL812_DA1_HI);
1279		start_pacer(dev, -1, 0, 0);	/*  stop 8254 */
1280		outb(0, dev->iobase + PCL812_DO_HI);
1281		outb(0, dev->iobase + PCL812_DO_LO);
1282		outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
1283		outb(0, dev->iobase + PCL812_CLRINT);
1284		break;
1285	case boardPCL813B:
1286	case boardPCL813:
1287	case boardISO813:
1288	case boardACL8113:
1289		udelay(5);
1290		break;
1291	}
1292	udelay(5);
1293#ifdef PCL812_EXTDEBUG
1294	printk("pcl812 EDBG: END: pcl812_reset(...)\n");
1295#endif
1296}
1297
1298/*
1299==============================================================================
1300*/
1301static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1302{
1303	int ret, subdev;
1304	unsigned long iobase;
1305	unsigned int irq;
1306	unsigned int dma;
1307	unsigned long pages;
1308	struct comedi_subdevice *s;
1309	int n_subdevices;
1310
1311	iobase = it->options[0];
1312	printk("comedi%d: pcl812:  board=%s, ioport=0x%03lx", dev->minor,
1313	       this_board->name, iobase);
1314
1315	if (!request_region(iobase, this_board->io_range, "pcl812")) {
1316		printk("I/O port conflict\n");
1317		return -EIO;
1318	}
1319	dev->iobase = iobase;
1320
1321	ret = alloc_private(dev, sizeof(struct pcl812_private));
1322	if (ret < 0) {
1323		free_resources(dev);
1324		return ret;	/* Can't alloc mem */
1325	}
1326
1327	dev->board_name = this_board->name;
1328
1329	irq = 0;
1330	if (this_board->IRQbits != 0) {	/* board support IRQ */
1331		irq = it->options[1];
1332		if (irq) {	/* we want to use IRQ */
1333			if (((1 << irq) & this_board->IRQbits) == 0) {
1334				printk
1335				    (", IRQ %u is out of allowed range, DISABLING IT",
1336				     irq);
1337				irq = 0;	/* Bad IRQ */
1338			} else {
1339				if (request_irq
1340				    (irq, interrupt_pcl812, 0, "pcl812", dev)) {
1341					printk
1342					    (", unable to allocate IRQ %u, DISABLING IT",
1343					     irq);
1344					irq = 0;	/* Can't use IRQ */
1345				} else {
1346					printk(", irq=%u", irq);
1347				}
1348			}
1349		}
1350	}
1351
1352	dev->irq = irq;
1353
1354	dma = 0;
1355	devpriv->dma = dma;
1356	if (!dev->irq)
1357		goto no_dma;	/* if we haven't IRQ, we can't use DMA */
1358	if (this_board->DMAbits != 0) {	/* board support DMA */
1359		dma = it->options[2];
1360		if (((1 << dma) & this_board->DMAbits) == 0) {
1361			printk(", DMA is out of allowed range, FAIL!\n");
1362			return -EINVAL;	/* Bad DMA */
1363		}
1364		ret = request_dma(dma, "pcl812");
1365		if (ret) {
1366			printk(", unable to allocate DMA %u, FAIL!\n", dma);
1367			return -EBUSY;	/* DMA isn't free */
1368		}
1369		devpriv->dma = dma;
1370		printk(", dma=%u", dma);
1371		pages = 1;	/* we want 8KB */
1372		devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1373		if (!devpriv->dmabuf[0]) {
1374			printk(", unable to allocate DMA buffer, FAIL!\n");
1375			/* maybe experiment with try_to_free_pages() will help .... */
1376			free_resources(dev);
1377			return -EBUSY;	/* no buffer :-( */
1378		}
1379		devpriv->dmapages[0] = pages;
1380		devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1381		devpriv->hwdmasize[0] = PAGE_SIZE * (1 << pages);
1382		devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1383		if (!devpriv->dmabuf[1]) {
1384			printk(", unable to allocate DMA buffer, FAIL!\n");
1385			free_resources(dev);
1386			return -EBUSY;
1387		}
1388		devpriv->dmapages[1] = pages;
1389		devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
1390		devpriv->hwdmasize[1] = PAGE_SIZE * (1 << pages);
1391	}
1392no_dma:
1393
1394	n_subdevices = 0;
1395	if (this_board->n_aichan > 0)
1396		n_subdevices++;
1397	if (this_board->n_aochan > 0)
1398		n_subdevices++;
1399	if (this_board->n_dichan > 0)
1400		n_subdevices++;
1401	if (this_board->n_dochan > 0)
1402		n_subdevices++;
1403
1404	ret = alloc_subdevices(dev, n_subdevices);
1405	if (ret < 0) {
1406		free_resources(dev);
1407		return ret;
1408	}
1409
1410	subdev = 0;
1411
1412	/* analog input */
1413	if (this_board->n_aichan > 0) {
1414		s = dev->subdevices + subdev;
1415		s->type = COMEDI_SUBD_AI;
1416		s->subdev_flags = SDF_READABLE;
1417		switch (this_board->board_type) {
1418		case boardA821:
1419			if (it->options[2] == 1) {
1420				s->n_chan = this_board->n_aichan_diff;
1421				s->subdev_flags |= SDF_DIFF;
1422				devpriv->use_diff = 1;
1423			} else {
1424				s->n_chan = this_board->n_aichan;
1425				s->subdev_flags |= SDF_GROUND;
1426			}
1427			break;
1428		case boardACL8112:
1429		case boardACL8216:
1430			if (it->options[4] == 1) {
1431				s->n_chan = this_board->n_aichan_diff;
1432				s->subdev_flags |= SDF_DIFF;
1433				devpriv->use_diff = 1;
1434			} else {
1435				s->n_chan = this_board->n_aichan;
1436				s->subdev_flags |= SDF_GROUND;
1437			}
1438			break;
1439		default:
1440			s->n_chan = this_board->n_aichan;
1441			s->subdev_flags |= SDF_GROUND;
1442			break;
1443		}
1444		s->maxdata = this_board->ai_maxdata;
1445		s->len_chanlist = MAX_CHANLIST_LEN;
1446		s->range_table = this_board->rangelist_ai;
1447		if (this_board->board_type == boardACL8216) {
1448			s->insn_read = acl8216_ai_insn_read;
1449		} else {
1450			s->insn_read = pcl812_ai_insn_read;
1451		}
1452		devpriv->use_MPC = this_board->haveMPC508;
1453		s->cancel = pcl812_ai_cancel;
1454		if (dev->irq) {
1455			dev->read_subdev = s;
1456			s->subdev_flags |= SDF_CMD_READ;
1457			s->do_cmdtest = pcl812_ai_cmdtest;
1458			s->do_cmd = pcl812_ai_cmd;
1459			s->poll = pcl812_ai_poll;
1460		}
1461		switch (this_board->board_type) {
1462		case boardPCL812PG:
1463			if (it->options[4] == 1)
1464				s->range_table = &range_pcl812pg2_ai;
1465			break;
1466		case boardPCL812:
1467			switch (it->options[4]) {
1468			case 0:
1469				s->range_table = &range_bipolar10;
1470				break;
1471			case 1:
1472				s->range_table = &range_bipolar5;
1473				break;
1474			case 2:
1475				s->range_table = &range_bipolar2_5;
1476				break;
1477			case 3:
1478				s->range_table = &range812_bipolar1_25;
1479				break;
1480			case 4:
1481				s->range_table = &range812_bipolar0_625;
1482				break;
1483			case 5:
1484				s->range_table = &range812_bipolar0_3125;
1485				break;
1486			default:
1487				s->range_table = &range_bipolar10;
1488				break;
1489				printk
1490				    (", incorrect range number %d, changing to 0 (+/-10V)",
1491				     it->options[4]);
1492				break;
1493			}
1494			break;
1495			break;
1496		case boardPCL813B:
1497			if (it->options[1] == 1)
1498				s->range_table = &range_pcl813b2_ai;
1499			break;
1500		case boardISO813:
1501			switch (it->options[1]) {
1502			case 0:
1503				s->range_table = &range_iso813_1_ai;
1504				break;
1505			case 1:
1506				s->range_table = &range_iso813_1_2_ai;
1507				break;
1508			case 2:
1509				s->range_table = &range_iso813_2_ai;
1510				devpriv->range_correction = 1;
1511				break;
1512			case 3:
1513				s->range_table = &range_iso813_2_2_ai;
1514				devpriv->range_correction = 1;
1515				break;
1516			default:
1517				s->range_table = &range_iso813_1_ai;
1518				break;
1519				printk
1520				    (", incorrect range number %d, changing to 0 ",
1521				     it->options[1]);
1522				break;
1523			}
1524			break;
1525		case boardACL8113:
1526			switch (it->options[1]) {
1527			case 0:
1528				s->range_table = &range_acl8113_1_ai;
1529				break;
1530			case 1:
1531				s->range_table = &range_acl8113_1_2_ai;
1532				break;
1533			case 2:
1534				s->range_table = &range_acl8113_2_ai;
1535				devpriv->range_correction = 1;
1536				break;
1537			case 3:
1538				s->range_table = &range_acl8113_2_2_ai;
1539				devpriv->range_correction = 1;
1540				break;
1541			default:
1542				s->range_table = &range_acl8113_1_ai;
1543				break;
1544				printk
1545				    (", incorrect range number %d, changing to 0 ",
1546				     it->options[1]);
1547				break;
1548			}
1549			break;
1550		}
1551		subdev++;
1552	}
1553
1554	/* analog output */
1555	if (this_board->n_aochan > 0) {
1556		s = dev->subdevices + subdev;
1557		s->type = COMEDI_SUBD_AO;
1558		s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1559		s->n_chan = this_board->n_aochan;
1560		s->maxdata = 0xfff;
1561		s->len_chanlist = 1;
1562		s->range_table = this_board->rangelist_ao;
1563		s->insn_read = pcl812_ao_insn_read;
1564		s->insn_write = pcl812_ao_insn_write;
1565		switch (this_board->board_type) {
1566		case boardA821:
1567			if (it->options[3] == 1)
1568				s->range_table = &range_unipolar10;
1569			break;
1570		case boardPCL812:
1571		case boardACL8112:
1572		case boardPCL812PG:
1573		case boardACL8216:
1574			if (it->options[5] == 1)
1575				s->range_table = &range_unipolar10;
1576			if (it->options[5] == 2)
1577				s->range_table = &range_unknown;
1578			break;
1579		}
1580		subdev++;
1581	}
1582
1583	/* digital input */
1584	if (this_board->n_dichan > 0) {
1585		s = dev->subdevices + subdev;
1586		s->type = COMEDI_SUBD_DI;
1587		s->subdev_flags = SDF_READABLE;
1588		s->n_chan = this_board->n_dichan;
1589		s->maxdata = 1;
1590		s->len_chanlist = this_board->n_dichan;
1591		s->range_table = &range_digital;
1592		s->insn_bits = pcl812_di_insn_bits;
1593		subdev++;
1594	}
1595
1596	/* digital output */
1597	if (this_board->n_dochan > 0) {
1598		s = dev->subdevices + subdev;
1599		s->type = COMEDI_SUBD_DO;
1600		s->subdev_flags = SDF_WRITABLE;
1601		s->n_chan = this_board->n_dochan;
1602		s->maxdata = 1;
1603		s->len_chanlist = this_board->n_dochan;
1604		s->range_table = &range_digital;
1605		s->insn_bits = pcl812_do_insn_bits;
1606		subdev++;
1607	}
1608
1609	switch (this_board->board_type) {
1610	case boardACL8216:
1611		devpriv->ai_is16b = 1;
1612	case boardPCL812PG:
1613	case boardPCL812:
1614	case boardACL8112:
1615		devpriv->max_812_ai_mode0_rangewait = 1;
1616		if (it->options[3] > 0)
1617			devpriv->use_ext_trg = 1;	/*  we use external trigger */
1618	case boardA821:
1619		devpriv->max_812_ai_mode0_rangewait = 1;
1620		devpriv->mode_reg_int = (irq << 4) & 0xf0;
1621		break;
1622	case boardPCL813B:
1623	case boardPCL813:
1624	case boardISO813:
1625	case boardACL8113:
1626		devpriv->max_812_ai_mode0_rangewait = 5;	/* maybe there must by greatest timeout */
1627		break;
1628	}
1629
1630	printk("\n");
1631	devpriv->valid = 1;
1632
1633	pcl812_reset(dev);
1634
1635	return 0;
1636}
1637
1638/*
1639==============================================================================
1640 */
1641static int pcl812_detach(struct comedi_device *dev)
1642{
1643
1644#ifdef PCL812_EXTDEBUG
1645	printk("comedi%d: pcl812: remove\n", dev->minor);
1646#endif
1647	free_resources(dev);
1648	return 0;
1649}
1650