staging "sep" Fix typos found while reading.
[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
101#include "../comedidev.h"
102
103#include <linux/ioport.h>
104#include <linux/mc146818rtc.h>
5a0e3ad6 105#include <linux/gfp.h>
4da6a1d8 106#include <linux/delay.h>
845d131e 107#include <linux/io.h>
4da6a1d8
MD
108#include <asm/dma.h>
109
110#include "8253.h"
111
0109253d 112/* #define PCL818_MODE13_AO 1 */
4da6a1d8 113
0109253d 114/* boards constants */
4da6a1d8
MD
115
116#define boardPCL818L 0
117#define boardPCL818H 1
118#define boardPCL818HD 2
119#define boardPCL818HG 3
120#define boardPCL818 4
121#define boardPCL718 5
122
0109253d 123/* IO space len */
4da6a1d8 124#define PCLx1x_RANGE 16
0109253d 125/* IO space len if we use FIFO */
4da6a1d8
MD
126#define PCLx1xFIFO_RANGE 32
127
0109253d 128/* W: clear INT request */
4da6a1d8 129#define PCL818_CLRINT 8
0109253d 130/* R: return status byte */
4da6a1d8 131#define PCL818_STATUS 8
0109253d 132/* R: A/D high byte W: A/D range control */
4da6a1d8 133#define PCL818_RANGE 1
0109253d 134/* R: next mux scan channel W: mux scan channel & range control pointer */
4da6a1d8 135#define PCL818_MUX 2
0109253d 136/* R/W: operation control register */
4da6a1d8 137#define PCL818_CONTROL 9
0109253d 138/* W: counter enable */
4da6a1d8
MD
139#define PCL818_CNTENABLE 10
140
0109253d 141/* R: low byte of A/D W: soft A/D trigger */
4da6a1d8 142#define PCL818_AD_LO 0
0109253d 143/* R: high byte of A/D W: A/D range control */
4da6a1d8 144#define PCL818_AD_HI 1
0109253d 145/* W: D/A low&high byte */
4da6a1d8
MD
146#define PCL818_DA_LO 4
147#define PCL818_DA_HI 5
0109253d 148/* R: low&high byte of DI */
4da6a1d8
MD
149#define PCL818_DI_LO 3
150#define PCL818_DI_HI 11
0109253d 151/* W: low&high byte of DO */
4da6a1d8
MD
152#define PCL818_DO_LO 3
153#define PCL818_DO_HI 11
0109253d 154/* W: PCL718 second D/A */
4da6a1d8
MD
155#define PCL718_DA2_LO 6
156#define PCL718_DA2_HI 7
0109253d 157/* counters */
4da6a1d8
MD
158#define PCL818_CTR0 12
159#define PCL818_CTR1 13
160#define PCL818_CTR2 14
0109253d 161/* W: counter control */
4da6a1d8
MD
162#define PCL818_CTRCTL 15
163
0109253d 164/* W: fifo enable/disable */
4da6a1d8 165#define PCL818_FI_ENABLE 6
0109253d 166/* W: fifo interrupt clear */
4da6a1d8 167#define PCL818_FI_INTCLR 20
0109253d 168/* W: fifo interrupt clear */
4da6a1d8 169#define PCL818_FI_FLUSH 25
0109253d 170/* R: fifo status */
4da6a1d8 171#define PCL818_FI_STATUS 25
0109253d 172/* R: one record from FIFO */
4da6a1d8
MD
173#define PCL818_FI_DATALO 23
174#define PCL818_FI_DATAHI 23
175
0109253d 176/* type of interrupt handler */
4da6a1d8
MD
177#define INT_TYPE_AI1_INT 1
178#define INT_TYPE_AI1_DMA 2
179#define INT_TYPE_AI1_FIFO 3
180#define INT_TYPE_AI3_INT 4
181#define INT_TYPE_AI3_DMA 5
182#define INT_TYPE_AI3_FIFO 6
183#ifdef PCL818_MODE13_AO
184#define INT_TYPE_AO1_INT 7
185#define INT_TYPE_AO3_INT 8
186#endif
187
188#ifdef unused
0109253d 189/* RTC stuff... */
4da6a1d8
MD
190#define INT_TYPE_AI1_DMA_RTC 9
191#define INT_TYPE_AI3_DMA_RTC 10
192
193#define RTC_IRQ 8
194#define RTC_IO_EXTENT 0x10
195#endif
196
197#define MAGIC_DMA_WORD 0x5a5a
198
9ced1de6 199static const struct comedi_lrange range_pcl818h_ai = { 9, {
0a85b6f0
MT
200 BIP_RANGE(5),
201 BIP_RANGE(2.5),
202 BIP_RANGE(1.25),
203 BIP_RANGE(0.625),
204 UNI_RANGE(10),
205 UNI_RANGE(5),
206 UNI_RANGE(2.5),
207 UNI_RANGE(1.25),
208 BIP_RANGE(10),
209 }
4da6a1d8
MD
210};
211
9ced1de6 212static const struct comedi_lrange range_pcl818hg_ai = { 10, {
0a85b6f0
MT
213 BIP_RANGE(5),
214 BIP_RANGE(0.5),
215 BIP_RANGE(0.05),
216 BIP_RANGE(0.005),
217 UNI_RANGE(10),
218 UNI_RANGE(1),
219 UNI_RANGE(0.1),
220 UNI_RANGE(0.01),
221 BIP_RANGE(10),
222 BIP_RANGE(1),
223 BIP_RANGE(0.1),
224 BIP_RANGE(0.01),
225 }
4da6a1d8
MD
226};
227
9ced1de6 228static const struct comedi_lrange range_pcl818l_l_ai = { 4, {
0a85b6f0
MT
229 BIP_RANGE(5),
230 BIP_RANGE(2.5),
231 BIP_RANGE(1.25),
232 BIP_RANGE(0.625),
233 }
4da6a1d8
MD
234};
235
9ced1de6 236static const struct comedi_lrange range_pcl818l_h_ai = { 4, {
0a85b6f0
MT
237 BIP_RANGE(10),
238 BIP_RANGE(5),
239 BIP_RANGE(2.5),
240 BIP_RANGE(1.25),
241 }
4da6a1d8
MD
242};
243
9ced1de6 244static const struct comedi_lrange range718_bipolar1 = { 1, {BIP_RANGE(1),} };
0a85b6f0
MT
245static const struct comedi_lrange range718_bipolar0_5 =
246 { 1, {BIP_RANGE(0.5),} };
9ced1de6
BP
247static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} };
248static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} };
4da6a1d8 249
4da6a1d8 250#ifdef unused
2b873134
RM
251static int RTC_lock; /* RTC lock */
252static int RTC_timer_lock; /* RTC int lock */
4da6a1d8
MD
253#endif
254
4634b815
BP
255struct pcl818_board {
256
0109253d
BP
257 const char *name; /* driver name */
258 int n_ranges; /* len of range list */
259 int n_aichan_se; /* num of A/D chans in single ended mode */
260 int n_aichan_diff; /* num of A/D chans in diferencial mode */
39eaedb6 261 unsigned int ns_min; /* minimal allowed delay between samples (in ns) */
0109253d
BP
262 int n_aochan; /* num of D/A chans */
263 int n_dichan; /* num of DI chans */
264 int n_dochan; /* num of DO chans */
265 const struct comedi_lrange *ai_range_type; /* default A/D rangelist */
266 const struct comedi_lrange *ao_range_type; /* default D/A rangelist */
267 unsigned int io_range; /* len of IO space */
268 unsigned int IRQbits; /* allowed interrupts */
269 unsigned int DMAbits; /* allowed DMA chans */
270 int ai_maxdata; /* maxdata for A/D */
271 int ao_maxdata; /* maxdata for D/A */
272 unsigned char fifo; /* 1=board has FIFO */
4da6a1d8 273 int is_818;
4634b815
BP
274};
275
087ea31b
BP
276struct pcl818_private {
277
0109253d
BP
278 unsigned int dma; /* used DMA, 0=don't use DMA */
279 int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */
4da6a1d8
MD
280 unsigned int io_range;
281#ifdef unused
0109253d 282 unsigned long rtc_iobase; /* RTC port region */
4da6a1d8
MD
283 unsigned int rtc_iosize;
284 unsigned int rtc_irq;
0109253d
BP
285 struct timer_list rtc_irq_timer; /* timer for RTC sanity check */
286 unsigned long rtc_freq; /* RTC int freq */
287 int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */
4da6a1d8 288#endif
0109253d
BP
289 unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
290 unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */
291 unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
292 unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */
293 unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */
294 unsigned int last_top_dma; /* DMA pointer in last RTC int */
295 int next_dma_buf; /* which DMA buffer will be used next round */
296 long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
297 unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
298 unsigned char neverending_ai; /* if=1, then we do neverending record (you must use cancel()) */
39eaedb6 299 unsigned int ns_min; /* manimal allowed delay between samples (in us) for actual card */
0109253d
BP
300 int i8253_osc_base; /* 1/frequency of on board oscilator in ns */
301 int irq_free; /* 1=have allocated IRQ */
302 int irq_blocked; /* 1=IRQ now uses any subdev */
303 int irq_was_now_closed; /* when IRQ finish, there's stored int818_mode for last interrupt */
304 int ai_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
305 struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */
306 int ai_act_scan; /* how many scans we finished */
307 int ai_act_chan; /* actual position in actual scan */
308 unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */
309 unsigned int act_chanlist_len; /* how long is actual MUX list */
310 unsigned int act_chanlist_pos; /* actual position in MUX list */
311 unsigned int ai_scans; /* len of scanlist */
312 unsigned int ai_n_chan; /* how many channels is measured */
313 unsigned int *ai_chanlist; /* actaul chanlist */
314 unsigned int ai_flags; /* flaglist */
315 unsigned int ai_data_len; /* len of data buffer */
0a85b6f0 316 short *ai_data; /* data buffer */
0109253d 317 unsigned int ai_timer1; /* timers */
4da6a1d8 318 unsigned int ai_timer2;
0109253d
BP
319 struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */
320 unsigned char usefifo; /* 1=use fifo */
790c5541 321 unsigned int ao_readback[2];
087ea31b
BP
322};
323
0109253d 324static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */
4da6a1d8
MD
325 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
326};
327
087ea31b 328#define devpriv ((struct pcl818_private *)dev->private)
4da6a1d8
MD
329
330/*
331==============================================================================
332*/
0a85b6f0
MT
333static void setup_channel_list(struct comedi_device *dev,
334 struct comedi_subdevice *s,
335 unsigned int *chanlist, unsigned int n_chan,
336 unsigned int seglen);
337static int check_channel_list(struct comedi_device *dev,
338 struct comedi_subdevice *s,
339 unsigned int *chanlist, unsigned int n_chan);
340
341static int pcl818_ai_cancel(struct comedi_device *dev,
342 struct comedi_subdevice *s);
343static void start_pacer(struct comedi_device *dev, int mode,
344 unsigned int divisor1, unsigned int divisor2);
4da6a1d8
MD
345
346#ifdef unused
347static int set_rtc_irq_bit(unsigned char bit);
348static void rtc_dropped_irq(unsigned long data);
349static int rtc_setfreq_irq(int freq);
350#endif
351
352/*
353==============================================================================
354 ANALOG INPUT MODE0, 818 cards, slow version
355*/
0a85b6f0
MT
356static int pcl818_ai_insn_read(struct comedi_device *dev,
357 struct comedi_subdevice *s,
358 struct comedi_insn *insn, unsigned int *data)
4da6a1d8
MD
359{
360 int n;
361 int timeout;
362
363 /* software trigger, DMA and INT off */
364 outb(0, dev->iobase + PCL818_CONTROL);
365
366 /* select channel */
367 outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX);
368
369 /* select gain */
370 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE);
371
372 for (n = 0; n < insn->n; n++) {
373
374 /* clear INT (conversion end) flag */
375 outb(0, dev->iobase + PCL818_CLRINT);
376
377 /* start conversion */
378 outb(0, dev->iobase + PCL818_AD_LO);
379
380 timeout = 100;
381 while (timeout--) {
382 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
383 goto conv_finish;
5f74ea14 384 udelay(1);
4da6a1d8
MD
385 }
386 comedi_error(dev, "A/D insn timeout");
387 /* clear INT (conversion end) flag */
388 outb(0, dev->iobase + PCL818_CLRINT);
389 return -EIO;
390
0a85b6f0 391conv_finish:
4da6a1d8 392 data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |
0a85b6f0 393 (inb(dev->iobase + PCL818_AD_LO) >> 4));
4da6a1d8
MD
394 }
395
396 return n;
397}
398
399/*
400==============================================================================
401 ANALOG OUTPUT MODE0, 818 cards
402 only one sample per call is supported
403*/
0a85b6f0
MT
404static int pcl818_ao_insn_read(struct comedi_device *dev,
405 struct comedi_subdevice *s,
406 struct comedi_insn *insn, unsigned int *data)
4da6a1d8
MD
407{
408 int n;
409 int chan = CR_CHAN(insn->chanspec);
410
fc950139 411 for (n = 0; n < insn->n; n++)
4da6a1d8 412 data[n] = devpriv->ao_readback[chan];
4da6a1d8
MD
413
414 return n;
415}
416
0a85b6f0
MT
417static int pcl818_ao_insn_write(struct comedi_device *dev,
418 struct comedi_subdevice *s,
419 struct comedi_insn *insn, unsigned int *data)
4da6a1d8
MD
420{
421 int n;
422 int chan = CR_CHAN(insn->chanspec);
423
424 for (n = 0; n < insn->n; n++) {
425 devpriv->ao_readback[chan] = data[n];
426 outb((data[n] & 0x000f) << 4, dev->iobase +
0a85b6f0 427 (chan ? PCL718_DA2_LO : PCL818_DA_LO));
4da6a1d8 428 outb((data[n] & 0x0ff0) >> 4, dev->iobase +
0a85b6f0 429 (chan ? PCL718_DA2_HI : PCL818_DA_HI));
4da6a1d8
MD
430 }
431
432 return n;
433}
434
435/*
436==============================================================================
437 DIGITAL INPUT MODE0, 818 cards
438
439 only one sample per call is supported
440*/
0a85b6f0
MT
441static int pcl818_di_insn_bits(struct comedi_device *dev,
442 struct comedi_subdevice *s,
443 struct comedi_insn *insn, unsigned int *data)
4da6a1d8
MD
444{
445 if (insn->n != 2)
446 return -EINVAL;
447
448 data[1] = inb(dev->iobase + PCL818_DI_LO) |
0a85b6f0 449 (inb(dev->iobase + PCL818_DI_HI) << 8);
4da6a1d8
MD
450
451 return 2;
452}
453
454/*
455==============================================================================
456 DIGITAL OUTPUT MODE0, 818 cards
457
458 only one sample per call is supported
459*/
0a85b6f0
MT
460static int pcl818_do_insn_bits(struct comedi_device *dev,
461 struct comedi_subdevice *s,
462 struct comedi_insn *insn, unsigned int *data)
4da6a1d8
MD
463{
464 if (insn->n != 2)
465 return -EINVAL;
466
467 s->state &= ~data[0];
468 s->state |= (data[0] & data[1]);
469
470 outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
471 outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
472
473 data[1] = s->state;
474
475 return 2;
476}
477
478/*
479==============================================================================
480 analog input interrupt mode 1 & 3, 818 cards
481 one sample per interrupt version
482*/
483static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
484{
71b5f4f1 485 struct comedi_device *dev = d;
34c43922 486 struct comedi_subdevice *s = dev->subdevices + 0;
4da6a1d8
MD
487 int low;
488 int timeout = 50; /* wait max 50us */
489
490 while (timeout--) {
491 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
492 goto conv_finish;
5f74ea14 493 udelay(1);
4da6a1d8
MD
494 }
495 outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */
496 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
497 pcl818_ai_cancel(dev, s);
498 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
499 comedi_event(dev, s);
500 return IRQ_HANDLED;
501
0a85b6f0 502conv_finish:
4da6a1d8 503 low = inb(dev->iobase + PCL818_AD_LO);
0109253d 504 comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */
4da6a1d8
MD
505 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
506
0109253d 507 if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
5f74ea14 508 printk
0a85b6f0
MT
509 ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
510 (low & 0xf),
511 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
4da6a1d8
MD
512 pcl818_ai_cancel(dev, s);
513 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
514 comedi_event(dev, s);
515 return IRQ_HANDLED;
516 }
b3559cb1 517 devpriv->act_chanlist_pos++;
fc950139 518 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
b3559cb1 519 devpriv->act_chanlist_pos = 0;
fc950139 520
b3559cb1
IA
521 s->async->cur_chan++;
522 if (s->async->cur_chan >= devpriv->ai_n_chan) {
5f74ea14 523 /* printk("E"); */
b3559cb1 524 s->async->cur_chan = 0;
4da6a1d8
MD
525 devpriv->ai_act_scan--;
526 }
527
528 if (!devpriv->neverending_ai) {
529 if (devpriv->ai_act_scan == 0) { /* all data sampled */
530 pcl818_ai_cancel(dev, s);
531 s->async->events |= COMEDI_CB_EOA;
532 }
533 }
534 comedi_event(dev, s);
535 return IRQ_HANDLED;
536}
537
538/*
539==============================================================================
540 analog input dma mode 1 & 3, 818 cards
541*/
542static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
543{
71b5f4f1 544 struct comedi_device *dev = d;
34c43922 545 struct comedi_subdevice *s = dev->subdevices + 0;
4da6a1d8
MD
546 int i, len, bufptr;
547 unsigned long flags;
790c5541 548 short *ptr;
4da6a1d8
MD
549
550 disable_dma(devpriv->dma);
551 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
0109253d 552 if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */
4da6a1d8
MD
553 set_dma_mode(devpriv->dma, DMA_MODE_READ);
554 flags = claim_dma_lock();
555 set_dma_addr(devpriv->dma,
0a85b6f0 556 devpriv->hwdmaptr[devpriv->next_dma_buf]);
4da6a1d8
MD
557 if (devpriv->dma_runs_to_end || devpriv->neverending_ai) {
558 set_dma_count(devpriv->dma,
0a85b6f0
MT
559 devpriv->hwdmasize[devpriv->
560 next_dma_buf]);
4da6a1d8
MD
561 } else {
562 set_dma_count(devpriv->dma, devpriv->last_dma_run);
563 }
564 release_dma_lock(flags);
565 enable_dma(devpriv->dma);
566 }
5f74ea14 567 printk("comedi: A/D mode1/3 IRQ \n");
4da6a1d8
MD
568
569 devpriv->dma_runs_to_end--;
570 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
0a85b6f0 571 ptr = (short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
4da6a1d8
MD
572
573 len = devpriv->hwdmasize[0] >> 1;
574 bufptr = 0;
575
576 for (i = 0; i < len; i++) {
0109253d 577 if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
5f74ea14 578 printk
0a85b6f0
MT
579 ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
580 (ptr[bufptr] & 0xf),
581 devpriv->act_chanlist[devpriv->act_chanlist_pos],
582 devpriv->act_chanlist_pos);
4da6a1d8
MD
583 pcl818_ai_cancel(dev, s);
584 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
585 comedi_event(dev, s);
586 return IRQ_HANDLED;
587 }
588
0109253d 589 comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */
4da6a1d8
MD
590
591 devpriv->act_chanlist_pos++;
fc950139 592 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
4da6a1d8 593 devpriv->act_chanlist_pos = 0;
fc950139 594
b3559cb1
IA
595 s->async->cur_chan++;
596 if (s->async->cur_chan >= devpriv->ai_n_chan) {
597 s->async->cur_chan = 0;
598 devpriv->ai_act_scan--;
599 }
4da6a1d8
MD
600
601 if (!devpriv->neverending_ai)
602 if (devpriv->ai_act_scan == 0) { /* all data sampled */
603 pcl818_ai_cancel(dev, s);
604 s->async->events |= COMEDI_CB_EOA;
605 comedi_event(dev, s);
0109253d 606 /* printk("done int ai13 dma\n"); */
4da6a1d8
MD
607 return IRQ_HANDLED;
608 }
609 }
610
611 if (len > 0)
612 comedi_event(dev, s);
613 return IRQ_HANDLED;
614}
615
616#ifdef unused
617/*
618==============================================================================
619 analog input dma mode 1 & 3 over RTC, 818 cards
620*/
621static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d)
622{
71b5f4f1 623 struct comedi_device *dev = d;
34c43922 624 struct comedi_subdevice *s = dev->subdevices + 0;
4da6a1d8
MD
625 unsigned long tmp;
626 unsigned int top1, top2, i, bufptr;
627 long ofs_dats;
0a85b6f0 628 short *dmabuf = (short *)devpriv->dmabuf[0];
4da6a1d8 629
0109253d 630 /* outb(2,0x378); */
4da6a1d8
MD
631 switch (devpriv->ai_mode) {
632 case INT_TYPE_AI1_DMA_RTC:
633 case INT_TYPE_AI3_DMA_RTC:
634 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
635 mod_timer(&devpriv->rtc_irq_timer,
0a85b6f0 636 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
4da6a1d8
MD
637
638 for (i = 0; i < 10; i++) {
639 top1 = get_dma_residue(devpriv->dma);
640 top2 = get_dma_residue(devpriv->dma);
641 if (top1 == top2)
642 break;
643 }
644
645 if (top1 != top2)
646 return IRQ_HANDLED;
0109253d 647 top1 = devpriv->hwdmasize[0] - top1; /* where is now DMA in buffer */
4da6a1d8 648 top1 >>= 1;
0109253d 649 ofs_dats = top1 - devpriv->last_top_dma; /* new samples from last call */
4da6a1d8
MD
650 if (ofs_dats < 0)
651 ofs_dats = (devpriv->dmasamplsize) + ofs_dats;
652 if (!ofs_dats)
0109253d
BP
653 return IRQ_HANDLED; /* exit=no new samples from last call */
654 /* obsluz data */
4da6a1d8
MD
655 i = devpriv->last_top_dma - 1;
656 i &= (devpriv->dmasamplsize - 1);
657
0109253d 658 if (dmabuf[i] != MAGIC_DMA_WORD) { /* DMA overflow! */
4da6a1d8 659 comedi_error(dev, "A/D mode1/3 DMA buffer overflow!");
5f74ea14 660 /* printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize); */
4da6a1d8
MD
661 pcl818_ai_cancel(dev, s);
662 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
663 comedi_event(dev, s);
664 return IRQ_HANDLED;
665 }
5f74ea14 666 /* printk("r %ld ",ofs_dats); */
4da6a1d8
MD
667
668 bufptr = devpriv->last_top_dma;
669
670 for (i = 0; i < ofs_dats; i++) {
0109253d 671 if ((dmabuf[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
5f74ea14 672 printk
0a85b6f0
MT
673 ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",
674 (dmabuf[bufptr] & 0xf),
675 devpriv->
676 act_chanlist[devpriv->act_chanlist_pos]);
4da6a1d8
MD
677 pcl818_ai_cancel(dev, s);
678 s->async->events |=
0a85b6f0 679 COMEDI_CB_EOA | COMEDI_CB_ERROR;
4da6a1d8
MD
680 comedi_event(dev, s);
681 return IRQ_HANDLED;
682 }
683
0109253d 684 comedi_buf_put(s->async, dmabuf[bufptr++] >> 4); /* get one sample */
4da6a1d8
MD
685 bufptr &= (devpriv->dmasamplsize - 1);
686
b3559cb1
IA
687 devpriv->act_chanlist_pos++;
688 if (devpriv->act_chanlist_pos >=
689 devpriv->act_chanlist_len) {
690 devpriv->act_chanlist_pos = 0;
691 }
692 s->async->cur_chan++;
693 if (s->async->cur_chan >= devpriv->ai_n_chan) {
694 s->async->cur_chan = 0;
4da6a1d8
MD
695 devpriv->ai_act_scan--;
696 }
697
698 if (!devpriv->neverending_ai)
699 if (devpriv->ai_act_scan == 0) { /* all data sampled */
700 pcl818_ai_cancel(dev, s);
701 s->async->events |= COMEDI_CB_EOA;
702 comedi_event(dev, s);
0109253d 703 /* printk("done int ai13 dma\n"); */
4da6a1d8
MD
704 return IRQ_HANDLED;
705 }
706 }
707
708 devpriv->last_top_dma = bufptr;
709 bufptr--;
710 bufptr &= (devpriv->dmasamplsize - 1);
711 dmabuf[bufptr] = MAGIC_DMA_WORD;
712 comedi_event(dev, s);
0109253d 713 /* outb(0,0x378); */
4da6a1d8
MD
714 return IRQ_HANDLED;
715 }
716
0109253d 717 /* outb(0,0x378); */
4da6a1d8
MD
718 return IRQ_HANDLED;
719}
720#endif
721
722/*
723==============================================================================
724 analog input interrupt mode 1 & 3, 818HD/HG cards
725*/
726static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
727{
71b5f4f1 728 struct comedi_device *dev = d;
34c43922 729 struct comedi_subdevice *s = dev->subdevices + 0;
4da6a1d8
MD
730 int i, len, lo;
731
0109253d 732 outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */
4da6a1d8
MD
733
734 lo = inb(dev->iobase + PCL818_FI_STATUS);
735
736 if (lo & 4) {
737 comedi_error(dev, "A/D mode1/3 FIFO overflow!");
738 pcl818_ai_cancel(dev, s);
739 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
740 comedi_event(dev, s);
741 return IRQ_HANDLED;
742 }
743
744 if (lo & 1) {
745 comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!");
746 pcl818_ai_cancel(dev, s);
747 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
748 comedi_event(dev, s);
749 return IRQ_HANDLED;
750 }
751
fc950139 752 if (lo & 2)
4da6a1d8 753 len = 512;
fc950139 754 else
4da6a1d8 755 len = 0;
4da6a1d8
MD
756
757 for (i = 0; i < len; i++) {
758 lo = inb(dev->iobase + PCL818_FI_DATALO);
0109253d 759 if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
5f74ea14 760 printk
0a85b6f0
MT
761 ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
762 (lo & 0xf),
763 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
4da6a1d8
MD
764 pcl818_ai_cancel(dev, s);
765 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
766 comedi_event(dev, s);
767 return IRQ_HANDLED;
768 }
769
0109253d 770 comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */
4da6a1d8 771
b3559cb1 772 devpriv->act_chanlist_pos++;
fc950139 773 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
b3559cb1 774 devpriv->act_chanlist_pos = 0;
fc950139 775
b3559cb1
IA
776 s->async->cur_chan++;
777 if (s->async->cur_chan >= devpriv->ai_n_chan) {
778 s->async->cur_chan = 0;
4da6a1d8
MD
779 devpriv->ai_act_scan--;
780 }
781
782 if (!devpriv->neverending_ai)
783 if (devpriv->ai_act_scan == 0) { /* all data sampled */
784 pcl818_ai_cancel(dev, s);
785 s->async->events |= COMEDI_CB_EOA;
786 comedi_event(dev, s);
787 return IRQ_HANDLED;
788 }
789 }
790
791 if (len > 0)
792 comedi_event(dev, s);
793 return IRQ_HANDLED;
794}
795
796/*
797==============================================================================
798 INT procedure
799*/
70265d24 800static irqreturn_t interrupt_pcl818(int irq, void *d)
4da6a1d8 801{
71b5f4f1 802 struct comedi_device *dev = d;
4da6a1d8
MD
803
804 if (!dev->attached) {
805 comedi_error(dev, "premature interrupt");
806 return IRQ_HANDLED;
807 }
5f74ea14 808 /* printk("I\n"); */
4da6a1d8 809
e21de1a8
IA
810 if (devpriv->irq_blocked && devpriv->irq_was_now_closed) {
811 if ((devpriv->neverending_ai || (!devpriv->neverending_ai &&
0a85b6f0
MT
812 devpriv->ai_act_scan > 0)) &&
813 (devpriv->ai_mode == INT_TYPE_AI1_DMA ||
814 devpriv->ai_mode == INT_TYPE_AI3_DMA)) {
e21de1a8
IA
815 /* The cleanup from ai_cancel() has been delayed
816 until now because the card doesn't seem to like
817 being reprogrammed while a DMA transfer is in
818 progress.
819 */
820 struct comedi_subdevice *s = dev->subdevices + 0;
821 devpriv->ai_act_scan = 0;
822 devpriv->neverending_ai = 0;
823 pcl818_ai_cancel(dev, s);
824 }
825
826 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
827
828 return IRQ_HANDLED;
829 }
830
4da6a1d8
MD
831 switch (devpriv->ai_mode) {
832 case INT_TYPE_AI1_DMA:
833 case INT_TYPE_AI3_DMA:
834 return interrupt_pcl818_ai_mode13_dma(irq, d);
835 case INT_TYPE_AI1_INT:
836 case INT_TYPE_AI3_INT:
837 return interrupt_pcl818_ai_mode13_int(irq, d);
838 case INT_TYPE_AI1_FIFO:
839 case INT_TYPE_AI3_FIFO:
840 return interrupt_pcl818_ai_mode13_fifo(irq, d);
841#ifdef PCL818_MODE13_AO
842 case INT_TYPE_AO1_INT:
843 case INT_TYPE_AO3_INT:
844 return interrupt_pcl818_ao_mode13_int(irq, d);
845#endif
846 default:
847 break;
848 }
849
850 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
851
852 if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked)
0a85b6f0 853 || (!devpriv->ai_mode)) {
4da6a1d8
MD
854 comedi_error(dev, "bad IRQ!");
855 return IRQ_NONE;
856 }
857
bbc9a991 858 comedi_error(dev, "IRQ from unknown source!");
4da6a1d8
MD
859 return IRQ_NONE;
860}
861
862/*
863==============================================================================
864 ANALOG INPUT MODE 1 or 3 DMA , 818 cards
865*/
da91b269 866static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev,
0a85b6f0 867 struct comedi_subdevice *s)
4da6a1d8
MD
868{
869 unsigned int flags;
870 unsigned int bytes;
871
5f74ea14 872 printk("mode13dma_int, mode: %d\n", mode);
0109253d 873 disable_dma(devpriv->dma); /* disable dma */
4da6a1d8
MD
874 bytes = devpriv->hwdmasize[0];
875 if (!devpriv->neverending_ai) {
0109253d
BP
876 bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */
877 devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */
878 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */
4da6a1d8
MD
879 devpriv->dma_runs_to_end--;
880 if (devpriv->dma_runs_to_end >= 0)
881 bytes = devpriv->hwdmasize[0];
882 }
883
884 devpriv->next_dma_buf = 0;
885 set_dma_mode(devpriv->dma, DMA_MODE_READ);
886 flags = claim_dma_lock();
887 clear_dma_ff(devpriv->dma);
888 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
889 set_dma_count(devpriv->dma, bytes);
890 release_dma_lock(flags);
891 enable_dma(devpriv->dma);
892
893 if (mode == 1) {
894 devpriv->ai_mode = INT_TYPE_AI1_DMA;
895 outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */
896 } else {
897 devpriv->ai_mode = INT_TYPE_AI3_DMA;
898 outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */
899 };
900}
901
902#ifdef unused
903/*
904==============================================================================
905 ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards
906*/
da91b269 907static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device *dev,
0a85b6f0 908 struct comedi_subdevice *s)
4da6a1d8
MD
909{
910 unsigned int flags;
790c5541 911 short *pole;
4da6a1d8
MD
912
913 set_dma_mode(devpriv->dma, DMA_MODE_READ | DMA_AUTOINIT);
914 flags = claim_dma_lock();
915 clear_dma_ff(devpriv->dma);
916 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
917 set_dma_count(devpriv->dma, devpriv->hwdmasize[0]);
918 release_dma_lock(flags);
919 enable_dma(devpriv->dma);
0109253d 920 devpriv->last_top_dma = 0; /* devpriv->hwdmasize[0]; */
0a85b6f0 921 pole = (short *)devpriv->dmabuf[0];
4da6a1d8
MD
922 devpriv->dmasamplsize = devpriv->hwdmasize[0] / 2;
923 pole[devpriv->dmasamplsize - 1] = MAGIC_DMA_WORD;
924#ifdef unused
925 devpriv->rtc_freq = rtc_setfreq_irq(2048);
926 devpriv->rtc_irq_timer.expires =
0a85b6f0 927 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100;
4da6a1d8
MD
928 devpriv->rtc_irq_timer.data = (unsigned long)dev;
929 devpriv->rtc_irq_timer.function = rtc_dropped_irq;
930
931 add_timer(&devpriv->rtc_irq_timer);
932#endif
933
934 if (mode == 1) {
935 devpriv->int818_mode = INT_TYPE_AI1_DMA_RTC;
936 outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+DMA */
937 } else {
938 devpriv->int818_mode = INT_TYPE_AI3_DMA_RTC;
939 outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+DMA */
940 };
941}
942#endif
943
944/*
945==============================================================================
946 ANALOG INPUT MODE 1 or 3, 818 cards
947*/
da91b269 948static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
0a85b6f0 949 struct comedi_subdevice *s)
4da6a1d8 950{
ea6d0d4c 951 struct comedi_cmd *cmd = &s->async->cmd;
48b1aff5 952 int divisor1 = 0, divisor2 = 0;
4da6a1d8
MD
953 unsigned int seglen;
954
c62a0ef4 955 dev_dbg(dev->hw_dev, "pcl818_ai_cmd_mode()\n");
4da6a1d8
MD
956 if ((!dev->irq) && (!devpriv->dma_rtc)) {
957 comedi_error(dev, "IRQ not defined!");
958 return -EINVAL;
959 }
960
961 if (devpriv->irq_blocked)
962 return -EBUSY;
963
0109253d 964 start_pacer(dev, -1, 0, 0); /* stop pacer */
4da6a1d8
MD
965
966 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
0a85b6f0 967 devpriv->ai_n_chan);
4da6a1d8
MD
968 if (seglen < 1)
969 return -EINVAL;
970 setup_channel_list(dev, s, devpriv->ai_chanlist,
0a85b6f0 971 devpriv->ai_n_chan, seglen);
4da6a1d8 972
5f74ea14 973 udelay(1);
4da6a1d8
MD
974
975 devpriv->ai_act_scan = devpriv->ai_scans;
976 devpriv->ai_act_chan = 0;
977 devpriv->irq_blocked = 1;
978 devpriv->irq_was_now_closed = 0;
979 devpriv->neverending_ai = 0;
980 devpriv->act_chanlist_pos = 0;
981 devpriv->dma_runs_to_end = 0;
982
983 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
0109253d 984 devpriv->neverending_ai = 1; /* well, user want neverending */
4da6a1d8
MD
985
986 if (mode == 1) {
987 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
0a85b6f0
MT
988 &divisor2, &cmd->convert_arg,
989 TRIG_ROUND_NEAREST);
4da6a1d8
MD
990 if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */
991 divisor1 = 2;
992 divisor2 /= 2;
993 }
994 if (divisor2 == 1) {
995 divisor2 = 2;
996 divisor1 /= 2;
997 }
998 }
999
1000 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1001
1002 switch (devpriv->dma) {
0109253d 1003 case 1: /* DMA */
4da6a1d8
MD
1004 case 3:
1005 if (devpriv->dma_rtc == 0) {
1006 pcl818_ai_mode13dma_int(mode, dev, s);
1007 }
1008#ifdef unused
1009 else {
1010 pcl818_ai_mode13dma_rtc(mode, dev, s);
1011 }
1012#else
1013 else {
1014 return -EINVAL;
1015 }
1016#endif
1017 break;
a71f18d2
IA
1018 case 0:
1019 if (!devpriv->usefifo) {
1020 /* IRQ */
5f74ea14 1021 /* printk("IRQ\n"); */
a71f18d2
IA
1022 if (mode == 1) {
1023 devpriv->ai_mode = INT_TYPE_AI1_INT;
1024 /* Pacer+IRQ */
0a85b6f0
MT
1025 outb(0x83 | (dev->irq << 4),
1026 dev->iobase + PCL818_CONTROL);
a71f18d2
IA
1027 } else {
1028 devpriv->ai_mode = INT_TYPE_AI3_INT;
1029 /* Ext trig+IRQ */
0a85b6f0
MT
1030 outb(0x82 | (dev->irq << 4),
1031 dev->iobase + PCL818_CONTROL);
a71f18d2 1032 }
4da6a1d8 1033 } else {
a71f18d2
IA
1034 /* FIFO */
1035 /* enable FIFO */
1036 outb(1, dev->iobase + PCL818_FI_ENABLE);
1037 if (mode == 1) {
1038 devpriv->ai_mode = INT_TYPE_AI1_FIFO;
1039 /* Pacer */
1040 outb(0x03, dev->iobase + PCL818_CONTROL);
1041 } else {
1042 devpriv->ai_mode = INT_TYPE_AI3_FIFO;
1043 outb(0x02, dev->iobase + PCL818_CONTROL);
1044 }
1045 }
4da6a1d8
MD
1046 }
1047
1048 start_pacer(dev, mode, divisor1, divisor2);
1049
1050#ifdef unused
1051 switch (devpriv->ai_mode) {
1052 case INT_TYPE_AI1_DMA_RTC:
1053 case INT_TYPE_AI3_DMA_RTC:
1054 set_rtc_irq_bit(1); /* start RTC */
1055 break;
1056 }
1057#endif
c62a0ef4 1058 dev_dbg(dev->hw_dev, "pcl818_ai_cmd_mode() end\n");
4da6a1d8
MD
1059 return 0;
1060}
1061
1062#ifdef unused
1063/*
1064==============================================================================
1065 ANALOG OUTPUT MODE 1 or 3, 818 cards
1066*/
1067#ifdef PCL818_MODE13_AO
0a85b6f0
MT
1068static int pcl818_ao_mode13(int mode, struct comedi_device *dev,
1069 struct comedi_subdevice *s, comedi_trig * it)
4da6a1d8 1070{
48b1aff5 1071 int divisor1 = 0, divisor2 = 0;
4da6a1d8
MD
1072
1073 if (!dev->irq) {
1074 comedi_error(dev, "IRQ not defined!");
1075 return -EINVAL;
1076 }
1077
1078 if (devpriv->irq_blocked)
1079 return -EBUSY;
1080
0109253d 1081 start_pacer(dev, -1, 0, 0); /* stop pacer */
4da6a1d8
MD
1082
1083 devpriv->int13_act_scan = it->n;
1084 devpriv->int13_act_chan = 0;
1085 devpriv->irq_blocked = 1;
1086 devpriv->irq_was_now_closed = 0;
1087 devpriv->neverending_ai = 0;
1088 devpriv->act_chanlist_pos = 0;
1089
1090 if (mode == 1) {
1091 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
0a85b6f0
MT
1092 &divisor2, &it->trigvar,
1093 TRIG_ROUND_NEAREST);
4da6a1d8
MD
1094 if (divisor1 == 1) { /* PCL818 crash if any divisor is set to 1 */
1095 divisor1 = 2;
1096 divisor2 /= 2;
1097 }
1098 if (divisor2 == 1) {
1099 divisor2 = 2;
1100 divisor1 /= 2;
1101 }
1102 }
1103
1104 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1105 if (mode == 1) {
1106 devpriv->int818_mode = INT_TYPE_AO1_INT;
1107 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */
1108 } else {
1109 devpriv->int818_mode = INT_TYPE_AO3_INT;
1110 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */
1111 };
1112
1113 start_pacer(dev, mode, divisor1, divisor2);
1114
1115 return 0;
1116}
1117
1118/*
1119==============================================================================
1120 ANALOG OUTPUT MODE 1, 818 cards
1121*/
0a85b6f0
MT
1122static int pcl818_ao_mode1(struct comedi_device *dev,
1123 struct comedi_subdevice *s, comedi_trig * it)
4da6a1d8
MD
1124{
1125 return pcl818_ao_mode13(1, dev, s, it);
1126}
1127
1128/*
1129==============================================================================
1130 ANALOG OUTPUT MODE 3, 818 cards
1131*/
0a85b6f0
MT
1132static int pcl818_ao_mode3(struct comedi_device *dev,
1133 struct comedi_subdevice *s, comedi_trig * it)
4da6a1d8
MD
1134{
1135 return pcl818_ao_mode13(3, dev, s, it);
1136}
1137#endif
1138#endif
1139
1140/*
1141==============================================================================
1142 Start/stop pacer onboard pacer
1143*/
0a85b6f0
MT
1144static void start_pacer(struct comedi_device *dev, int mode,
1145 unsigned int divisor1, unsigned int divisor2)
4da6a1d8
MD
1146{
1147 outb(0xb4, dev->iobase + PCL818_CTRCTL);
1148 outb(0x74, dev->iobase + PCL818_CTRCTL);
5f74ea14 1149 udelay(1);
4da6a1d8
MD
1150
1151 if (mode == 1) {
1152 outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
1153 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
1154 outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
1155 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
1156 }
1157}
1158
1159/*
1160==============================================================================
1161 Check if channel list from user is builded correctly
1162 If it's ok, then program scan/gain logic
1163*/
0a85b6f0
MT
1164static int check_channel_list(struct comedi_device *dev,
1165 struct comedi_subdevice *s,
1166 unsigned int *chanlist, unsigned int n_chan)
4da6a1d8
MD
1167{
1168 unsigned int chansegment[16];
1169 unsigned int i, nowmustbechan, seglen, segpos;
1170
1171 /* correct channel and range number check itself comedi/range.c */
1172 if (n_chan < 1) {
1173 comedi_error(dev, "range/channel list is empty!");
1174 return 0;
1175 }
1176
1177 if (n_chan > 1) {
25985edc 1178 /* first channel is every time ok */
4da6a1d8 1179 chansegment[0] = chanlist[0];
0109253d 1180 /* build part of chanlist */
4da6a1d8 1181 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
0109253d 1182
5f74ea14 1183 /* printk("%d. %d * %d\n",i,
0109253d
BP
1184 * CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));*/
1185
1186 /* we detect loop, this must by finish */
1187
4da6a1d8
MD
1188 if (chanlist[0] == chanlist[i])
1189 break;
1190 nowmustbechan =
0a85b6f0 1191 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
25985edc 1192 if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */
5f74ea14 1193 printk
25985edc 1194 ("comedi%d: pcl818: channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
0a85b6f0
MT
1195 dev->minor, i, CR_CHAN(chanlist[i]),
1196 nowmustbechan, CR_CHAN(chanlist[0]));
4da6a1d8
MD
1197 return 0;
1198 }
0109253d 1199 /* well, this is next correct channel in list */
4da6a1d8
MD
1200 chansegment[i] = chanlist[i];
1201 }
1202
0109253d 1203 /* check whole chanlist */
4da6a1d8 1204 for (i = 0, segpos = 0; i < n_chan; i++) {
5f74ea14 1205 /* 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 1206 if (chanlist[i] != chansegment[i % seglen]) {
5f74ea14 1207 printk
0a85b6f0
MT
1208 ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1209 dev->minor, i, CR_CHAN(chansegment[i]),
1210 CR_RANGE(chansegment[i]),
1211 CR_AREF(chansegment[i]),
1212 CR_CHAN(chanlist[i % seglen]),
1213 CR_RANGE(chanlist[i % seglen]),
1214 CR_AREF(chansegment[i % seglen]));
0109253d 1215 return 0; /* chan/gain list is strange */
4da6a1d8
MD
1216 }
1217 }
1218 } else {
1219 seglen = 1;
1220 }
5f74ea14 1221 printk("check_channel_list: seglen %d\n", seglen);
4da6a1d8
MD
1222 return seglen;
1223}
1224
0a85b6f0
MT
1225static void setup_channel_list(struct comedi_device *dev,
1226 struct comedi_subdevice *s,
1227 unsigned int *chanlist, unsigned int n_chan,
1228 unsigned int seglen)
4da6a1d8
MD
1229{
1230 int i;
1231
1232 devpriv->act_chanlist_len = seglen;
1233 devpriv->act_chanlist_pos = 0;
1234
0109253d 1235 for (i = 0; i < seglen; i++) { /* store range list to card */
4da6a1d8
MD
1236 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
1237 outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */
1238 outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */
1239 }
1240
5f74ea14 1241 udelay(1);
4da6a1d8
MD
1242
1243 /* select channel interval to scan */
1244 outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen -
0a85b6f0
MT
1245 1] << 4),
1246 dev->iobase + PCL818_MUX);
4da6a1d8
MD
1247}
1248
1249/*
1250==============================================================================
1251 Check if board is switched to SE (1) or DIFF(0) mode
1252*/
1253static int check_single_ended(unsigned int port)
1254{
fc950139 1255 if (inb(port + PCL818_STATUS) & 0x20)
4da6a1d8 1256 return 1;
fc950139 1257 return 0;
4da6a1d8
MD
1258}
1259
1260/*
1261==============================================================================
1262*/
da91b269 1263static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 1264 struct comedi_cmd *cmd)
4da6a1d8 1265{
dd8a4b47 1266 const struct pcl818_board *board = comedi_board(dev);
4da6a1d8 1267 int err = 0;
48b1aff5 1268 int tmp, divisor1 = 0, divisor2 = 0;
4da6a1d8
MD
1269
1270 /* step 1: make sure trigger sources are trivially valid */
1271
1272 tmp = cmd->start_src;
1273 cmd->start_src &= TRIG_NOW;
1274 if (!cmd->start_src || tmp != cmd->start_src)
1275 err++;
1276
1277 tmp = cmd->scan_begin_src;
1278 cmd->scan_begin_src &= TRIG_FOLLOW;
1279 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1280 err++;
1281
1282 tmp = cmd->convert_src;
1283 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
1284 if (!cmd->convert_src || tmp != cmd->convert_src)
1285 err++;
1286
1287 tmp = cmd->scan_end_src;
1288 cmd->scan_end_src &= TRIG_COUNT;
1289 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1290 err++;
1291
1292 tmp = cmd->stop_src;
1293 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
1294 if (!cmd->stop_src || tmp != cmd->stop_src)
1295 err++;
1296
fc950139 1297 if (err)
4da6a1d8 1298 return 1;
4da6a1d8
MD
1299
1300 /* step 2: make sure trigger sources are unique and mutually compatible */
1301
1302 if (cmd->start_src != TRIG_NOW) {
1303 cmd->start_src = TRIG_NOW;
1304 err++;
1305 }
1306 if (cmd->scan_begin_src != TRIG_FOLLOW) {
1307 cmd->scan_begin_src = TRIG_FOLLOW;
1308 err++;
1309 }
1310 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
1311 err++;
1312
1313 if (cmd->scan_end_src != TRIG_COUNT) {
1314 cmd->scan_end_src = TRIG_COUNT;
1315 err++;
1316 }
1317
1318 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
1319 err++;
1320
fc950139 1321 if (err)
4da6a1d8 1322 return 2;
4da6a1d8
MD
1323
1324 /* step 3: make sure arguments are trivially compatible */
1325
1326 if (cmd->start_arg != 0) {
1327 cmd->start_arg = 0;
1328 err++;
1329 }
1330
1331 if (cmd->scan_begin_arg != 0) {
1332 cmd->scan_begin_arg = 0;
1333 err++;
1334 }
1335
1336 if (cmd->convert_src == TRIG_TIMER) {
dd8a4b47
HS
1337 if (cmd->convert_arg < board->ns_min) {
1338 cmd->convert_arg = board->ns_min;
4da6a1d8
MD
1339 err++;
1340 }
1341 } else { /* TRIG_EXT */
1342 if (cmd->convert_arg != 0) {
1343 cmd->convert_arg = 0;
1344 err++;
1345 }
1346 }
1347
4da6a1d8
MD
1348 if (cmd->scan_end_arg != cmd->chanlist_len) {
1349 cmd->scan_end_arg = cmd->chanlist_len;
1350 err++;
1351 }
1352 if (cmd->stop_src == TRIG_COUNT) {
1353 if (!cmd->stop_arg) {
1354 cmd->stop_arg = 1;
1355 err++;
1356 }
1357 } else { /* TRIG_NONE */
1358 if (cmd->stop_arg != 0) {
1359 cmd->stop_arg = 0;
1360 err++;
1361 }
1362 }
1363
fc950139 1364 if (err)
4da6a1d8 1365 return 3;
4da6a1d8
MD
1366
1367 /* step 4: fix up any arguments */
1368
1369 if (cmd->convert_src == TRIG_TIMER) {
1370 tmp = cmd->convert_arg;
1371 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
0a85b6f0
MT
1372 &divisor2, &cmd->convert_arg,
1373 cmd->flags & TRIG_ROUND_MASK);
dd8a4b47
HS
1374 if (cmd->convert_arg < board->ns_min)
1375 cmd->convert_arg = board->ns_min;
4da6a1d8
MD
1376 if (tmp != cmd->convert_arg)
1377 err++;
1378 }
1379
fc950139 1380 if (err)
4da6a1d8 1381 return 4;
4da6a1d8
MD
1382
1383 /* step 5: complain about special chanlist considerations */
1384
1385 if (cmd->chanlist) {
1386 if (!check_channel_list(dev, s, cmd->chanlist,
0a85b6f0 1387 cmd->chanlist_len))
0109253d 1388 return 5; /* incorrect channels list */
4da6a1d8
MD
1389 }
1390
1391 return 0;
1392}
1393
1394/*
1395==============================================================================
1396*/
da91b269 1397static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
4da6a1d8 1398{
ea6d0d4c 1399 struct comedi_cmd *cmd = &s->async->cmd;
4da6a1d8
MD
1400 int retval;
1401
c62a0ef4 1402 dev_dbg(dev->hw_dev, "pcl818_ai_cmd()\n");
4da6a1d8
MD
1403 devpriv->ai_n_chan = cmd->chanlist_len;
1404 devpriv->ai_chanlist = cmd->chanlist;
1405 devpriv->ai_flags = cmd->flags;
1406 devpriv->ai_data_len = s->async->prealloc_bufsz;
1407 devpriv->ai_data = s->async->prealloc_buf;
1408 devpriv->ai_timer1 = 0;
1409 devpriv->ai_timer2 = 0;
1410
fc950139 1411 if (cmd->stop_src == TRIG_COUNT)
4da6a1d8 1412 devpriv->ai_scans = cmd->stop_arg;
fc950139 1413 else
4da6a1d8 1414 devpriv->ai_scans = 0;
4da6a1d8 1415
0109253d
BP
1416 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */
1417 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */
4da6a1d8
MD
1418 devpriv->ai_timer1 = cmd->convert_arg;
1419 retval = pcl818_ai_cmd_mode(1, dev, s);
c62a0ef4 1420 dev_dbg(dev->hw_dev, "pcl818_ai_cmd() end\n");
4da6a1d8
MD
1421 return retval;
1422 }
0109253d 1423 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
4da6a1d8
MD
1424 return pcl818_ai_cmd_mode(3, dev, s);
1425 }
1426 }
1427
1428 return -1;
1429}
1430
1431/*
1432==============================================================================
1433 cancel any mode 1-4 AI
1434*/
0a85b6f0
MT
1435static int pcl818_ai_cancel(struct comedi_device *dev,
1436 struct comedi_subdevice *s)
4da6a1d8
MD
1437{
1438 if (devpriv->irq_blocked > 0) {
c62a0ef4 1439 dev_dbg(dev->hw_dev, "pcl818_ai_cancel()\n");
e21de1a8 1440 devpriv->irq_was_now_closed = 1;
4da6a1d8 1441
e21de1a8 1442 switch (devpriv->ai_mode) {
4da6a1d8
MD
1443#ifdef unused
1444 case INT_TYPE_AI1_DMA_RTC:
1445 case INT_TYPE_AI3_DMA_RTC:
0109253d 1446 set_rtc_irq_bit(0); /* stop RTC */
4da6a1d8
MD
1447 del_timer(&devpriv->rtc_irq_timer);
1448#endif
1449 case INT_TYPE_AI1_DMA:
1450 case INT_TYPE_AI3_DMA:
e21de1a8 1451 if (devpriv->neverending_ai ||
0a85b6f0
MT
1452 (!devpriv->neverending_ai &&
1453 devpriv->ai_act_scan > 0)) {
4da6a1d8
MD
1454 /* wait for running dma transfer to end, do cleanup in interrupt */
1455 goto end;
1456 }
1457 disable_dma(devpriv->dma);
1458 case INT_TYPE_AI1_INT:
1459 case INT_TYPE_AI3_INT:
1460 case INT_TYPE_AI1_FIFO:
1461 case INT_TYPE_AI3_FIFO:
1462#ifdef PCL818_MODE13_AO
1463 case INT_TYPE_AO1_INT:
1464 case INT_TYPE_AO3_INT:
1465#endif
1466 outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */
5f74ea14 1467 udelay(1);
4da6a1d8
MD
1468 start_pacer(dev, -1, 0, 0);
1469 outb(0, dev->iobase + PCL818_AD_LO);
1470 inb(dev->iobase + PCL818_AD_LO);
1471 inb(dev->iobase + PCL818_AD_HI);
1472 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
1473 outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */
0109253d 1474 if (devpriv->usefifo) { /* FIFO shutdown */
4da6a1d8
MD
1475 outb(0, dev->iobase + PCL818_FI_INTCLR);
1476 outb(0, dev->iobase + PCL818_FI_FLUSH);
1477 outb(0, dev->iobase + PCL818_FI_ENABLE);
1478 }
1479 devpriv->irq_blocked = 0;
1480 devpriv->last_int_sub = s;
1481 devpriv->neverending_ai = 0;
e21de1a8
IA
1482 devpriv->ai_mode = 0;
1483 devpriv->irq_was_now_closed = 0;
4da6a1d8
MD
1484 break;
1485 }
1486 }
1487
0a85b6f0 1488end:
c62a0ef4 1489 dev_dbg(dev->hw_dev, "pcl818_ai_cancel() end\n");
4da6a1d8
MD
1490 return 0;
1491}
1492
1493/*
1494==============================================================================
1495 chech for PCL818
1496*/
1497static int pcl818_check(unsigned long iobase)
1498{
1499 outb(0x00, iobase + PCL818_MUX);
5f74ea14 1500 udelay(1);
4da6a1d8 1501 if (inb(iobase + PCL818_MUX) != 0x00)
0109253d 1502 return 1; /* there isn't card */
4da6a1d8 1503 outb(0x55, iobase + PCL818_MUX);
5f74ea14 1504 udelay(1);
4da6a1d8 1505 if (inb(iobase + PCL818_MUX) != 0x55)
0109253d 1506 return 1; /* there isn't card */
4da6a1d8 1507 outb(0x00, iobase + PCL818_MUX);
5f74ea14 1508 udelay(1);
4da6a1d8 1509 outb(0x18, iobase + PCL818_CONTROL);
5f74ea14 1510 udelay(1);
4da6a1d8 1511 if (inb(iobase + PCL818_CONTROL) != 0x18)
0109253d
BP
1512 return 1; /* there isn't card */
1513 return 0; /* ok, card exist */
4da6a1d8
MD
1514}
1515
1516/*
1517==============================================================================
1518 reset whole PCL-818 cards
1519*/
da91b269 1520static void pcl818_reset(struct comedi_device *dev)
4da6a1d8 1521{
dd8a4b47
HS
1522 const struct pcl818_board *board = comedi_board(dev);
1523
0109253d 1524 if (devpriv->usefifo) { /* FIFO shutdown */
4da6a1d8
MD
1525 outb(0, dev->iobase + PCL818_FI_INTCLR);
1526 outb(0, dev->iobase + PCL818_FI_FLUSH);
1527 outb(0, dev->iobase + PCL818_FI_ENABLE);
1528 }
0109253d 1529 outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */
4da6a1d8 1530 outb(0, dev->iobase + PCL818_DA_HI);
5f74ea14 1531 udelay(1);
0109253d 1532 outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */
4da6a1d8 1533 outb(0, dev->iobase + PCL818_DO_LO);
5f74ea14 1534 udelay(1);
4da6a1d8
MD
1535 outb(0, dev->iobase + PCL818_CONTROL);
1536 outb(0, dev->iobase + PCL818_CNTENABLE);
1537 outb(0, dev->iobase + PCL818_MUX);
1538 outb(0, dev->iobase + PCL818_CLRINT);
1539 outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */
1540 outb(0x70, dev->iobase + PCL818_CTRCTL);
1541 outb(0x30, dev->iobase + PCL818_CTRCTL);
dd8a4b47 1542 if (board->is_818) {
4da6a1d8
MD
1543 outb(0, dev->iobase + PCL818_RANGE);
1544 } else {
1545 outb(0, dev->iobase + PCL718_DA2_LO);
1546 outb(0, dev->iobase + PCL718_DA2_HI);
1547 }
1548}
1549
1550#ifdef unused
1551/*
1552==============================================================================
1553 Enable(1)/disable(0) periodic interrupts from RTC
1554*/
1555static int set_rtc_irq_bit(unsigned char bit)
1556{
1557 unsigned char val;
1558 unsigned long flags;
1559
1560 if (bit == 1) {
1561 RTC_timer_lock++;
1562 if (RTC_timer_lock > 1)
1563 return 0;
1564 } else {
1565 RTC_timer_lock--;
1566 if (RTC_timer_lock < 0)
1567 RTC_timer_lock = 0;
1568 if (RTC_timer_lock > 0)
1569 return 0;
1570 }
1571
1572 save_flags(flags);
1573 cli();
1574 val = CMOS_READ(RTC_CONTROL);
fc950139 1575 if (bit)
4da6a1d8 1576 val |= RTC_PIE;
fc950139 1577 else
4da6a1d8 1578 val &= ~RTC_PIE;
fc950139 1579
4da6a1d8
MD
1580 CMOS_WRITE(val, RTC_CONTROL);
1581 CMOS_READ(RTC_INTR_FLAGS);
1582 restore_flags(flags);
1583 return 0;
1584}
1585
1586/*
1587==============================================================================
1588 Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers)
1589*/
1590static void rtc_dropped_irq(unsigned long data)
1591{
71b5f4f1 1592 struct comedi_device *dev = (void *)data;
4da6a1d8
MD
1593 unsigned long flags, tmp;
1594
1595 switch (devpriv->int818_mode) {
1596 case INT_TYPE_AI1_DMA_RTC:
1597 case INT_TYPE_AI3_DMA_RTC:
1598 mod_timer(&devpriv->rtc_irq_timer,
0a85b6f0 1599 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
4da6a1d8
MD
1600 save_flags(flags);
1601 cli();
1602 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */
1603 restore_flags(flags);
1604 break;
95cd17c9 1605 }
4da6a1d8
MD
1606}
1607
1608/*
1609==============================================================================
1610 Set frequency of interrupts from RTC
1611*/
1612static int rtc_setfreq_irq(int freq)
1613{
1614 int tmp = 0;
1615 int rtc_freq;
1616 unsigned char val;
1617 unsigned long flags;
1618
1619 if (freq < 2)
1620 freq = 2;
1621 if (freq > 8192)
1622 freq = 8192;
1623
1624 while (freq > (1 << tmp))
1625 tmp++;
1626
1627 rtc_freq = 1 << tmp;
1628
1629 save_flags(flags);
1630 cli();
1631 val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
1632 val |= (16 - tmp);
1633 CMOS_WRITE(val, RTC_FREQ_SELECT);
1634 restore_flags(flags);
1635 return rtc_freq;
1636}
1637#endif
1638
da91b269 1639static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
4da6a1d8 1640{
dd8a4b47 1641 const struct pcl818_board *board = comedi_board(dev);
4da6a1d8
MD
1642 int ret;
1643 unsigned long iobase;
a71f18d2
IA
1644 unsigned int irq;
1645 int dma;
4da6a1d8 1646 unsigned long pages;
34c43922 1647 struct comedi_subdevice *s;
4da6a1d8 1648
c3744138
BP
1649 ret = alloc_private(dev, sizeof(struct pcl818_private));
1650 if (ret < 0)
4da6a1d8
MD
1651 return ret; /* Can't alloc mem */
1652
1653 /* claim our I/O space */
1654 iobase = it->options[0];
26ba666c
RM
1655 printk
1656 ("comedi%d: pcl818: board=%s, ioport=0x%03lx",
dd8a4b47
HS
1657 dev->minor, board->name, iobase);
1658 devpriv->io_range = board->io_range;
1659 if ((board->fifo) && (it->options[2] == -1)) {
1660 /* we've board with FIFO and we want to use FIFO */
4da6a1d8
MD
1661 devpriv->io_range = PCLx1xFIFO_RANGE;
1662 devpriv->usefifo = 1;
1663 }
1664 if (!request_region(iobase, devpriv->io_range, "pcl818")) {
26ba666c 1665 comedi_error(dev, "I/O port conflict\n");
4da6a1d8
MD
1666 return -EIO;
1667 }
1668
1669 dev->iobase = iobase;
1670
1671 if (pcl818_check(iobase)) {
26ba666c 1672 comedi_error(dev, "I can't detect board. FAIL!\n");
4da6a1d8
MD
1673 return -EIO;
1674 }
1675
dd8a4b47
HS
1676 dev->board_name = board->name;
1677
4da6a1d8
MD
1678 /* grab our IRQ */
1679 irq = 0;
dd8a4b47 1680 if (board->IRQbits != 0) { /* board support IRQ */
4da6a1d8
MD
1681 irq = it->options[1];
1682 if (irq) { /* we want to use IRQ */
dd8a4b47 1683 if (((1 << irq) & board->IRQbits) == 0) {
5f74ea14 1684 printk
0a85b6f0
MT
1685 (", IRQ %u is out of allowed range, DISABLING IT",
1686 irq);
4da6a1d8
MD
1687 irq = 0; /* Bad IRQ */
1688 } else {
0a85b6f0
MT
1689 if (request_irq
1690 (irq, interrupt_pcl818, 0, "pcl818", dev)) {
5f74ea14 1691 printk
0a85b6f0
MT
1692 (", unable to allocate IRQ %u, DISABLING IT",
1693 irq);
4da6a1d8
MD
1694 irq = 0; /* Can't use IRQ */
1695 } else {
26ba666c 1696 printk(KERN_DEBUG "irq=%u", irq);
4da6a1d8
MD
1697 }
1698 }
1699 }
1700 }
1701
1702 dev->irq = irq;
fc950139
RM
1703 if (irq)
1704 devpriv->irq_free = 1; /* 1=we have allocated irq */
1705 else
4da6a1d8 1706 devpriv->irq_free = 0;
fc950139 1707
4da6a1d8
MD
1708 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
1709 devpriv->ai_mode = 0; /* mode of irq */
1710
1711#ifdef unused
1712 /* grab RTC for DMA operations */
1713 devpriv->dma_rtc = 0;
0109253d 1714 if (it->options[2] > 0) { /* we want to use DMA */
4da6a1d8
MD
1715 if (RTC_lock == 0) {
1716 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
0a85b6f0 1717 "pcl818 (RTC)"))
4da6a1d8
MD
1718 goto no_rtc;
1719 }
1720 devpriv->rtc_iobase = RTC_PORT(0);
1721 devpriv->rtc_iosize = RTC_IO_EXTENT;
1722 RTC_lock++;
5f74ea14 1723 if (!request_irq(RTC_IRQ, interrupt_pcl818_ai_mode13_dma_rtc, 0,
0a85b6f0 1724 "pcl818 DMA (RTC)", dev)) {
4da6a1d8
MD
1725 devpriv->dma_rtc = 1;
1726 devpriv->rtc_irq = RTC_IRQ;
26ba666c 1727 printk(KERN_DEBUG "dma_irq=%u", devpriv->rtc_irq);
4da6a1d8
MD
1728 } else {
1729 RTC_lock--;
1730 if (RTC_lock == 0) {
1731 if (devpriv->rtc_iobase)
1732 release_region(devpriv->rtc_iobase,
0a85b6f0 1733 devpriv->rtc_iosize);
4da6a1d8
MD
1734 }
1735 devpriv->rtc_iobase = 0;
1736 devpriv->rtc_iosize = 0;
1737 }
1738 }
1739
0a85b6f0 1740no_rtc:
4da6a1d8
MD
1741#endif
1742 /* grab our DMA */
1743 dma = 0;
1744 devpriv->dma = dma;
1745 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1746 goto no_dma; /* if we haven't IRQ, we can't use DMA */
dd8a4b47 1747 if (board->DMAbits != 0) { /* board support DMA */
4da6a1d8
MD
1748 dma = it->options[2];
1749 if (dma < 1)
1750 goto no_dma; /* DMA disabled */
dd8a4b47 1751 if (((1 << dma) & board->DMAbits) == 0) {
408f6bcd 1752 printk(KERN_ERR "DMA is out of allowed range, FAIL!\n");
4da6a1d8
MD
1753 return -EINVAL; /* Bad DMA */
1754 }
1755 ret = request_dma(dma, "pcl818");
408f6bcd 1756 if (ret)
4da6a1d8 1757 return -EBUSY; /* DMA isn't free */
4da6a1d8 1758 devpriv->dma = dma;
4da6a1d8
MD
1759 pages = 2; /* we need 16KB */
1760 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
408f6bcd 1761 if (!devpriv->dmabuf[0])
4da6a1d8
MD
1762 /* maybe experiment with try_to_free_pages() will help .... */
1763 return -EBUSY; /* no buffer :-( */
4da6a1d8
MD
1764 devpriv->dmapages[0] = pages;
1765 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1766 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
5f74ea14 1767 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
0109253d 1768 if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */
4da6a1d8 1769 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
408f6bcd 1770 if (!devpriv->dmabuf[1])
4da6a1d8 1771 return -EBUSY;
4da6a1d8
MD
1772 devpriv->dmapages[1] = pages;
1773 devpriv->hwdmaptr[1] =
0a85b6f0 1774 virt_to_bus((void *)devpriv->dmabuf[1]);
4da6a1d8
MD
1775 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1776 }
1777 }
1778
0a85b6f0 1779no_dma:
4da6a1d8 1780
c3744138
BP
1781 ret = alloc_subdevices(dev, 4);
1782 if (ret < 0)
4da6a1d8
MD
1783 return ret;
1784
1785 s = dev->subdevices + 0;
dd8a4b47 1786 if (!board->n_aichan_se) {
4da6a1d8
MD
1787 s->type = COMEDI_SUBD_UNUSED;
1788 } else {
1789 s->type = COMEDI_SUBD_AI;
1790 devpriv->sub_ai = s;
1791 s->subdev_flags = SDF_READABLE;
1792 if (check_single_ended(dev->iobase)) {
dd8a4b47 1793 s->n_chan = board->n_aichan_se;
4da6a1d8
MD
1794 s->subdev_flags |= SDF_COMMON | SDF_GROUND;
1795 printk(", %dchans S.E. DAC", s->n_chan);
1796 } else {
dd8a4b47 1797 s->n_chan = board->n_aichan_diff;
4da6a1d8
MD
1798 s->subdev_flags |= SDF_DIFF;
1799 printk(", %dchans DIFF DAC", s->n_chan);
1800 }
dd8a4b47 1801 s->maxdata = board->ai_maxdata;
4da6a1d8 1802 s->len_chanlist = s->n_chan;
dd8a4b47 1803 s->range_table = board->ai_range_type;
4da6a1d8
MD
1804 s->cancel = pcl818_ai_cancel;
1805 s->insn_read = pcl818_ai_insn_read;
1806 if ((irq) || (devpriv->dma_rtc)) {
1807 dev->read_subdev = s;
1808 s->subdev_flags |= SDF_CMD_READ;
1809 s->do_cmdtest = ai_cmdtest;
1810 s->do_cmd = ai_cmd;
1811 }
dd8a4b47 1812 if (board->is_818) {
4da6a1d8 1813 if ((it->options[4] == 1) || (it->options[4] == 10))
0109253d 1814 s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */
4da6a1d8
MD
1815 } else {
1816 switch (it->options[4]) {
1817 case 0:
1818 s->range_table = &range_bipolar10;
1819 break;
1820 case 1:
1821 s->range_table = &range_bipolar5;
1822 break;
1823 case 2:
1824 s->range_table = &range_bipolar2_5;
1825 break;
1826 case 3:
1827 s->range_table = &range718_bipolar1;
1828 break;
1829 case 4:
1830 s->range_table = &range718_bipolar0_5;
1831 break;
1832 case 6:
1833 s->range_table = &range_unipolar10;
1834 break;
1835 case 7:
1836 s->range_table = &range_unipolar5;
1837 break;
1838 case 8:
1839 s->range_table = &range718_unipolar2;
1840 break;
1841 case 9:
1842 s->range_table = &range718_unipolar1;
1843 break;
1844 default:
1845 s->range_table = &range_unknown;
1846 break;
1847 }
1848 }
1849 }
1850
1851 s = dev->subdevices + 1;
dd8a4b47 1852 if (!board->n_aochan) {
4da6a1d8
MD
1853 s->type = COMEDI_SUBD_UNUSED;
1854 } else {
1855 s->type = COMEDI_SUBD_AO;
1856 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
dd8a4b47
HS
1857 s->n_chan = board->n_aochan;
1858 s->maxdata = board->ao_maxdata;
1859 s->len_chanlist = board->n_aochan;
1860 s->range_table = board->ao_range_type;
4da6a1d8
MD
1861 s->insn_read = pcl818_ao_insn_read;
1862 s->insn_write = pcl818_ao_insn_write;
1863#ifdef unused
1864#ifdef PCL818_MODE13_AO
1865 if (irq) {
1866 s->trig[1] = pcl818_ao_mode1;
1867 s->trig[3] = pcl818_ao_mode3;
1868 }
1869#endif
1870#endif
dd8a4b47 1871 if (board->is_818) {
4da6a1d8
MD
1872 if ((it->options[4] == 1) || (it->options[4] == 10))
1873 s->range_table = &range_unipolar10;
1874 if (it->options[4] == 2)
1875 s->range_table = &range_unknown;
1876 } else {
1877 if ((it->options[5] == 1) || (it->options[5] == 10))
1878 s->range_table = &range_unipolar10;
1879 if (it->options[5] == 2)
1880 s->range_table = &range_unknown;
1881 }
1882 }
1883
1884 s = dev->subdevices + 2;
dd8a4b47 1885 if (!board->n_dichan) {
4da6a1d8
MD
1886 s->type = COMEDI_SUBD_UNUSED;
1887 } else {
1888 s->type = COMEDI_SUBD_DI;
1889 s->subdev_flags = SDF_READABLE;
dd8a4b47 1890 s->n_chan = board->n_dichan;
4da6a1d8 1891 s->maxdata = 1;
dd8a4b47 1892 s->len_chanlist = board->n_dichan;
4da6a1d8
MD
1893 s->range_table = &range_digital;
1894 s->insn_bits = pcl818_di_insn_bits;
1895 }
1896
1897 s = dev->subdevices + 3;
dd8a4b47 1898 if (!board->n_dochan) {
4da6a1d8
MD
1899 s->type = COMEDI_SUBD_UNUSED;
1900 } else {
1901 s->type = COMEDI_SUBD_DO;
1902 s->subdev_flags = SDF_WRITABLE;
dd8a4b47 1903 s->n_chan = board->n_dochan;
4da6a1d8 1904 s->maxdata = 1;
dd8a4b47 1905 s->len_chanlist = board->n_dochan;
4da6a1d8
MD
1906 s->range_table = &range_digital;
1907 s->insn_bits = pcl818_do_insn_bits;
1908 }
1909
1910 /* select 1/10MHz oscilator */
fc950139 1911 if ((it->options[3] == 0) || (it->options[3] == 10))
4da6a1d8 1912 devpriv->i8253_osc_base = 100;
fc950139 1913 else
4da6a1d8 1914 devpriv->i8253_osc_base = 1000;
4da6a1d8
MD
1915
1916 /* max sampling speed */
dd8a4b47 1917 devpriv->ns_min = board->ns_min;
4da6a1d8 1918
dd8a4b47 1919 if (!board->is_818) {
4da6a1d8
MD
1920 if ((it->options[6] == 1) || (it->options[6] == 100))
1921 devpriv->ns_min = 10000; /* extended PCL718 to 100kHz DAC */
1922 }
1923
1924 pcl818_reset(dev);
1925
5f74ea14 1926 printk("\n");
4da6a1d8
MD
1927
1928 return 0;
1929}
1930
484ecc95 1931static void pcl818_detach(struct comedi_device *dev)
4da6a1d8 1932{
484ecc95
HS
1933 if (dev->private) {
1934 pcl818_ai_cancel(dev, devpriv->sub_ai);
1935 pcl818_reset(dev);
1936 if (devpriv->dma)
1937 free_dma(devpriv->dma);
1938 if (devpriv->dmabuf[0])
1939 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1940 if (devpriv->dmabuf[1])
1941 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1942#ifdef unused
1943 if (devpriv->rtc_irq)
1944 free_irq(devpriv->rtc_irq, dev);
1945 if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1946 if (devpriv->rtc_iobase)
1947 release_region(devpriv->rtc_iobase,
1948 devpriv->rtc_iosize);
1949 }
1950 if (devpriv->dma_rtc)
1951 RTC_lock--;
1952#endif
1953 }
1954 if (dev->irq)
1955 free_irq(dev->irq, dev);
1956 if (dev->iobase)
1957 release_region(dev->iobase, devpriv->io_range);
4da6a1d8 1958}
90f703d3 1959
f6aafa10
HS
1960static const struct pcl818_board boardtypes[] = {
1961 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
1962 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1963 0x0a, 0xfff, 0xfff, 0, 1},
1964 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
1965 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1966 0x0a, 0xfff, 0xfff, 0, 1},
1967 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
1968 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1969 0x0a, 0xfff, 0xfff, 1, 1},
1970 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
1971 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1972 0x0a, 0xfff, 0xfff, 1, 1},
1973 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
1974 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1975 0x0a, 0xfff, 0xfff, 0, 1},
1976 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
1977 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1978 0x0a, 0xfff, 0xfff, 0, 0},
1979 /* pcm3718 */
1980 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
1981 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1982 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
1983};
1984
294f930d 1985static struct comedi_driver pcl818_driver = {
f6aafa10
HS
1986 .driver_name = "pcl818",
1987 .module = THIS_MODULE,
1988 .attach = pcl818_attach,
1989 .detach = pcl818_detach,
1990 .board_name = &boardtypes[0].name,
1991 .num_names = ARRAY_SIZE(boardtypes),
1992 .offset = sizeof(struct pcl818_board),
1993};
294f930d 1994module_comedi_driver(pcl818_driver);
f6aafa10 1995
90f703d3
AT
1996MODULE_AUTHOR("Comedi http://www.comedi.org");
1997MODULE_DESCRIPTION("Comedi low-level driver");
1998MODULE_LICENSE("GPL");