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