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