staging: comedi: pcl812: convert private data flags to bit-fields
[linux-2.6-block.git] / drivers / staging / comedi / drivers / pcl818.c
CommitLineData
4da6a1d8
MD
1/*
2 comedi/drivers/pcl818.c
3
4 Author: Michal Dobes <dobes@tesnet.cz>
5
6 hardware driver for Advantech cards:
7 card: PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818, PCL-718
8 driver: pcl818l, pcl818h, pcl818hd, pcl818hg, pcl818, pcl718
9*/
10/*
11Driver: pcl818
12Description: Advantech PCL-818 cards, PCL-718
13Author: Michal Dobes <dobes@tesnet.cz>
14Devices: [Advantech] PCL-818L (pcl818l), PCL-818H (pcl818h),
15 PCL-818HD (pcl818hd), PCL-818HG (pcl818hg), PCL-818 (pcl818),
16 PCL-718 (pcl718)
17Status: works
18
19All cards have 16 SE/8 DIFF ADCs, one or two DACs, 16 DI and 16 DO.
20Differences are only at maximal sample speed, range list and FIFO
21support.
22The driver support AI mode 0, 1, 3 other subdevices (AO, DI, DO) support
23only mode 0. If DMA/FIFO/INT are disabled then AI support only mode 0.
24PCL-818HD and PCL-818HG support 1kword FIFO. Driver support this FIFO
25but this code is untested.
26A word or two about DMA. Driver support DMA operations at two ways:
271) DMA uses two buffers and after one is filled then is generated
28 INT and DMA restart with second buffer. With this mode I'm unable run
29 more that 80Ksamples/secs without data dropouts on K6/233.
302) DMA uses one buffer and run in autoinit mode and the data are
31 from DMA buffer moved on the fly with 2kHz interrupts from RTC.
32 This mode is used if the interrupt 8 is available for allocation.
33 If not, then first DMA mode is used. With this I can run at
34 full speed one card (100ksamples/secs) or two cards with
35 60ksamples/secs each (more is problem on account of ISA limitations).
36 To use this mode you must have compiled kernel with disabled
37 "Enhanced Real Time Clock Support".
38 Maybe you can have problems if you use xntpd or similar.
39 If you've data dropouts with DMA mode 2 then:
40 a) disable IDE DMA
41 b) switch text mode console to fb.
42
43 Options for PCL-818L:
44 [0] - IO Base
45 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
46 [2] - DMA (0=disable, 1, 3)
47 [3] - 0, 10=10MHz clock for 8254
48 1= 1MHz clock for 8254
49 [4] - 0, 5=A/D input -5V.. +5V
50 1, 10=A/D input -10V..+10V
51 [5] - 0, 5=D/A output 0-5V (internal reference -5V)
52 1, 10=D/A output 0-10V (internal reference -10V)
bbc9a991 53 2 =D/A output unknown (external reference)
4da6a1d8
MD
54
55 Options for PCL-818, PCL-818H:
56 [0] - IO Base
57 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
58 [2] - DMA (0=disable, 1, 3)
59 [3] - 0, 10=10MHz clock for 8254
60 1= 1MHz clock for 8254
61 [4] - 0, 5=D/A output 0-5V (internal reference -5V)
62 1, 10=D/A output 0-10V (internal reference -10V)
bbc9a991 63 2 =D/A output unknown (external reference)
4da6a1d8
MD
64
65 Options for PCL-818HD, PCL-818HG:
66 [0] - IO Base
67 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
68 [2] - DMA/FIFO (-1=use FIFO, 0=disable both FIFO and DMA,
69 1=use DMA ch 1, 3=use DMA ch 3)
70 [3] - 0, 10=10MHz clock for 8254
71 1= 1MHz clock for 8254
72 [4] - 0, 5=D/A output 0-5V (internal reference -5V)
73 1, 10=D/A output 0-10V (internal reference -10V)
bbc9a991 74 2 =D/A output unknown (external reference)
4da6a1d8
MD
75
76 Options for PCL-718:
77 [0] - IO Base
78 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
79 [2] - DMA (0=disable, 1, 3)
80 [3] - 0, 10=10MHz clock for 8254
81 1= 1MHz clock for 8254
82 [4] - 0=A/D Range is +/-10V
83 1= +/-5V
84 2= +/-2.5V
85 3= +/-1V
86 4= +/-0.5V
87 5= user defined bipolar
88 6= 0-10V
89 7= 0-5V
90 8= 0-2V
91 9= 0-1V
92 10= user defined unipolar
93 [5] - 0, 5=D/A outputs 0-5V (internal reference -5V)
94 1, 10=D/A outputs 0-10V (internal reference -10V)
bbc9a991 95 2=D/A outputs unknown (external reference)
4da6a1d8
MD
96 [6] - 0, 60=max 60kHz A/D sampling
97 1,100=max 100kHz A/D sampling (PCL-718 with Option 001 installed)
98
99*/
100
ce157f80 101#include <linux/module.h>
5a0e3ad6 102#include <linux/gfp.h>
4da6a1d8 103#include <linux/delay.h>
845d131e 104#include <linux/io.h>
aecfd1ec 105#include <linux/interrupt.h>
4da6a1d8
MD
106#include <asm/dma.h>
107
aecfd1ec
HS
108#include "../comedidev.h"
109
27020ffe 110#include "comedi_fc.h"
4da6a1d8
MD
111#include "8253.h"
112
0109253d 113/* boards constants */
4da6a1d8
MD
114
115#define boardPCL818L 0
116#define boardPCL818H 1
117#define boardPCL818HD 2
118#define boardPCL818HG 3
119#define boardPCL818 4
120#define boardPCL718 5
121
0109253d 122/* W: clear INT request */
4da6a1d8 123#define PCL818_CLRINT 8
0109253d 124/* R: return status byte */
4da6a1d8 125#define PCL818_STATUS 8
0109253d 126/* R: A/D high byte W: A/D range control */
4da6a1d8 127#define PCL818_RANGE 1
0109253d 128/* R: next mux scan channel W: mux scan channel & range control pointer */
4da6a1d8 129#define PCL818_MUX 2
0109253d 130/* R/W: operation control register */
4da6a1d8 131#define PCL818_CONTROL 9
0109253d 132/* W: counter enable */
4da6a1d8
MD
133#define PCL818_CNTENABLE 10
134
0109253d 135/* R: low byte of A/D W: soft A/D trigger */
4da6a1d8 136#define PCL818_AD_LO 0
0109253d 137/* R: high byte of A/D W: A/D range control */
4da6a1d8 138#define PCL818_AD_HI 1
0109253d 139/* W: D/A low&high byte */
4da6a1d8
MD
140#define PCL818_DA_LO 4
141#define PCL818_DA_HI 5
0109253d 142/* R: low&high byte of DI */
4da6a1d8
MD
143#define PCL818_DI_LO 3
144#define PCL818_DI_HI 11
0109253d 145/* W: low&high byte of DO */
4da6a1d8
MD
146#define PCL818_DO_LO 3
147#define PCL818_DO_HI 11
0109253d 148/* W: PCL718 second D/A */
4da6a1d8
MD
149#define PCL718_DA2_LO 6
150#define PCL718_DA2_HI 7
833b458a
HS
151
152#define PCL818_TIMER_BASE 0x0c
4da6a1d8 153
0109253d 154/* W: fifo enable/disable */
4da6a1d8 155#define PCL818_FI_ENABLE 6
0109253d 156/* W: fifo interrupt clear */
4da6a1d8 157#define PCL818_FI_INTCLR 20
0109253d 158/* W: fifo interrupt clear */
4da6a1d8 159#define PCL818_FI_FLUSH 25
0109253d 160/* R: fifo status */
4da6a1d8 161#define PCL818_FI_STATUS 25
0109253d 162/* R: one record from FIFO */
4da6a1d8
MD
163#define PCL818_FI_DATALO 23
164#define PCL818_FI_DATAHI 23
165
0109253d 166/* type of interrupt handler */
4da6a1d8
MD
167#define INT_TYPE_AI1_INT 1
168#define INT_TYPE_AI1_DMA 2
169#define INT_TYPE_AI1_FIFO 3
170#define INT_TYPE_AI3_INT 4
171#define INT_TYPE_AI3_DMA 5
172#define INT_TYPE_AI3_FIFO 6
4da6a1d8 173
4da6a1d8
MD
174#define MAGIC_DMA_WORD 0x5a5a
175
4cdd4eb2
HS
176static const struct comedi_lrange range_pcl818h_ai = {
177 9, {
178 BIP_RANGE(5),
179 BIP_RANGE(2.5),
180 BIP_RANGE(1.25),
181 BIP_RANGE(0.625),
182 UNI_RANGE(10),
183 UNI_RANGE(5),
184 UNI_RANGE(2.5),
185 UNI_RANGE(1.25),
186 BIP_RANGE(10)
187 }
4da6a1d8
MD
188};
189
4cdd4eb2
HS
190static const struct comedi_lrange range_pcl818hg_ai = {
191 10, {
192 BIP_RANGE(5),
193 BIP_RANGE(0.5),
194 BIP_RANGE(0.05),
195 BIP_RANGE(0.005),
196 UNI_RANGE(10),
197 UNI_RANGE(1),
198 UNI_RANGE(0.1),
199 UNI_RANGE(0.01),
200 BIP_RANGE(10),
201 BIP_RANGE(1),
202 BIP_RANGE(0.1),
203 BIP_RANGE(0.01)
204 }
4da6a1d8
MD
205};
206
4cdd4eb2
HS
207static const struct comedi_lrange range_pcl818l_l_ai = {
208 4, {
209 BIP_RANGE(5),
210 BIP_RANGE(2.5),
211 BIP_RANGE(1.25),
212 BIP_RANGE(0.625)
213 }
4da6a1d8
MD
214};
215
4cdd4eb2
HS
216static const struct comedi_lrange range_pcl818l_h_ai = {
217 4, {
218 BIP_RANGE(10),
219 BIP_RANGE(5),
220 BIP_RANGE(2.5),
221 BIP_RANGE(1.25)
222 }
223};
224
225static const struct comedi_lrange range718_bipolar1 = {
226 1, {
227 BIP_RANGE(1)
228 }
4da6a1d8
MD
229};
230
74c7c503 231static const struct comedi_lrange range718_bipolar0_5 = {
4cdd4eb2
HS
232 1, {
233 BIP_RANGE(0.5)
234 }
235};
236
237static const struct comedi_lrange range718_unipolar2 = {
238 1, {
239 UNI_RANGE(2)
240 }
241};
242
243static const struct comedi_lrange range718_unipolar1 = {
244 1, {
245 BIP_RANGE(1)
246 }
247};
4da6a1d8 248
4634b815 249struct pcl818_board {
43f1b6e9 250 const char *name;
43f1b6e9
HS
251 unsigned int ns_min;
252 int n_aochan;
43f1b6e9 253 const struct comedi_lrange *ai_range_type;
4ba4a2d3 254 unsigned int has_dma:1;
d6125588 255 unsigned int has_fifo:1;
9acf56f2 256 unsigned int is_818:1;
4634b815
BP
257};
258
43f1b6e9
HS
259static const struct pcl818_board boardtypes[] = {
260 {
261 .name = "pcl818l",
43f1b6e9
HS
262 .ns_min = 25000,
263 .n_aochan = 1,
43f1b6e9 264 .ai_range_type = &range_pcl818l_l_ai,
4ba4a2d3 265 .has_dma = 1,
43f1b6e9
HS
266 .is_818 = 1,
267 }, {
268 .name = "pcl818h",
43f1b6e9
HS
269 .ns_min = 10000,
270 .n_aochan = 1,
43f1b6e9 271 .ai_range_type = &range_pcl818h_ai,
4ba4a2d3 272 .has_dma = 1,
43f1b6e9
HS
273 .is_818 = 1,
274 }, {
275 .name = "pcl818hd",
43f1b6e9
HS
276 .ns_min = 10000,
277 .n_aochan = 1,
43f1b6e9 278 .ai_range_type = &range_pcl818h_ai,
4ba4a2d3 279 .has_dma = 1,
d6125588 280 .has_fifo = 1,
43f1b6e9
HS
281 .is_818 = 1,
282 }, {
283 .name = "pcl818hg",
43f1b6e9
HS
284 .ns_min = 10000,
285 .n_aochan = 1,
43f1b6e9 286 .ai_range_type = &range_pcl818hg_ai,
4ba4a2d3 287 .has_dma = 1,
d6125588 288 .has_fifo = 1,
43f1b6e9
HS
289 .is_818 = 1,
290 }, {
291 .name = "pcl818",
43f1b6e9
HS
292 .ns_min = 10000,
293 .n_aochan = 2,
43f1b6e9 294 .ai_range_type = &range_pcl818h_ai,
4ba4a2d3 295 .has_dma = 1,
43f1b6e9
HS
296 .is_818 = 1,
297 }, {
298 .name = "pcl718",
43f1b6e9
HS
299 .ns_min = 16000,
300 .n_aochan = 2,
43f1b6e9 301 .ai_range_type = &range_unipolar5,
4ba4a2d3 302 .has_dma = 1,
43f1b6e9
HS
303 }, {
304 .name = "pcm3718",
43f1b6e9 305 .ns_min = 10000,
43f1b6e9 306 .ai_range_type = &range_pcl818h_ai,
4ba4a2d3 307 .has_dma = 1,
43f1b6e9
HS
308 .is_818 = 1,
309 },
310};
311
087ea31b 312struct pcl818_private {
0109253d 313 unsigned int dma; /* used DMA, 0=don't use DMA */
f5cc425a
HS
314 unsigned int dmapages;
315 unsigned int hwdmasize;
0109253d 316 unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
0109253d 317 unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
0109253d
BP
318 int next_dma_buf; /* which DMA buffer will be used next round */
319 long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
320 unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
321 unsigned char neverending_ai; /* if=1, then we do neverending record (you must use cancel()) */
39eaedb6 322 unsigned int ns_min; /* manimal allowed delay between samples (in us) for actual card */
0109253d 323 int i8253_osc_base; /* 1/frequency of on board oscilator in ns */
0109253d
BP
324 int irq_blocked; /* 1=IRQ now uses any subdev */
325 int irq_was_now_closed; /* when IRQ finish, there's stored int818_mode for last interrupt */
326 int ai_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
0109253d
BP
327 int ai_act_scan; /* how many scans we finished */
328 int ai_act_chan; /* actual position in actual scan */
329 unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */
330 unsigned int act_chanlist_len; /* how long is actual MUX list */
331 unsigned int act_chanlist_pos; /* actual position in MUX list */
0109253d 332 unsigned int ai_data_len; /* len of data buffer */
0109253d 333 unsigned char usefifo; /* 1=use fifo */
790c5541 334 unsigned int ao_readback[2];
f4985a79
HS
335 unsigned int divisor1;
336 unsigned int divisor2;
087ea31b
BP
337};
338
0109253d 339static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */
4da6a1d8
MD
340 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
341};
342
4da6a1d8
MD
343/*
344==============================================================================
345*/
0a85b6f0
MT
346static void setup_channel_list(struct comedi_device *dev,
347 struct comedi_subdevice *s,
348 unsigned int *chanlist, unsigned int n_chan,
349 unsigned int seglen);
350static int check_channel_list(struct comedi_device *dev,
351 struct comedi_subdevice *s,
352 unsigned int *chanlist, unsigned int n_chan);
353
f4985a79 354static void pcl818_start_pacer(struct comedi_device *dev, bool load_counters)
833b458a 355{
f4985a79 356 struct pcl818_private *devpriv = dev->private;
833b458a
HS
357 unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE;
358
359 i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
360 i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
361 udelay(1);
362
363 if (load_counters) {
f4985a79
HS
364 i8254_write(timer_base, 0, 2, devpriv->divisor2);
365 i8254_write(timer_base, 0, 1, devpriv->divisor1);
833b458a
HS
366 }
367}
4da6a1d8 368
8fc9f652
HS
369static unsigned int pcl818_ai_get_sample(struct comedi_device *dev,
370 struct comedi_subdevice *s,
371 unsigned int *chan)
372{
373 unsigned int val;
374
375 val = inb(dev->iobase + PCL818_AD_HI) << 8;
376 val |= inb(dev->iobase + PCL818_AD_LO);
377
378 if (chan)
379 *chan = val & 0xf;
380
381 return (val >> 4) & s->maxdata;
382}
383
1d6f4af9
HS
384static int pcl818_ai_eoc(struct comedi_device *dev,
385 struct comedi_subdevice *s,
386 struct comedi_insn *insn,
387 unsigned long context)
388{
389 unsigned int status;
390
391 status = inb(dev->iobase + PCL818_STATUS);
392 if (status & 0x10)
393 return 0;
394 return -EBUSY;
395}
396
0a85b6f0
MT
397static int pcl818_ai_insn_read(struct comedi_device *dev,
398 struct comedi_subdevice *s,
399 struct comedi_insn *insn, unsigned int *data)
4da6a1d8 400{
1d6f4af9 401 int ret;
4da6a1d8 402 int n;
4da6a1d8
MD
403
404 /* software trigger, DMA and INT off */
405 outb(0, dev->iobase + PCL818_CONTROL);
406
407 /* select channel */
408 outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX);
409
410 /* select gain */
411 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE);
412
413 for (n = 0; n < insn->n; n++) {
414
415 /* clear INT (conversion end) flag */
416 outb(0, dev->iobase + PCL818_CLRINT);
417
418 /* start conversion */
419 outb(0, dev->iobase + PCL818_AD_LO);
420
1d6f4af9
HS
421 ret = comedi_timeout(dev, s, insn, pcl818_ai_eoc, 0);
422 if (ret) {
1d6f4af9
HS
423 /* clear INT (conversion end) flag */
424 outb(0, dev->iobase + PCL818_CLRINT);
425 return ret;
4da6a1d8 426 }
4da6a1d8 427
8fc9f652 428 data[n] = pcl818_ai_get_sample(dev, s, NULL);
4da6a1d8
MD
429 }
430
431 return n;
432}
433
434/*
435==============================================================================
436 ANALOG OUTPUT MODE0, 818 cards
437 only one sample per call is supported
438*/
0a85b6f0
MT
439static int pcl818_ao_insn_read(struct comedi_device *dev,
440 struct comedi_subdevice *s,
441 struct comedi_insn *insn, unsigned int *data)
4da6a1d8 442{
9a1a6cf8 443 struct pcl818_private *devpriv = dev->private;
4da6a1d8
MD
444 int n;
445 int chan = CR_CHAN(insn->chanspec);
446
fc950139 447 for (n = 0; n < insn->n; n++)
4da6a1d8 448 data[n] = devpriv->ao_readback[chan];
4da6a1d8
MD
449
450 return n;
451}
452
0a85b6f0
MT
453static int pcl818_ao_insn_write(struct comedi_device *dev,
454 struct comedi_subdevice *s,
455 struct comedi_insn *insn, unsigned int *data)
4da6a1d8 456{
9a1a6cf8 457 struct pcl818_private *devpriv = dev->private;
4da6a1d8
MD
458 int n;
459 int chan = CR_CHAN(insn->chanspec);
460
461 for (n = 0; n < insn->n; n++) {
462 devpriv->ao_readback[chan] = data[n];
463 outb((data[n] & 0x000f) << 4, dev->iobase +
0a85b6f0 464 (chan ? PCL718_DA2_LO : PCL818_DA_LO));
4da6a1d8 465 outb((data[n] & 0x0ff0) >> 4, dev->iobase +
0a85b6f0 466 (chan ? PCL718_DA2_HI : PCL818_DA_HI));
4da6a1d8
MD
467 }
468
469 return n;
470}
471
472/*
473==============================================================================
474 DIGITAL INPUT MODE0, 818 cards
475
476 only one sample per call is supported
477*/
0a85b6f0
MT
478static int pcl818_di_insn_bits(struct comedi_device *dev,
479 struct comedi_subdevice *s,
480 struct comedi_insn *insn, unsigned int *data)
4da6a1d8 481{
4da6a1d8 482 data[1] = inb(dev->iobase + PCL818_DI_LO) |
0a85b6f0 483 (inb(dev->iobase + PCL818_DI_HI) << 8);
4da6a1d8 484
a2714e3e 485 return insn->n;
4da6a1d8
MD
486}
487
0a85b6f0
MT
488static int pcl818_do_insn_bits(struct comedi_device *dev,
489 struct comedi_subdevice *s,
97f4289a
HS
490 struct comedi_insn *insn,
491 unsigned int *data)
4da6a1d8 492{
97f4289a
HS
493 if (comedi_dio_update_state(s, data)) {
494 outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
495 outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
496 }
4da6a1d8
MD
497
498 data[1] = s->state;
499
a2714e3e 500 return insn->n;
4da6a1d8
MD
501}
502
503/*
504==============================================================================
505 analog input interrupt mode 1 & 3, 818 cards
506 one sample per interrupt version
507*/
508static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
509{
71b5f4f1 510 struct comedi_device *dev = d;
9a1a6cf8 511 struct pcl818_private *devpriv = dev->private;
e4bfb085 512 struct comedi_subdevice *s = dev->read_subdev;
41bbe835 513 struct comedi_cmd *cmd = &s->async->cmd;
8fc9f652 514 unsigned int chan;
4da6a1d8
MD
515 int timeout = 50; /* wait max 50us */
516
517 while (timeout--) {
518 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
519 goto conv_finish;
5f74ea14 520 udelay(1);
4da6a1d8
MD
521 }
522 outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */
523 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
6c42119d 524 s->cancel(dev, s);
4da6a1d8
MD
525 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
526 comedi_event(dev, s);
527 return IRQ_HANDLED;
528
0a85b6f0 529conv_finish:
8fc9f652 530 comedi_buf_put(s->async, pcl818_ai_get_sample(dev, s, &chan));
4da6a1d8
MD
531 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
532
8fc9f652 533 if (chan != devpriv->act_chanlist[devpriv->act_chanlist_pos]) {
d65e5b9d
HS
534 dev_dbg(dev->class_dev,
535 "A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
8fc9f652 536 chan,
d65e5b9d 537 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
6c42119d 538 s->cancel(dev, s);
4da6a1d8
MD
539 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
540 comedi_event(dev, s);
541 return IRQ_HANDLED;
542 }
b3559cb1 543 devpriv->act_chanlist_pos++;
fc950139 544 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
b3559cb1 545 devpriv->act_chanlist_pos = 0;
fc950139 546
b3559cb1 547 s->async->cur_chan++;
41bbe835 548 if (s->async->cur_chan >= cmd->chanlist_len) {
b3559cb1 549 s->async->cur_chan = 0;
4da6a1d8
MD
550 devpriv->ai_act_scan--;
551 }
552
553 if (!devpriv->neverending_ai) {
554 if (devpriv->ai_act_scan == 0) { /* all data sampled */
6c42119d 555 s->cancel(dev, s);
4da6a1d8
MD
556 s->async->events |= COMEDI_CB_EOA;
557 }
558 }
559 comedi_event(dev, s);
560 return IRQ_HANDLED;
561}
562
563/*
564==============================================================================
565 analog input dma mode 1 & 3, 818 cards
566*/
567static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
568{
71b5f4f1 569 struct comedi_device *dev = d;
9a1a6cf8 570 struct pcl818_private *devpriv = dev->private;
e4bfb085 571 struct comedi_subdevice *s = dev->read_subdev;
41bbe835 572 struct comedi_cmd *cmd = &s->async->cmd;
4da6a1d8
MD
573 int i, len, bufptr;
574 unsigned long flags;
4bf59ce2 575 unsigned short *ptr;
4da6a1d8
MD
576
577 disable_dma(devpriv->dma);
578 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
0109253d 579 if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */
4da6a1d8
MD
580 set_dma_mode(devpriv->dma, DMA_MODE_READ);
581 flags = claim_dma_lock();
582 set_dma_addr(devpriv->dma,
0a85b6f0 583 devpriv->hwdmaptr[devpriv->next_dma_buf]);
f5cc425a
HS
584 if (devpriv->dma_runs_to_end || devpriv->neverending_ai)
585 set_dma_count(devpriv->dma, devpriv->hwdmasize);
586 else
4da6a1d8 587 set_dma_count(devpriv->dma, devpriv->last_dma_run);
4da6a1d8
MD
588 release_dma_lock(flags);
589 enable_dma(devpriv->dma);
590 }
4da6a1d8
MD
591
592 devpriv->dma_runs_to_end--;
593 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
4bf59ce2 594 ptr = (unsigned short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
4da6a1d8 595
f5cc425a 596 len = devpriv->hwdmasize >> 1;
4da6a1d8
MD
597 bufptr = 0;
598
599 for (i = 0; i < len; i++) {
0109253d 600 if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
d65e5b9d
HS
601 dev_dbg(dev->class_dev,
602 "A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
603 (ptr[bufptr] & 0xf),
604 devpriv->act_chanlist[devpriv->act_chanlist_pos],
605 devpriv->act_chanlist_pos);
6c42119d 606 s->cancel(dev, s);
4da6a1d8
MD
607 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
608 comedi_event(dev, s);
609 return IRQ_HANDLED;
610 }
611
0109253d 612 comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */
4da6a1d8
MD
613
614 devpriv->act_chanlist_pos++;
fc950139 615 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
4da6a1d8 616 devpriv->act_chanlist_pos = 0;
fc950139 617
b3559cb1 618 s->async->cur_chan++;
41bbe835 619 if (s->async->cur_chan >= cmd->chanlist_len) {
b3559cb1
IA
620 s->async->cur_chan = 0;
621 devpriv->ai_act_scan--;
622 }
4da6a1d8
MD
623
624 if (!devpriv->neverending_ai)
625 if (devpriv->ai_act_scan == 0) { /* all data sampled */
6c42119d 626 s->cancel(dev, s);
4da6a1d8
MD
627 s->async->events |= COMEDI_CB_EOA;
628 comedi_event(dev, s);
4da6a1d8
MD
629 return IRQ_HANDLED;
630 }
631 }
632
633 if (len > 0)
634 comedi_event(dev, s);
635 return IRQ_HANDLED;
636}
637
4da6a1d8
MD
638/*
639==============================================================================
640 analog input interrupt mode 1 & 3, 818HD/HG cards
641*/
642static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
643{
71b5f4f1 644 struct comedi_device *dev = d;
9a1a6cf8 645 struct pcl818_private *devpriv = dev->private;
e4bfb085 646 struct comedi_subdevice *s = dev->read_subdev;
41bbe835 647 struct comedi_cmd *cmd = &s->async->cmd;
4bf59ce2
IA
648 int i, len;
649 unsigned char lo;
4da6a1d8 650
0109253d 651 outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */
4da6a1d8
MD
652
653 lo = inb(dev->iobase + PCL818_FI_STATUS);
654
655 if (lo & 4) {
656 comedi_error(dev, "A/D mode1/3 FIFO overflow!");
6c42119d 657 s->cancel(dev, s);
4da6a1d8
MD
658 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
659 comedi_event(dev, s);
660 return IRQ_HANDLED;
661 }
662
663 if (lo & 1) {
664 comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!");
6c42119d 665 s->cancel(dev, s);
4da6a1d8
MD
666 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
667 comedi_event(dev, s);
668 return IRQ_HANDLED;
669 }
670
fc950139 671 if (lo & 2)
4da6a1d8 672 len = 512;
fc950139 673 else
4da6a1d8 674 len = 0;
4da6a1d8
MD
675
676 for (i = 0; i < len; i++) {
677 lo = inb(dev->iobase + PCL818_FI_DATALO);
0109253d 678 if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
d65e5b9d
HS
679 dev_dbg(dev->class_dev,
680 "A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
681 (lo & 0xf),
682 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
6c42119d 683 s->cancel(dev, s);
4da6a1d8
MD
684 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
685 comedi_event(dev, s);
686 return IRQ_HANDLED;
687 }
688
0109253d 689 comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */
4da6a1d8 690
b3559cb1 691 devpriv->act_chanlist_pos++;
fc950139 692 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
b3559cb1 693 devpriv->act_chanlist_pos = 0;
fc950139 694
b3559cb1 695 s->async->cur_chan++;
41bbe835 696 if (s->async->cur_chan >= cmd->chanlist_len) {
b3559cb1 697 s->async->cur_chan = 0;
4da6a1d8
MD
698 devpriv->ai_act_scan--;
699 }
700
701 if (!devpriv->neverending_ai)
702 if (devpriv->ai_act_scan == 0) { /* all data sampled */
6c42119d 703 s->cancel(dev, s);
4da6a1d8
MD
704 s->async->events |= COMEDI_CB_EOA;
705 comedi_event(dev, s);
706 return IRQ_HANDLED;
707 }
708 }
709
710 if (len > 0)
711 comedi_event(dev, s);
712 return IRQ_HANDLED;
713}
714
715/*
716==============================================================================
717 INT procedure
718*/
70265d24 719static irqreturn_t interrupt_pcl818(int irq, void *d)
4da6a1d8 720{
71b5f4f1 721 struct comedi_device *dev = d;
9a1a6cf8 722 struct pcl818_private *devpriv = dev->private;
6c42119d 723 struct comedi_subdevice *s = dev->read_subdev;
4da6a1d8
MD
724
725 if (!dev->attached) {
726 comedi_error(dev, "premature interrupt");
727 return IRQ_HANDLED;
728 }
4da6a1d8 729
e21de1a8
IA
730 if (devpriv->irq_blocked && devpriv->irq_was_now_closed) {
731 if ((devpriv->neverending_ai || (!devpriv->neverending_ai &&
0a85b6f0
MT
732 devpriv->ai_act_scan > 0)) &&
733 (devpriv->ai_mode == INT_TYPE_AI1_DMA ||
734 devpriv->ai_mode == INT_TYPE_AI3_DMA)) {
e21de1a8
IA
735 /* The cleanup from ai_cancel() has been delayed
736 until now because the card doesn't seem to like
737 being reprogrammed while a DMA transfer is in
738 progress.
739 */
e21de1a8
IA
740 devpriv->ai_act_scan = 0;
741 devpriv->neverending_ai = 0;
6c42119d 742 s->cancel(dev, s);
e21de1a8
IA
743 }
744
745 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
746
747 return IRQ_HANDLED;
748 }
749
4da6a1d8
MD
750 switch (devpriv->ai_mode) {
751 case INT_TYPE_AI1_DMA:
752 case INT_TYPE_AI3_DMA:
753 return interrupt_pcl818_ai_mode13_dma(irq, d);
754 case INT_TYPE_AI1_INT:
755 case INT_TYPE_AI3_INT:
756 return interrupt_pcl818_ai_mode13_int(irq, d);
757 case INT_TYPE_AI1_FIFO:
758 case INT_TYPE_AI3_FIFO:
759 return interrupt_pcl818_ai_mode13_fifo(irq, d);
4da6a1d8
MD
760 default:
761 break;
762 }
763
764 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
765
1dcea26a 766 if (!devpriv->irq_blocked || !devpriv->ai_mode) {
4da6a1d8
MD
767 comedi_error(dev, "bad IRQ!");
768 return IRQ_NONE;
769 }
770
bbc9a991 771 comedi_error(dev, "IRQ from unknown source!");
4da6a1d8
MD
772 return IRQ_NONE;
773}
774
775/*
776==============================================================================
777 ANALOG INPUT MODE 1 or 3 DMA , 818 cards
778*/
da91b269 779static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev,
0a85b6f0 780 struct comedi_subdevice *s)
4da6a1d8 781{
9a1a6cf8 782 struct pcl818_private *devpriv = dev->private;
c2e519dd 783 struct comedi_cmd *cmd = &s->async->cmd;
4da6a1d8
MD
784 unsigned int flags;
785 unsigned int bytes;
786
0109253d 787 disable_dma(devpriv->dma); /* disable dma */
f5cc425a 788 bytes = devpriv->hwdmasize;
4da6a1d8 789 if (!devpriv->neverending_ai) {
f5cc425a
HS
790 bytes = cmd->chanlist_len * cmd->stop_arg * sizeof(short);
791 devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize;
792 devpriv->last_dma_run = bytes % devpriv->hwdmasize;
4da6a1d8
MD
793 devpriv->dma_runs_to_end--;
794 if (devpriv->dma_runs_to_end >= 0)
f5cc425a 795 bytes = devpriv->hwdmasize;
4da6a1d8
MD
796 }
797
798 devpriv->next_dma_buf = 0;
799 set_dma_mode(devpriv->dma, DMA_MODE_READ);
800 flags = claim_dma_lock();
801 clear_dma_ff(devpriv->dma);
802 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
803 set_dma_count(devpriv->dma, bytes);
804 release_dma_lock(flags);
805 enable_dma(devpriv->dma);
806
807 if (mode == 1) {
808 devpriv->ai_mode = INT_TYPE_AI1_DMA;
809 outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */
810 } else {
811 devpriv->ai_mode = INT_TYPE_AI3_DMA;
812 outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */
4b5c08e8 813 }
4da6a1d8
MD
814}
815
4da6a1d8
MD
816/*
817==============================================================================
818 ANALOG INPUT MODE 1 or 3, 818 cards
819*/
da91b269 820static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
0a85b6f0 821 struct comedi_subdevice *s)
4da6a1d8 822{
9a1a6cf8 823 struct pcl818_private *devpriv = dev->private;
ea6d0d4c 824 struct comedi_cmd *cmd = &s->async->cmd;
4da6a1d8
MD
825 unsigned int seglen;
826
4da6a1d8
MD
827 if (devpriv->irq_blocked)
828 return -EBUSY;
829
f4985a79 830 pcl818_start_pacer(dev, false);
4da6a1d8 831
1784f305 832 seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len);
4da6a1d8
MD
833 if (seglen < 1)
834 return -EINVAL;
1784f305 835 setup_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len, seglen);
4da6a1d8 836
5f74ea14 837 udelay(1);
4da6a1d8 838
c2e519dd 839 devpriv->ai_act_scan = cmd->stop_arg;
4da6a1d8
MD
840 devpriv->ai_act_chan = 0;
841 devpriv->irq_blocked = 1;
842 devpriv->irq_was_now_closed = 0;
4da6a1d8
MD
843 devpriv->act_chanlist_pos = 0;
844 devpriv->dma_runs_to_end = 0;
845
4da6a1d8
MD
846 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
847
848 switch (devpriv->dma) {
0109253d 849 case 1: /* DMA */
4da6a1d8 850 case 3:
aecfd1ec 851 pcl818_ai_mode13dma_int(mode, dev, s);
4da6a1d8 852 break;
a71f18d2
IA
853 case 0:
854 if (!devpriv->usefifo) {
855 /* IRQ */
a71f18d2
IA
856 if (mode == 1) {
857 devpriv->ai_mode = INT_TYPE_AI1_INT;
858 /* Pacer+IRQ */
0a85b6f0
MT
859 outb(0x83 | (dev->irq << 4),
860 dev->iobase + PCL818_CONTROL);
a71f18d2
IA
861 } else {
862 devpriv->ai_mode = INT_TYPE_AI3_INT;
863 /* Ext trig+IRQ */
0a85b6f0
MT
864 outb(0x82 | (dev->irq << 4),
865 dev->iobase + PCL818_CONTROL);
a71f18d2 866 }
4da6a1d8 867 } else {
a71f18d2
IA
868 /* FIFO */
869 /* enable FIFO */
870 outb(1, dev->iobase + PCL818_FI_ENABLE);
871 if (mode == 1) {
872 devpriv->ai_mode = INT_TYPE_AI1_FIFO;
873 /* Pacer */
874 outb(0x03, dev->iobase + PCL818_CONTROL);
875 } else {
876 devpriv->ai_mode = INT_TYPE_AI3_FIFO;
877 outb(0x02, dev->iobase + PCL818_CONTROL);
878 }
879 }
4da6a1d8
MD
880 }
881
f4985a79 882 pcl818_start_pacer(dev, mode == 1);
4da6a1d8 883
4da6a1d8
MD
884 return 0;
885}
886
4da6a1d8
MD
887/*
888==============================================================================
889 Check if channel list from user is builded correctly
890 If it's ok, then program scan/gain logic
891*/
0a85b6f0
MT
892static int check_channel_list(struct comedi_device *dev,
893 struct comedi_subdevice *s,
894 unsigned int *chanlist, unsigned int n_chan)
4da6a1d8
MD
895{
896 unsigned int chansegment[16];
897 unsigned int i, nowmustbechan, seglen, segpos;
898
899 /* correct channel and range number check itself comedi/range.c */
900 if (n_chan < 1) {
901 comedi_error(dev, "range/channel list is empty!");
902 return 0;
903 }
904
905 if (n_chan > 1) {
25985edc 906 /* first channel is every time ok */
4da6a1d8 907 chansegment[0] = chanlist[0];
0109253d 908 /* build part of chanlist */
4da6a1d8 909 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
0109253d
BP
910 /* we detect loop, this must by finish */
911
4da6a1d8
MD
912 if (chanlist[0] == chanlist[i])
913 break;
914 nowmustbechan =
0a85b6f0 915 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
25985edc 916 if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */
84f03cf1
HS
917 dev_dbg(dev->class_dev,
918 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
919 i, CR_CHAN(chanlist[i]), nowmustbechan,
920 CR_CHAN(chanlist[0]));
4da6a1d8
MD
921 return 0;
922 }
0109253d 923 /* well, this is next correct channel in list */
4da6a1d8
MD
924 chansegment[i] = chanlist[i];
925 }
926
0109253d 927 /* check whole chanlist */
4da6a1d8 928 for (i = 0, segpos = 0; i < n_chan; i++) {
4da6a1d8 929 if (chanlist[i] != chansegment[i % seglen]) {
84f03cf1
HS
930 dev_dbg(dev->class_dev,
931 "bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
932 i, CR_CHAN(chansegment[i]),
933 CR_RANGE(chansegment[i]),
934 CR_AREF(chansegment[i]),
935 CR_CHAN(chanlist[i % seglen]),
936 CR_RANGE(chanlist[i % seglen]),
937 CR_AREF(chansegment[i % seglen]));
0109253d 938 return 0; /* chan/gain list is strange */
4da6a1d8
MD
939 }
940 }
941 } else {
942 seglen = 1;
943 }
4da6a1d8
MD
944 return seglen;
945}
946
0a85b6f0
MT
947static void setup_channel_list(struct comedi_device *dev,
948 struct comedi_subdevice *s,
949 unsigned int *chanlist, unsigned int n_chan,
950 unsigned int seglen)
4da6a1d8 951{
9a1a6cf8 952 struct pcl818_private *devpriv = dev->private;
4da6a1d8
MD
953 int i;
954
955 devpriv->act_chanlist_len = seglen;
956 devpriv->act_chanlist_pos = 0;
957
0109253d 958 for (i = 0; i < seglen; i++) { /* store range list to card */
4da6a1d8
MD
959 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
960 outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */
961 outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */
962 }
963
5f74ea14 964 udelay(1);
4da6a1d8
MD
965
966 /* select channel interval to scan */
967 outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen -
0a85b6f0
MT
968 1] << 4),
969 dev->iobase + PCL818_MUX);
4da6a1d8
MD
970}
971
972/*
973==============================================================================
974 Check if board is switched to SE (1) or DIFF(0) mode
975*/
976static int check_single_ended(unsigned int port)
977{
fc950139 978 if (inb(port + PCL818_STATUS) & 0x20)
4da6a1d8 979 return 1;
fc950139 980 return 0;
4da6a1d8
MD
981}
982
983/*
984==============================================================================
985*/
da91b269 986static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 987 struct comedi_cmd *cmd)
4da6a1d8 988{
dd8a4b47 989 const struct pcl818_board *board = comedi_board(dev);
9a1a6cf8 990 struct pcl818_private *devpriv = dev->private;
4da6a1d8 991 int err = 0;
f4985a79 992 int tmp;
4da6a1d8 993
27020ffe 994 /* Step 1 : check if triggers are trivially valid */
4da6a1d8 995
27020ffe
HS
996 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
997 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
998 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
999 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1000 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
4da6a1d8 1001
fc950139 1002 if (err)
4da6a1d8 1003 return 1;
4da6a1d8 1004
27020ffe 1005 /* Step 2a : make sure trigger sources are unique */
4da6a1d8 1006
27020ffe
HS
1007 err |= cfc_check_trigger_is_unique(cmd->convert_src);
1008 err |= cfc_check_trigger_is_unique(cmd->stop_src);
4da6a1d8 1009
27020ffe 1010 /* Step 2b : and mutually compatible */
4da6a1d8 1011
fc950139 1012 if (err)
4da6a1d8 1013 return 2;
4da6a1d8 1014
8efdc1bf 1015 /* Step 3: check if arguments are trivially valid */
4da6a1d8 1016
8efdc1bf
HS
1017 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
1018 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
4da6a1d8 1019
8efdc1bf
HS
1020 if (cmd->convert_src == TRIG_TIMER)
1021 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
1022 board->ns_min);
1023 else /* TRIG_EXT */
1024 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
4da6a1d8 1025
8efdc1bf 1026 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
4da6a1d8 1027
8efdc1bf
HS
1028 if (cmd->stop_src == TRIG_COUNT)
1029 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
1030 else /* TRIG_NONE */
1031 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
4da6a1d8 1032
fc950139 1033 if (err)
4da6a1d8 1034 return 3;
4da6a1d8
MD
1035
1036 /* step 4: fix up any arguments */
1037
1038 if (cmd->convert_src == TRIG_TIMER) {
1039 tmp = cmd->convert_arg;
cb9cfd7e 1040 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base,
f4985a79
HS
1041 &devpriv->divisor1,
1042 &devpriv->divisor2,
cb9cfd7e 1043 &cmd->convert_arg, cmd->flags);
dd8a4b47
HS
1044 if (cmd->convert_arg < board->ns_min)
1045 cmd->convert_arg = board->ns_min;
4da6a1d8
MD
1046 if (tmp != cmd->convert_arg)
1047 err++;
1048 }
1049
fc950139 1050 if (err)
4da6a1d8 1051 return 4;
4da6a1d8
MD
1052
1053 /* step 5: complain about special chanlist considerations */
1054
1055 if (cmd->chanlist) {
1056 if (!check_channel_list(dev, s, cmd->chanlist,
0a85b6f0 1057 cmd->chanlist_len))
0109253d 1058 return 5; /* incorrect channels list */
4da6a1d8
MD
1059 }
1060
1061 return 0;
1062}
1063
1064/*
1065==============================================================================
1066*/
da91b269 1067static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
4da6a1d8 1068{
9a1a6cf8 1069 struct pcl818_private *devpriv = dev->private;
ea6d0d4c 1070 struct comedi_cmd *cmd = &s->async->cmd;
4da6a1d8
MD
1071 int retval;
1072
4da6a1d8 1073 devpriv->ai_data_len = s->async->prealloc_bufsz;
4da6a1d8 1074
fc950139 1075 if (cmd->stop_src == TRIG_COUNT)
c2e519dd 1076 devpriv->neverending_ai = 0;
fc950139 1077 else
c2e519dd 1078 devpriv->neverending_ai = 1;
4da6a1d8 1079
0109253d
BP
1080 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */
1081 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */
4da6a1d8 1082 retval = pcl818_ai_cmd_mode(1, dev, s);
4da6a1d8
MD
1083 return retval;
1084 }
0109253d 1085 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
4da6a1d8
MD
1086 return pcl818_ai_cmd_mode(3, dev, s);
1087 }
1088 }
1089
1090 return -1;
1091}
1092
1093/*
1094==============================================================================
1095 cancel any mode 1-4 AI
1096*/
0a85b6f0
MT
1097static int pcl818_ai_cancel(struct comedi_device *dev,
1098 struct comedi_subdevice *s)
4da6a1d8 1099{
9a1a6cf8
HS
1100 struct pcl818_private *devpriv = dev->private;
1101
4da6a1d8 1102 if (devpriv->irq_blocked > 0) {
e21de1a8 1103 devpriv->irq_was_now_closed = 1;
4da6a1d8 1104
e21de1a8 1105 switch (devpriv->ai_mode) {
4da6a1d8
MD
1106 case INT_TYPE_AI1_DMA:
1107 case INT_TYPE_AI3_DMA:
e21de1a8 1108 if (devpriv->neverending_ai ||
0a85b6f0
MT
1109 (!devpriv->neverending_ai &&
1110 devpriv->ai_act_scan > 0)) {
4da6a1d8
MD
1111 /* wait for running dma transfer to end, do cleanup in interrupt */
1112 goto end;
1113 }
1114 disable_dma(devpriv->dma);
1115 case INT_TYPE_AI1_INT:
1116 case INT_TYPE_AI3_INT:
1117 case INT_TYPE_AI1_FIFO:
1118 case INT_TYPE_AI3_FIFO:
4da6a1d8 1119 outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */
5f74ea14 1120 udelay(1);
f4985a79 1121 pcl818_start_pacer(dev, false);
4da6a1d8 1122 outb(0, dev->iobase + PCL818_AD_LO);
8fc9f652 1123 pcl818_ai_get_sample(dev, s, NULL);
4da6a1d8
MD
1124 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
1125 outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */
0109253d 1126 if (devpriv->usefifo) { /* FIFO shutdown */
4da6a1d8
MD
1127 outb(0, dev->iobase + PCL818_FI_INTCLR);
1128 outb(0, dev->iobase + PCL818_FI_FLUSH);
1129 outb(0, dev->iobase + PCL818_FI_ENABLE);
1130 }
1131 devpriv->irq_blocked = 0;
4da6a1d8 1132 devpriv->neverending_ai = 0;
e21de1a8
IA
1133 devpriv->ai_mode = 0;
1134 devpriv->irq_was_now_closed = 0;
4da6a1d8
MD
1135 break;
1136 }
1137 }
1138
0a85b6f0 1139end:
4da6a1d8
MD
1140 return 0;
1141}
1142
1143/*
1144==============================================================================
1145 chech for PCL818
1146*/
1147static int pcl818_check(unsigned long iobase)
1148{
1149 outb(0x00, iobase + PCL818_MUX);
5f74ea14 1150 udelay(1);
4da6a1d8 1151 if (inb(iobase + PCL818_MUX) != 0x00)
0109253d 1152 return 1; /* there isn't card */
4da6a1d8 1153 outb(0x55, iobase + PCL818_MUX);
5f74ea14 1154 udelay(1);
4da6a1d8 1155 if (inb(iobase + PCL818_MUX) != 0x55)
0109253d 1156 return 1; /* there isn't card */
4da6a1d8 1157 outb(0x00, iobase + PCL818_MUX);
5f74ea14 1158 udelay(1);
4da6a1d8 1159 outb(0x18, iobase + PCL818_CONTROL);
5f74ea14 1160 udelay(1);
4da6a1d8 1161 if (inb(iobase + PCL818_CONTROL) != 0x18)
0109253d
BP
1162 return 1; /* there isn't card */
1163 return 0; /* ok, card exist */
4da6a1d8
MD
1164}
1165
1166/*
1167==============================================================================
1168 reset whole PCL-818 cards
1169*/
da91b269 1170static void pcl818_reset(struct comedi_device *dev)
4da6a1d8 1171{
dd8a4b47 1172 const struct pcl818_board *board = comedi_board(dev);
9a1a6cf8 1173 struct pcl818_private *devpriv = dev->private;
833b458a 1174 unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE;
dd8a4b47 1175
0109253d 1176 if (devpriv->usefifo) { /* FIFO shutdown */
4da6a1d8
MD
1177 outb(0, dev->iobase + PCL818_FI_INTCLR);
1178 outb(0, dev->iobase + PCL818_FI_FLUSH);
1179 outb(0, dev->iobase + PCL818_FI_ENABLE);
1180 }
0109253d 1181 outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */
4da6a1d8 1182 outb(0, dev->iobase + PCL818_DA_HI);
5f74ea14 1183 udelay(1);
0109253d 1184 outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */
4da6a1d8 1185 outb(0, dev->iobase + PCL818_DO_LO);
5f74ea14 1186 udelay(1);
4da6a1d8
MD
1187 outb(0, dev->iobase + PCL818_CONTROL);
1188 outb(0, dev->iobase + PCL818_CNTENABLE);
1189 outb(0, dev->iobase + PCL818_MUX);
1190 outb(0, dev->iobase + PCL818_CLRINT);
833b458a
HS
1191
1192 /* Stop pacer */
1193 i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY);
1194 i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY);
1195 i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY);
1196
dd8a4b47 1197 if (board->is_818) {
4da6a1d8
MD
1198 outb(0, dev->iobase + PCL818_RANGE);
1199 } else {
1200 outb(0, dev->iobase + PCL718_DA2_LO);
1201 outb(0, dev->iobase + PCL718_DA2_HI);
1202 }
1203}
1204
f39b8ccf
HS
1205static void pcl818_set_ai_range_table(struct comedi_device *dev,
1206 struct comedi_subdevice *s,
1207 struct comedi_devconfig *it)
1208{
1209 const struct pcl818_board *board = comedi_board(dev);
1210
1211 /* default to the range table from the boardinfo */
1212 s->range_table = board->ai_range_type;
1213
1214 /* now check the user config option based on the boardtype */
1215 if (board->is_818) {
1216 if (it->options[4] == 1 || it->options[4] == 10) {
1217 /* secondary range list jumper selectable */
1218 s->range_table = &range_pcl818l_h_ai;
1219 }
1220 } else {
1221 switch (it->options[4]) {
1222 case 0:
1223 s->range_table = &range_bipolar10;
1224 break;
1225 case 1:
1226 s->range_table = &range_bipolar5;
1227 break;
1228 case 2:
1229 s->range_table = &range_bipolar2_5;
1230 break;
1231 case 3:
1232 s->range_table = &range718_bipolar1;
1233 break;
1234 case 4:
1235 s->range_table = &range718_bipolar0_5;
1236 break;
1237 case 6:
1238 s->range_table = &range_unipolar10;
1239 break;
1240 case 7:
1241 s->range_table = &range_unipolar5;
1242 break;
1243 case 8:
1244 s->range_table = &range718_unipolar2;
1245 break;
1246 case 9:
1247 s->range_table = &range718_unipolar1;
1248 break;
1249 default:
1250 s->range_table = &range_unknown;
1251 break;
1252 }
1253 }
1254}
1255
da91b269 1256static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
4da6a1d8 1257{
dd8a4b47 1258 const struct pcl818_board *board = comedi_board(dev);
9a1a6cf8 1259 struct pcl818_private *devpriv;
34c43922 1260 struct comedi_subdevice *s;
f5cc425a
HS
1261 int ret;
1262 int i;
4da6a1d8 1263
0bdab509 1264 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
c34fa261
HS
1265 if (!devpriv)
1266 return -ENOMEM;
4da6a1d8 1267
d6125588
HS
1268 /* should we use the FIFO? */
1269 if (board->has_fifo && it->options[2] == -1)
4da6a1d8 1270 devpriv->usefifo = 1;
d6125588
HS
1271
1272 ret = comedi_request_region(dev, it->options[0],
1273 devpriv->usefifo ? 0x20 : 0x10);
d6c5ec04
HS
1274 if (ret)
1275 return ret;
4da6a1d8 1276
d6c5ec04 1277 if (pcl818_check(dev->iobase)) {
26ba666c 1278 comedi_error(dev, "I can't detect board. FAIL!\n");
4da6a1d8
MD
1279 return -EIO;
1280 }
1281
8356d4b4
HS
1282 /* we can use IRQ 2-7 for async command support */
1283 if (it->options[1] >= 2 && it->options[1] <= 7) {
e30b22a9
HS
1284 ret = request_irq(it->options[1], interrupt_pcl818, 0,
1285 dev->board_name, dev);
35a8735d 1286 if (ret == 0)
e30b22a9 1287 dev->irq = it->options[1];
4da6a1d8
MD
1288 }
1289
4da6a1d8
MD
1290 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
1291 devpriv->ai_mode = 0; /* mode of irq */
1292
4ba4a2d3
HS
1293 /* we need an IRQ to do DMA on channel 3 or 1 */
1294 if (dev->irq && board->has_dma &&
1295 (it->options[2] == 3 || it->options[2] == 1)) {
1296 ret = request_dma(it->options[2], dev->board_name);
1297 if (ret) {
d65e5b9d 1298 dev_err(dev->class_dev,
4ba4a2d3
HS
1299 "unable to request DMA channel %d\n",
1300 it->options[2]);
1301 return -EBUSY;
4da6a1d8 1302 }
4ba4a2d3
HS
1303 devpriv->dma = it->options[2];
1304
f5cc425a
HS
1305 devpriv->dmapages = 2; /* we need 16KB */
1306 devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
1307
1308 for (i = 0; i < 2; i++) {
1309 unsigned long dmabuf;
1310
1311 dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
1312 if (!dmabuf)
1313 return -ENOMEM;
1314
1315 devpriv->dmabuf[i] = dmabuf;
1316 devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
1317 }
4da6a1d8
MD
1318 }
1319
2f0b9d08 1320 ret = comedi_alloc_subdevices(dev, 4);
8b6c5694 1321 if (ret)
4da6a1d8
MD
1322 return ret;
1323
9fab6123 1324 s = &dev->subdevices[0];
9c06c4e3
HS
1325 s->type = COMEDI_SUBD_AI;
1326 s->subdev_flags = SDF_READABLE;
1327 if (check_single_ended(dev->iobase)) {
1328 s->n_chan = 16;
1329 s->subdev_flags |= SDF_COMMON | SDF_GROUND;
4da6a1d8 1330 } else {
9c06c4e3
HS
1331 s->n_chan = 8;
1332 s->subdev_flags |= SDF_DIFF;
1333 }
bca1b594 1334 s->maxdata = 0x0fff;
9c06c4e3
HS
1335
1336 pcl818_set_ai_range_table(dev, s, it);
1337
1338 s->insn_read = pcl818_ai_insn_read;
1339 if (dev->irq) {
1340 dev->read_subdev = s;
1341 s->subdev_flags |= SDF_CMD_READ;
1342 s->len_chanlist = s->n_chan;
1343 s->do_cmdtest = ai_cmdtest;
1344 s->do_cmd = ai_cmd;
1345 s->cancel = pcl818_ai_cancel;
4da6a1d8
MD
1346 }
1347
9fab6123 1348 s = &dev->subdevices[1];
dd8a4b47 1349 if (!board->n_aochan) {
4da6a1d8
MD
1350 s->type = COMEDI_SUBD_UNUSED;
1351 } else {
1352 s->type = COMEDI_SUBD_AO;
1353 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
dd8a4b47 1354 s->n_chan = board->n_aochan;
2bfe3eb7 1355 s->maxdata = 0x0fff;
ba93331e 1356 s->range_table = &range_unipolar5;
4da6a1d8
MD
1357 s->insn_read = pcl818_ao_insn_read;
1358 s->insn_write = pcl818_ao_insn_write;
dd8a4b47 1359 if (board->is_818) {
4da6a1d8
MD
1360 if ((it->options[4] == 1) || (it->options[4] == 10))
1361 s->range_table = &range_unipolar10;
1362 if (it->options[4] == 2)
1363 s->range_table = &range_unknown;
1364 } else {
1365 if ((it->options[5] == 1) || (it->options[5] == 10))
1366 s->range_table = &range_unipolar10;
1367 if (it->options[5] == 2)
1368 s->range_table = &range_unknown;
1369 }
1370 }
1371
03d98e6c 1372 /* Digital Input subdevice */
9fab6123 1373 s = &dev->subdevices[2];
03d98e6c
HS
1374 s->type = COMEDI_SUBD_DI;
1375 s->subdev_flags = SDF_READABLE;
1376 s->n_chan = 16;
1377 s->maxdata = 1;
1378 s->range_table = &range_digital;
1379 s->insn_bits = pcl818_di_insn_bits;
1380
1381 /* Digital Output subdevice */
9fab6123 1382 s = &dev->subdevices[3];
03d98e6c
HS
1383 s->type = COMEDI_SUBD_DO;
1384 s->subdev_flags = SDF_WRITABLE;
1385 s->n_chan = 16;
1386 s->maxdata = 1;
1387 s->range_table = &range_digital;
1388 s->insn_bits = pcl818_do_insn_bits;
4da6a1d8
MD
1389
1390 /* select 1/10MHz oscilator */
fc950139 1391 if ((it->options[3] == 0) || (it->options[3] == 10))
cb9cfd7e 1392 devpriv->i8253_osc_base = I8254_OSC_BASE_10MHZ;
fc950139 1393 else
cb9cfd7e 1394 devpriv->i8253_osc_base = I8254_OSC_BASE_1MHZ;
4da6a1d8
MD
1395
1396 /* max sampling speed */
dd8a4b47 1397 devpriv->ns_min = board->ns_min;
4da6a1d8 1398
dd8a4b47 1399 if (!board->is_818) {
4da6a1d8
MD
1400 if ((it->options[6] == 1) || (it->options[6] == 100))
1401 devpriv->ns_min = 10000; /* extended PCL718 to 100kHz DAC */
1402 }
1403
1404 pcl818_reset(dev);
1405
4da6a1d8
MD
1406 return 0;
1407}
1408
484ecc95 1409static void pcl818_detach(struct comedi_device *dev)
4da6a1d8 1410{
9a1a6cf8
HS
1411 struct pcl818_private *devpriv = dev->private;
1412
1413 if (devpriv) {
89dac49e 1414 pcl818_ai_cancel(dev, dev->read_subdev);
484ecc95
HS
1415 pcl818_reset(dev);
1416 if (devpriv->dma)
1417 free_dma(devpriv->dma);
1418 if (devpriv->dmabuf[0])
f5cc425a 1419 free_pages(devpriv->dmabuf[0], devpriv->dmapages);
484ecc95 1420 if (devpriv->dmabuf[1])
f5cc425a 1421 free_pages(devpriv->dmabuf[1], devpriv->dmapages);
484ecc95 1422 }
a32c6d00 1423 comedi_legacy_detach(dev);
4da6a1d8 1424}
90f703d3 1425
294f930d 1426static struct comedi_driver pcl818_driver = {
f6aafa10
HS
1427 .driver_name = "pcl818",
1428 .module = THIS_MODULE,
1429 .attach = pcl818_attach,
1430 .detach = pcl818_detach,
1431 .board_name = &boardtypes[0].name,
1432 .num_names = ARRAY_SIZE(boardtypes),
1433 .offset = sizeof(struct pcl818_board),
1434};
294f930d 1435module_comedi_driver(pcl818_driver);
f6aafa10 1436
90f703d3
AT
1437MODULE_AUTHOR("Comedi http://www.comedi.org");
1438MODULE_DESCRIPTION("Comedi low-level driver");
1439MODULE_LICENSE("GPL");