Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
[GitHub/mt8127/android_kernel_alcatel_ttab.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
4da6a1d8 101#include <linux/ioport.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
c34fa261
HS
1230 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
1231 if (!devpriv)
1232 return -ENOMEM;
1233 dev->private = devpriv;
4da6a1d8 1234
dd8a4b47
HS
1235 devpriv->io_range = board->io_range;
1236 if ((board->fifo) && (it->options[2] == -1)) {
1237 /* we've board with FIFO and we want to use FIFO */
4da6a1d8
MD
1238 devpriv->io_range = PCLx1xFIFO_RANGE;
1239 devpriv->usefifo = 1;
1240 }
d6c5ec04
HS
1241 ret = comedi_request_region(dev, it->options[0], devpriv->io_range);
1242 if (ret)
1243 return ret;
4da6a1d8 1244
d6c5ec04 1245 if (pcl818_check(dev->iobase)) {
26ba666c 1246 comedi_error(dev, "I can't detect board. FAIL!\n");
4da6a1d8
MD
1247 return -EIO;
1248 }
1249
4da6a1d8
MD
1250 /* grab our IRQ */
1251 irq = 0;
dd8a4b47 1252 if (board->IRQbits != 0) { /* board support IRQ */
4da6a1d8
MD
1253 irq = it->options[1];
1254 if (irq) { /* we want to use IRQ */
dd8a4b47 1255 if (((1 << irq) & board->IRQbits) == 0) {
5f74ea14 1256 printk
0a85b6f0
MT
1257 (", IRQ %u is out of allowed range, DISABLING IT",
1258 irq);
4da6a1d8
MD
1259 irq = 0; /* Bad IRQ */
1260 } else {
b27cc413
HS
1261 if (request_irq(irq, interrupt_pcl818, 0,
1262 dev->board_name, dev)) {
5f74ea14 1263 printk
0a85b6f0
MT
1264 (", unable to allocate IRQ %u, DISABLING IT",
1265 irq);
4da6a1d8
MD
1266 irq = 0; /* Can't use IRQ */
1267 } else {
26ba666c 1268 printk(KERN_DEBUG "irq=%u", irq);
4da6a1d8
MD
1269 }
1270 }
1271 }
1272 }
1273
1274 dev->irq = irq;
fc950139
RM
1275 if (irq)
1276 devpriv->irq_free = 1; /* 1=we have allocated irq */
1277 else
4da6a1d8 1278 devpriv->irq_free = 0;
fc950139 1279
4da6a1d8
MD
1280 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
1281 devpriv->ai_mode = 0; /* mode of irq */
1282
4da6a1d8
MD
1283 /* grab our DMA */
1284 dma = 0;
1285 devpriv->dma = dma;
aecfd1ec 1286 if (!devpriv->irq_free)
4da6a1d8 1287 goto no_dma; /* if we haven't IRQ, we can't use DMA */
dd8a4b47 1288 if (board->DMAbits != 0) { /* board support DMA */
4da6a1d8
MD
1289 dma = it->options[2];
1290 if (dma < 1)
1291 goto no_dma; /* DMA disabled */
dd8a4b47 1292 if (((1 << dma) & board->DMAbits) == 0) {
408f6bcd 1293 printk(KERN_ERR "DMA is out of allowed range, FAIL!\n");
4da6a1d8
MD
1294 return -EINVAL; /* Bad DMA */
1295 }
b27cc413 1296 ret = request_dma(dma, dev->board_name);
408f6bcd 1297 if (ret)
4da6a1d8 1298 return -EBUSY; /* DMA isn't free */
4da6a1d8 1299 devpriv->dma = dma;
4da6a1d8
MD
1300 pages = 2; /* we need 16KB */
1301 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
408f6bcd 1302 if (!devpriv->dmabuf[0])
4da6a1d8
MD
1303 /* maybe experiment with try_to_free_pages() will help .... */
1304 return -EBUSY; /* no buffer :-( */
4da6a1d8
MD
1305 devpriv->dmapages[0] = pages;
1306 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1307 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
5f74ea14 1308 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
aecfd1ec
HS
1309 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1310 if (!devpriv->dmabuf[1])
1311 return -EBUSY;
1312 devpriv->dmapages[1] = pages;
1313 devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
1314 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
4da6a1d8
MD
1315 }
1316
0a85b6f0 1317no_dma:
4da6a1d8 1318
2f0b9d08 1319 ret = comedi_alloc_subdevices(dev, 4);
8b6c5694 1320 if (ret)
4da6a1d8
MD
1321 return ret;
1322
9fab6123 1323 s = &dev->subdevices[0];
dd8a4b47 1324 if (!board->n_aichan_se) {
4da6a1d8
MD
1325 s->type = COMEDI_SUBD_UNUSED;
1326 } else {
1327 s->type = COMEDI_SUBD_AI;
1328 devpriv->sub_ai = s;
1329 s->subdev_flags = SDF_READABLE;
1330 if (check_single_ended(dev->iobase)) {
dd8a4b47 1331 s->n_chan = board->n_aichan_se;
4da6a1d8
MD
1332 s->subdev_flags |= SDF_COMMON | SDF_GROUND;
1333 printk(", %dchans S.E. DAC", s->n_chan);
1334 } else {
dd8a4b47 1335 s->n_chan = board->n_aichan_diff;
4da6a1d8
MD
1336 s->subdev_flags |= SDF_DIFF;
1337 printk(", %dchans DIFF DAC", s->n_chan);
1338 }
dd8a4b47 1339 s->maxdata = board->ai_maxdata;
4da6a1d8 1340 s->len_chanlist = s->n_chan;
dd8a4b47 1341 s->range_table = board->ai_range_type;
4da6a1d8
MD
1342 s->cancel = pcl818_ai_cancel;
1343 s->insn_read = pcl818_ai_insn_read;
aecfd1ec 1344 if (irq) {
4da6a1d8
MD
1345 dev->read_subdev = s;
1346 s->subdev_flags |= SDF_CMD_READ;
1347 s->do_cmdtest = ai_cmdtest;
1348 s->do_cmd = ai_cmd;
1349 }
dd8a4b47 1350 if (board->is_818) {
4da6a1d8 1351 if ((it->options[4] == 1) || (it->options[4] == 10))
0109253d 1352 s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */
4da6a1d8
MD
1353 } else {
1354 switch (it->options[4]) {
1355 case 0:
1356 s->range_table = &range_bipolar10;
1357 break;
1358 case 1:
1359 s->range_table = &range_bipolar5;
1360 break;
1361 case 2:
1362 s->range_table = &range_bipolar2_5;
1363 break;
1364 case 3:
1365 s->range_table = &range718_bipolar1;
1366 break;
1367 case 4:
1368 s->range_table = &range718_bipolar0_5;
1369 break;
1370 case 6:
1371 s->range_table = &range_unipolar10;
1372 break;
1373 case 7:
1374 s->range_table = &range_unipolar5;
1375 break;
1376 case 8:
1377 s->range_table = &range718_unipolar2;
1378 break;
1379 case 9:
1380 s->range_table = &range718_unipolar1;
1381 break;
1382 default:
1383 s->range_table = &range_unknown;
1384 break;
1385 }
1386 }
1387 }
1388
9fab6123 1389 s = &dev->subdevices[1];
dd8a4b47 1390 if (!board->n_aochan) {
4da6a1d8
MD
1391 s->type = COMEDI_SUBD_UNUSED;
1392 } else {
1393 s->type = COMEDI_SUBD_AO;
1394 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
dd8a4b47
HS
1395 s->n_chan = board->n_aochan;
1396 s->maxdata = board->ao_maxdata;
1397 s->len_chanlist = board->n_aochan;
1398 s->range_table = board->ao_range_type;
4da6a1d8
MD
1399 s->insn_read = pcl818_ao_insn_read;
1400 s->insn_write = pcl818_ao_insn_write;
dd8a4b47 1401 if (board->is_818) {
4da6a1d8
MD
1402 if ((it->options[4] == 1) || (it->options[4] == 10))
1403 s->range_table = &range_unipolar10;
1404 if (it->options[4] == 2)
1405 s->range_table = &range_unknown;
1406 } else {
1407 if ((it->options[5] == 1) || (it->options[5] == 10))
1408 s->range_table = &range_unipolar10;
1409 if (it->options[5] == 2)
1410 s->range_table = &range_unknown;
1411 }
1412 }
1413
9fab6123 1414 s = &dev->subdevices[2];
dd8a4b47 1415 if (!board->n_dichan) {
4da6a1d8
MD
1416 s->type = COMEDI_SUBD_UNUSED;
1417 } else {
1418 s->type = COMEDI_SUBD_DI;
1419 s->subdev_flags = SDF_READABLE;
dd8a4b47 1420 s->n_chan = board->n_dichan;
4da6a1d8 1421 s->maxdata = 1;
dd8a4b47 1422 s->len_chanlist = board->n_dichan;
4da6a1d8
MD
1423 s->range_table = &range_digital;
1424 s->insn_bits = pcl818_di_insn_bits;
1425 }
1426
9fab6123 1427 s = &dev->subdevices[3];
dd8a4b47 1428 if (!board->n_dochan) {
4da6a1d8
MD
1429 s->type = COMEDI_SUBD_UNUSED;
1430 } else {
1431 s->type = COMEDI_SUBD_DO;
1432 s->subdev_flags = SDF_WRITABLE;
dd8a4b47 1433 s->n_chan = board->n_dochan;
4da6a1d8 1434 s->maxdata = 1;
dd8a4b47 1435 s->len_chanlist = board->n_dochan;
4da6a1d8
MD
1436 s->range_table = &range_digital;
1437 s->insn_bits = pcl818_do_insn_bits;
1438 }
1439
1440 /* select 1/10MHz oscilator */
fc950139 1441 if ((it->options[3] == 0) || (it->options[3] == 10))
4da6a1d8 1442 devpriv->i8253_osc_base = 100;
fc950139 1443 else
4da6a1d8 1444 devpriv->i8253_osc_base = 1000;
4da6a1d8
MD
1445
1446 /* max sampling speed */
dd8a4b47 1447 devpriv->ns_min = board->ns_min;
4da6a1d8 1448
dd8a4b47 1449 if (!board->is_818) {
4da6a1d8
MD
1450 if ((it->options[6] == 1) || (it->options[6] == 100))
1451 devpriv->ns_min = 10000; /* extended PCL718 to 100kHz DAC */
1452 }
1453
1454 pcl818_reset(dev);
1455
5f74ea14 1456 printk("\n");
4da6a1d8
MD
1457
1458 return 0;
1459}
1460
484ecc95 1461static void pcl818_detach(struct comedi_device *dev)
4da6a1d8 1462{
9a1a6cf8
HS
1463 struct pcl818_private *devpriv = dev->private;
1464
1465 if (devpriv) {
484ecc95
HS
1466 pcl818_ai_cancel(dev, devpriv->sub_ai);
1467 pcl818_reset(dev);
1468 if (devpriv->dma)
1469 free_dma(devpriv->dma);
1470 if (devpriv->dmabuf[0])
1471 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1472 if (devpriv->dmabuf[1])
1473 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
484ecc95 1474 }
a32c6d00 1475 comedi_legacy_detach(dev);
4da6a1d8 1476}
90f703d3 1477
f6aafa10
HS
1478static const struct pcl818_board boardtypes[] = {
1479 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
1480 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1481 0x0a, 0xfff, 0xfff, 0, 1},
1482 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
1483 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1484 0x0a, 0xfff, 0xfff, 0, 1},
1485 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
1486 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1487 0x0a, 0xfff, 0xfff, 1, 1},
1488 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
1489 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1490 0x0a, 0xfff, 0xfff, 1, 1},
1491 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
1492 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1493 0x0a, 0xfff, 0xfff, 0, 1},
1494 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
1495 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1496 0x0a, 0xfff, 0xfff, 0, 0},
1497 /* pcm3718 */
1498 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
1499 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1500 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
1501};
1502
294f930d 1503static struct comedi_driver pcl818_driver = {
f6aafa10
HS
1504 .driver_name = "pcl818",
1505 .module = THIS_MODULE,
1506 .attach = pcl818_attach,
1507 .detach = pcl818_detach,
1508 .board_name = &boardtypes[0].name,
1509 .num_names = ARRAY_SIZE(boardtypes),
1510 .offset = sizeof(struct pcl818_board),
1511};
294f930d 1512module_comedi_driver(pcl818_driver);
f6aafa10 1513
90f703d3
AT
1514MODULE_AUTHOR("Comedi http://www.comedi.org");
1515MODULE_DESCRIPTION("Comedi low-level driver");
1516MODULE_LICENSE("GPL");