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