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