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