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