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