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