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