staging: rts5139: Fix typo in rts5139
[linux-2.6-block.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)
4634b815 329#define this_board ((const struct pcl818_board *)dev->board_ptr)
4da6a1d8
MD
330
331/*
332==============================================================================
333*/
0a85b6f0
MT
334static void setup_channel_list(struct comedi_device *dev,
335 struct comedi_subdevice *s,
336 unsigned int *chanlist, unsigned int n_chan,
337 unsigned int seglen);
338static int check_channel_list(struct comedi_device *dev,
339 struct comedi_subdevice *s,
340 unsigned int *chanlist, unsigned int n_chan);
341
342static int pcl818_ai_cancel(struct comedi_device *dev,
343 struct comedi_subdevice *s);
344static void start_pacer(struct comedi_device *dev, int mode,
345 unsigned int divisor1, unsigned int divisor2);
4da6a1d8
MD
346
347#ifdef unused
348static int set_rtc_irq_bit(unsigned char bit);
349static void rtc_dropped_irq(unsigned long data);
350static int rtc_setfreq_irq(int freq);
351#endif
352
353/*
354==============================================================================
355 ANALOG INPUT MODE0, 818 cards, slow version
356*/
0a85b6f0
MT
357static int pcl818_ai_insn_read(struct comedi_device *dev,
358 struct comedi_subdevice *s,
359 struct comedi_insn *insn, unsigned int *data)
4da6a1d8
MD
360{
361 int n;
362 int timeout;
363
364 /* software trigger, DMA and INT off */
365 outb(0, dev->iobase + PCL818_CONTROL);
366
367 /* select channel */
368 outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX);
369
370 /* select gain */
371 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE);
372
373 for (n = 0; n < insn->n; n++) {
374
375 /* clear INT (conversion end) flag */
376 outb(0, dev->iobase + PCL818_CLRINT);
377
378 /* start conversion */
379 outb(0, dev->iobase + PCL818_AD_LO);
380
381 timeout = 100;
382 while (timeout--) {
383 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
384 goto conv_finish;
5f74ea14 385 udelay(1);
4da6a1d8
MD
386 }
387 comedi_error(dev, "A/D insn timeout");
388 /* clear INT (conversion end) flag */
389 outb(0, dev->iobase + PCL818_CLRINT);
390 return -EIO;
391
0a85b6f0 392conv_finish:
4da6a1d8 393 data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |
0a85b6f0 394 (inb(dev->iobase + PCL818_AD_LO) >> 4));
4da6a1d8
MD
395 }
396
397 return n;
398}
399
400/*
401==============================================================================
402 ANALOG OUTPUT MODE0, 818 cards
403 only one sample per call is supported
404*/
0a85b6f0
MT
405static int pcl818_ao_insn_read(struct comedi_device *dev,
406 struct comedi_subdevice *s,
407 struct comedi_insn *insn, unsigned int *data)
4da6a1d8
MD
408{
409 int n;
410 int chan = CR_CHAN(insn->chanspec);
411
fc950139 412 for (n = 0; n < insn->n; n++)
4da6a1d8 413 data[n] = devpriv->ao_readback[chan];
4da6a1d8
MD
414
415 return n;
416}
417
0a85b6f0
MT
418static int pcl818_ao_insn_write(struct comedi_device *dev,
419 struct comedi_subdevice *s,
420 struct comedi_insn *insn, unsigned int *data)
4da6a1d8
MD
421{
422 int n;
423 int chan = CR_CHAN(insn->chanspec);
424
425 for (n = 0; n < insn->n; n++) {
426 devpriv->ao_readback[chan] = data[n];
427 outb((data[n] & 0x000f) << 4, dev->iobase +
0a85b6f0 428 (chan ? PCL718_DA2_LO : PCL818_DA_LO));
4da6a1d8 429 outb((data[n] & 0x0ff0) >> 4, dev->iobase +
0a85b6f0 430 (chan ? PCL718_DA2_HI : PCL818_DA_HI));
4da6a1d8
MD
431 }
432
433 return n;
434}
435
436/*
437==============================================================================
438 DIGITAL INPUT MODE0, 818 cards
439
440 only one sample per call is supported
441*/
0a85b6f0
MT
442static int pcl818_di_insn_bits(struct comedi_device *dev,
443 struct comedi_subdevice *s,
444 struct comedi_insn *insn, unsigned int *data)
4da6a1d8
MD
445{
446 if (insn->n != 2)
447 return -EINVAL;
448
449 data[1] = inb(dev->iobase + PCL818_DI_LO) |
0a85b6f0 450 (inb(dev->iobase + PCL818_DI_HI) << 8);
4da6a1d8
MD
451
452 return 2;
453}
454
455/*
456==============================================================================
457 DIGITAL OUTPUT MODE0, 818 cards
458
459 only one sample per call is supported
460*/
0a85b6f0
MT
461static int pcl818_do_insn_bits(struct comedi_device *dev,
462 struct comedi_subdevice *s,
463 struct comedi_insn *insn, unsigned int *data)
4da6a1d8
MD
464{
465 if (insn->n != 2)
466 return -EINVAL;
467
468 s->state &= ~data[0];
469 s->state |= (data[0] & data[1]);
470
471 outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
472 outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
473
474 data[1] = s->state;
475
476 return 2;
477}
478
479/*
480==============================================================================
481 analog input interrupt mode 1 & 3, 818 cards
482 one sample per interrupt version
483*/
484static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
485{
71b5f4f1 486 struct comedi_device *dev = d;
34c43922 487 struct comedi_subdevice *s = dev->subdevices + 0;
4da6a1d8
MD
488 int low;
489 int timeout = 50; /* wait max 50us */
490
491 while (timeout--) {
492 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
493 goto conv_finish;
5f74ea14 494 udelay(1);
4da6a1d8
MD
495 }
496 outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */
497 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
498 pcl818_ai_cancel(dev, s);
499 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
500 comedi_event(dev, s);
501 return IRQ_HANDLED;
502
0a85b6f0 503conv_finish:
4da6a1d8 504 low = inb(dev->iobase + PCL818_AD_LO);
0109253d 505 comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */
4da6a1d8
MD
506 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
507
0109253d 508 if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
5f74ea14 509 printk
0a85b6f0
MT
510 ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
511 (low & 0xf),
512 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
4da6a1d8
MD
513 pcl818_ai_cancel(dev, s);
514 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
515 comedi_event(dev, s);
516 return IRQ_HANDLED;
517 }
b3559cb1 518 devpriv->act_chanlist_pos++;
fc950139 519 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
b3559cb1 520 devpriv->act_chanlist_pos = 0;
fc950139 521
b3559cb1
IA
522 s->async->cur_chan++;
523 if (s->async->cur_chan >= devpriv->ai_n_chan) {
5f74ea14 524 /* printk("E"); */
b3559cb1 525 s->async->cur_chan = 0;
4da6a1d8
MD
526 devpriv->ai_act_scan--;
527 }
528
529 if (!devpriv->neverending_ai) {
530 if (devpriv->ai_act_scan == 0) { /* all data sampled */
531 pcl818_ai_cancel(dev, s);
532 s->async->events |= COMEDI_CB_EOA;
533 }
534 }
535 comedi_event(dev, s);
536 return IRQ_HANDLED;
537}
538
539/*
540==============================================================================
541 analog input dma mode 1 & 3, 818 cards
542*/
543static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
544{
71b5f4f1 545 struct comedi_device *dev = d;
34c43922 546 struct comedi_subdevice *s = dev->subdevices + 0;
4da6a1d8
MD
547 int i, len, bufptr;
548 unsigned long flags;
790c5541 549 short *ptr;
4da6a1d8
MD
550
551 disable_dma(devpriv->dma);
552 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
0109253d 553 if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */
4da6a1d8
MD
554 set_dma_mode(devpriv->dma, DMA_MODE_READ);
555 flags = claim_dma_lock();
556 set_dma_addr(devpriv->dma,
0a85b6f0 557 devpriv->hwdmaptr[devpriv->next_dma_buf]);
4da6a1d8
MD
558 if (devpriv->dma_runs_to_end || devpriv->neverending_ai) {
559 set_dma_count(devpriv->dma,
0a85b6f0
MT
560 devpriv->hwdmasize[devpriv->
561 next_dma_buf]);
4da6a1d8
MD
562 } else {
563 set_dma_count(devpriv->dma, devpriv->last_dma_run);
564 }
565 release_dma_lock(flags);
566 enable_dma(devpriv->dma);
567 }
5f74ea14 568 printk("comedi: A/D mode1/3 IRQ \n");
4da6a1d8
MD
569
570 devpriv->dma_runs_to_end--;
571 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
0a85b6f0 572 ptr = (short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
4da6a1d8
MD
573
574 len = devpriv->hwdmasize[0] >> 1;
575 bufptr = 0;
576
577 for (i = 0; i < len; i++) {
0109253d 578 if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
5f74ea14 579 printk
0a85b6f0
MT
580 ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
581 (ptr[bufptr] & 0xf),
582 devpriv->act_chanlist[devpriv->act_chanlist_pos],
583 devpriv->act_chanlist_pos);
4da6a1d8
MD
584 pcl818_ai_cancel(dev, s);
585 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
586 comedi_event(dev, s);
587 return IRQ_HANDLED;
588 }
589
0109253d 590 comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */
4da6a1d8
MD
591
592 devpriv->act_chanlist_pos++;
fc950139 593 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
4da6a1d8 594 devpriv->act_chanlist_pos = 0;
fc950139 595
b3559cb1
IA
596 s->async->cur_chan++;
597 if (s->async->cur_chan >= devpriv->ai_n_chan) {
598 s->async->cur_chan = 0;
599 devpriv->ai_act_scan--;
600 }
4da6a1d8
MD
601
602 if (!devpriv->neverending_ai)
603 if (devpriv->ai_act_scan == 0) { /* all data sampled */
604 pcl818_ai_cancel(dev, s);
605 s->async->events |= COMEDI_CB_EOA;
606 comedi_event(dev, s);
0109253d 607 /* printk("done int ai13 dma\n"); */
4da6a1d8
MD
608 return IRQ_HANDLED;
609 }
610 }
611
612 if (len > 0)
613 comedi_event(dev, s);
614 return IRQ_HANDLED;
615}
616
617#ifdef unused
618/*
619==============================================================================
620 analog input dma mode 1 & 3 over RTC, 818 cards
621*/
622static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d)
623{
71b5f4f1 624 struct comedi_device *dev = d;
34c43922 625 struct comedi_subdevice *s = dev->subdevices + 0;
4da6a1d8
MD
626 unsigned long tmp;
627 unsigned int top1, top2, i, bufptr;
628 long ofs_dats;
0a85b6f0 629 short *dmabuf = (short *)devpriv->dmabuf[0];
4da6a1d8 630
0109253d 631 /* outb(2,0x378); */
4da6a1d8
MD
632 switch (devpriv->ai_mode) {
633 case INT_TYPE_AI1_DMA_RTC:
634 case INT_TYPE_AI3_DMA_RTC:
635 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
636 mod_timer(&devpriv->rtc_irq_timer,
0a85b6f0 637 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
4da6a1d8
MD
638
639 for (i = 0; i < 10; i++) {
640 top1 = get_dma_residue(devpriv->dma);
641 top2 = get_dma_residue(devpriv->dma);
642 if (top1 == top2)
643 break;
644 }
645
646 if (top1 != top2)
647 return IRQ_HANDLED;
0109253d 648 top1 = devpriv->hwdmasize[0] - top1; /* where is now DMA in buffer */
4da6a1d8 649 top1 >>= 1;
0109253d 650 ofs_dats = top1 - devpriv->last_top_dma; /* new samples from last call */
4da6a1d8
MD
651 if (ofs_dats < 0)
652 ofs_dats = (devpriv->dmasamplsize) + ofs_dats;
653 if (!ofs_dats)
0109253d
BP
654 return IRQ_HANDLED; /* exit=no new samples from last call */
655 /* obsluz data */
4da6a1d8
MD
656 i = devpriv->last_top_dma - 1;
657 i &= (devpriv->dmasamplsize - 1);
658
0109253d 659 if (dmabuf[i] != MAGIC_DMA_WORD) { /* DMA overflow! */
4da6a1d8 660 comedi_error(dev, "A/D mode1/3 DMA buffer overflow!");
5f74ea14 661 /* printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize); */
4da6a1d8
MD
662 pcl818_ai_cancel(dev, s);
663 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
664 comedi_event(dev, s);
665 return IRQ_HANDLED;
666 }
5f74ea14 667 /* printk("r %ld ",ofs_dats); */
4da6a1d8
MD
668
669 bufptr = devpriv->last_top_dma;
670
671 for (i = 0; i < ofs_dats; i++) {
0109253d 672 if ((dmabuf[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
5f74ea14 673 printk
0a85b6f0
MT
674 ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",
675 (dmabuf[bufptr] & 0xf),
676 devpriv->
677 act_chanlist[devpriv->act_chanlist_pos]);
4da6a1d8
MD
678 pcl818_ai_cancel(dev, s);
679 s->async->events |=
0a85b6f0 680 COMEDI_CB_EOA | COMEDI_CB_ERROR;
4da6a1d8
MD
681 comedi_event(dev, s);
682 return IRQ_HANDLED;
683 }
684
0109253d 685 comedi_buf_put(s->async, dmabuf[bufptr++] >> 4); /* get one sample */
4da6a1d8
MD
686 bufptr &= (devpriv->dmasamplsize - 1);
687
b3559cb1
IA
688 devpriv->act_chanlist_pos++;
689 if (devpriv->act_chanlist_pos >=
690 devpriv->act_chanlist_len) {
691 devpriv->act_chanlist_pos = 0;
692 }
693 s->async->cur_chan++;
694 if (s->async->cur_chan >= devpriv->ai_n_chan) {
695 s->async->cur_chan = 0;
4da6a1d8
MD
696 devpriv->ai_act_scan--;
697 }
698
699 if (!devpriv->neverending_ai)
700 if (devpriv->ai_act_scan == 0) { /* all data sampled */
701 pcl818_ai_cancel(dev, s);
702 s->async->events |= COMEDI_CB_EOA;
703 comedi_event(dev, s);
0109253d 704 /* printk("done int ai13 dma\n"); */
4da6a1d8
MD
705 return IRQ_HANDLED;
706 }
707 }
708
709 devpriv->last_top_dma = bufptr;
710 bufptr--;
711 bufptr &= (devpriv->dmasamplsize - 1);
712 dmabuf[bufptr] = MAGIC_DMA_WORD;
713 comedi_event(dev, s);
0109253d 714 /* outb(0,0x378); */
4da6a1d8
MD
715 return IRQ_HANDLED;
716 }
717
0109253d 718 /* outb(0,0x378); */
4da6a1d8
MD
719 return IRQ_HANDLED;
720}
721#endif
722
723/*
724==============================================================================
725 analog input interrupt mode 1 & 3, 818HD/HG cards
726*/
727static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
728{
71b5f4f1 729 struct comedi_device *dev = d;
34c43922 730 struct comedi_subdevice *s = dev->subdevices + 0;
4da6a1d8
MD
731 int i, len, lo;
732
0109253d 733 outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */
4da6a1d8
MD
734
735 lo = inb(dev->iobase + PCL818_FI_STATUS);
736
737 if (lo & 4) {
738 comedi_error(dev, "A/D mode1/3 FIFO overflow!");
739 pcl818_ai_cancel(dev, s);
740 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
741 comedi_event(dev, s);
742 return IRQ_HANDLED;
743 }
744
745 if (lo & 1) {
746 comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!");
747 pcl818_ai_cancel(dev, s);
748 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
749 comedi_event(dev, s);
750 return IRQ_HANDLED;
751 }
752
fc950139 753 if (lo & 2)
4da6a1d8 754 len = 512;
fc950139 755 else
4da6a1d8 756 len = 0;
4da6a1d8
MD
757
758 for (i = 0; i < len; i++) {
759 lo = inb(dev->iobase + PCL818_FI_DATALO);
0109253d 760 if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
5f74ea14 761 printk
0a85b6f0
MT
762 ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
763 (lo & 0xf),
764 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
4da6a1d8
MD
765 pcl818_ai_cancel(dev, s);
766 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
767 comedi_event(dev, s);
768 return IRQ_HANDLED;
769 }
770
0109253d 771 comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */
4da6a1d8 772
b3559cb1 773 devpriv->act_chanlist_pos++;
fc950139 774 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
b3559cb1 775 devpriv->act_chanlist_pos = 0;
fc950139 776
b3559cb1
IA
777 s->async->cur_chan++;
778 if (s->async->cur_chan >= devpriv->ai_n_chan) {
779 s->async->cur_chan = 0;
4da6a1d8
MD
780 devpriv->ai_act_scan--;
781 }
782
783 if (!devpriv->neverending_ai)
784 if (devpriv->ai_act_scan == 0) { /* all data sampled */
785 pcl818_ai_cancel(dev, s);
786 s->async->events |= COMEDI_CB_EOA;
787 comedi_event(dev, s);
788 return IRQ_HANDLED;
789 }
790 }
791
792 if (len > 0)
793 comedi_event(dev, s);
794 return IRQ_HANDLED;
795}
796
797/*
798==============================================================================
799 INT procedure
800*/
70265d24 801static irqreturn_t interrupt_pcl818(int irq, void *d)
4da6a1d8 802{
71b5f4f1 803 struct comedi_device *dev = d;
4da6a1d8
MD
804
805 if (!dev->attached) {
806 comedi_error(dev, "premature interrupt");
807 return IRQ_HANDLED;
808 }
5f74ea14 809 /* printk("I\n"); */
4da6a1d8 810
e21de1a8
IA
811 if (devpriv->irq_blocked && devpriv->irq_was_now_closed) {
812 if ((devpriv->neverending_ai || (!devpriv->neverending_ai &&
0a85b6f0
MT
813 devpriv->ai_act_scan > 0)) &&
814 (devpriv->ai_mode == INT_TYPE_AI1_DMA ||
815 devpriv->ai_mode == INT_TYPE_AI3_DMA)) {
e21de1a8
IA
816 /* The cleanup from ai_cancel() has been delayed
817 until now because the card doesn't seem to like
818 being reprogrammed while a DMA transfer is in
819 progress.
820 */
821 struct comedi_subdevice *s = dev->subdevices + 0;
822 devpriv->ai_act_scan = 0;
823 devpriv->neverending_ai = 0;
824 pcl818_ai_cancel(dev, s);
825 }
826
827 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
828
829 return IRQ_HANDLED;
830 }
831
4da6a1d8
MD
832 switch (devpriv->ai_mode) {
833 case INT_TYPE_AI1_DMA:
834 case INT_TYPE_AI3_DMA:
835 return interrupt_pcl818_ai_mode13_dma(irq, d);
836 case INT_TYPE_AI1_INT:
837 case INT_TYPE_AI3_INT:
838 return interrupt_pcl818_ai_mode13_int(irq, d);
839 case INT_TYPE_AI1_FIFO:
840 case INT_TYPE_AI3_FIFO:
841 return interrupt_pcl818_ai_mode13_fifo(irq, d);
842#ifdef PCL818_MODE13_AO
843 case INT_TYPE_AO1_INT:
844 case INT_TYPE_AO3_INT:
845 return interrupt_pcl818_ao_mode13_int(irq, d);
846#endif
847 default:
848 break;
849 }
850
851 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
852
853 if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked)
0a85b6f0 854 || (!devpriv->ai_mode)) {
4da6a1d8
MD
855 comedi_error(dev, "bad IRQ!");
856 return IRQ_NONE;
857 }
858
bbc9a991 859 comedi_error(dev, "IRQ from unknown source!");
4da6a1d8
MD
860 return IRQ_NONE;
861}
862
863/*
864==============================================================================
865 ANALOG INPUT MODE 1 or 3 DMA , 818 cards
866*/
da91b269 867static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev,
0a85b6f0 868 struct comedi_subdevice *s)
4da6a1d8
MD
869{
870 unsigned int flags;
871 unsigned int bytes;
872
5f74ea14 873 printk("mode13dma_int, mode: %d\n", mode);
0109253d 874 disable_dma(devpriv->dma); /* disable dma */
4da6a1d8
MD
875 bytes = devpriv->hwdmasize[0];
876 if (!devpriv->neverending_ai) {
0109253d
BP
877 bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */
878 devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */
879 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */
4da6a1d8
MD
880 devpriv->dma_runs_to_end--;
881 if (devpriv->dma_runs_to_end >= 0)
882 bytes = devpriv->hwdmasize[0];
883 }
884
885 devpriv->next_dma_buf = 0;
886 set_dma_mode(devpriv->dma, DMA_MODE_READ);
887 flags = claim_dma_lock();
888 clear_dma_ff(devpriv->dma);
889 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
890 set_dma_count(devpriv->dma, bytes);
891 release_dma_lock(flags);
892 enable_dma(devpriv->dma);
893
894 if (mode == 1) {
895 devpriv->ai_mode = INT_TYPE_AI1_DMA;
896 outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */
897 } else {
898 devpriv->ai_mode = INT_TYPE_AI3_DMA;
899 outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */
900 };
901}
902
903#ifdef unused
904/*
905==============================================================================
906 ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards
907*/
da91b269 908static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device *dev,
0a85b6f0 909 struct comedi_subdevice *s)
4da6a1d8
MD
910{
911 unsigned int flags;
790c5541 912 short *pole;
4da6a1d8
MD
913
914 set_dma_mode(devpriv->dma, DMA_MODE_READ | DMA_AUTOINIT);
915 flags = claim_dma_lock();
916 clear_dma_ff(devpriv->dma);
917 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
918 set_dma_count(devpriv->dma, devpriv->hwdmasize[0]);
919 release_dma_lock(flags);
920 enable_dma(devpriv->dma);
0109253d 921 devpriv->last_top_dma = 0; /* devpriv->hwdmasize[0]; */
0a85b6f0 922 pole = (short *)devpriv->dmabuf[0];
4da6a1d8
MD
923 devpriv->dmasamplsize = devpriv->hwdmasize[0] / 2;
924 pole[devpriv->dmasamplsize - 1] = MAGIC_DMA_WORD;
925#ifdef unused
926 devpriv->rtc_freq = rtc_setfreq_irq(2048);
927 devpriv->rtc_irq_timer.expires =
0a85b6f0 928 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100;
4da6a1d8
MD
929 devpriv->rtc_irq_timer.data = (unsigned long)dev;
930 devpriv->rtc_irq_timer.function = rtc_dropped_irq;
931
932 add_timer(&devpriv->rtc_irq_timer);
933#endif
934
935 if (mode == 1) {
936 devpriv->int818_mode = INT_TYPE_AI1_DMA_RTC;
937 outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+DMA */
938 } else {
939 devpriv->int818_mode = INT_TYPE_AI3_DMA_RTC;
940 outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+DMA */
941 };
942}
943#endif
944
945/*
946==============================================================================
947 ANALOG INPUT MODE 1 or 3, 818 cards
948*/
da91b269 949static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
0a85b6f0 950 struct comedi_subdevice *s)
4da6a1d8 951{
ea6d0d4c 952 struct comedi_cmd *cmd = &s->async->cmd;
48b1aff5 953 int divisor1 = 0, divisor2 = 0;
4da6a1d8
MD
954 unsigned int seglen;
955
c62a0ef4 956 dev_dbg(dev->hw_dev, "pcl818_ai_cmd_mode()\n");
4da6a1d8
MD
957 if ((!dev->irq) && (!devpriv->dma_rtc)) {
958 comedi_error(dev, "IRQ not defined!");
959 return -EINVAL;
960 }
961
962 if (devpriv->irq_blocked)
963 return -EBUSY;
964
0109253d 965 start_pacer(dev, -1, 0, 0); /* stop pacer */
4da6a1d8
MD
966
967 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
0a85b6f0 968 devpriv->ai_n_chan);
4da6a1d8
MD
969 if (seglen < 1)
970 return -EINVAL;
971 setup_channel_list(dev, s, devpriv->ai_chanlist,
0a85b6f0 972 devpriv->ai_n_chan, seglen);
4da6a1d8 973
5f74ea14 974 udelay(1);
4da6a1d8
MD
975
976 devpriv->ai_act_scan = devpriv->ai_scans;
977 devpriv->ai_act_chan = 0;
978 devpriv->irq_blocked = 1;
979 devpriv->irq_was_now_closed = 0;
980 devpriv->neverending_ai = 0;
981 devpriv->act_chanlist_pos = 0;
982 devpriv->dma_runs_to_end = 0;
983
984 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
0109253d 985 devpriv->neverending_ai = 1; /* well, user want neverending */
4da6a1d8
MD
986
987 if (mode == 1) {
988 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
0a85b6f0
MT
989 &divisor2, &cmd->convert_arg,
990 TRIG_ROUND_NEAREST);
4da6a1d8
MD
991 if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */
992 divisor1 = 2;
993 divisor2 /= 2;
994 }
995 if (divisor2 == 1) {
996 divisor2 = 2;
997 divisor1 /= 2;
998 }
999 }
1000
1001 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1002
1003 switch (devpriv->dma) {
0109253d 1004 case 1: /* DMA */
4da6a1d8
MD
1005 case 3:
1006 if (devpriv->dma_rtc == 0) {
1007 pcl818_ai_mode13dma_int(mode, dev, s);
1008 }
1009#ifdef unused
1010 else {
1011 pcl818_ai_mode13dma_rtc(mode, dev, s);
1012 }
1013#else
1014 else {
1015 return -EINVAL;
1016 }
1017#endif
1018 break;
a71f18d2
IA
1019 case 0:
1020 if (!devpriv->usefifo) {
1021 /* IRQ */
5f74ea14 1022 /* printk("IRQ\n"); */
a71f18d2
IA
1023 if (mode == 1) {
1024 devpriv->ai_mode = INT_TYPE_AI1_INT;
1025 /* Pacer+IRQ */
0a85b6f0
MT
1026 outb(0x83 | (dev->irq << 4),
1027 dev->iobase + PCL818_CONTROL);
a71f18d2
IA
1028 } else {
1029 devpriv->ai_mode = INT_TYPE_AI3_INT;
1030 /* Ext trig+IRQ */
0a85b6f0
MT
1031 outb(0x82 | (dev->irq << 4),
1032 dev->iobase + PCL818_CONTROL);
a71f18d2 1033 }
4da6a1d8 1034 } else {
a71f18d2
IA
1035 /* FIFO */
1036 /* enable FIFO */
1037 outb(1, dev->iobase + PCL818_FI_ENABLE);
1038 if (mode == 1) {
1039 devpriv->ai_mode = INT_TYPE_AI1_FIFO;
1040 /* Pacer */
1041 outb(0x03, dev->iobase + PCL818_CONTROL);
1042 } else {
1043 devpriv->ai_mode = INT_TYPE_AI3_FIFO;
1044 outb(0x02, dev->iobase + PCL818_CONTROL);
1045 }
1046 }
4da6a1d8
MD
1047 }
1048
1049 start_pacer(dev, mode, divisor1, divisor2);
1050
1051#ifdef unused
1052 switch (devpriv->ai_mode) {
1053 case INT_TYPE_AI1_DMA_RTC:
1054 case INT_TYPE_AI3_DMA_RTC:
1055 set_rtc_irq_bit(1); /* start RTC */
1056 break;
1057 }
1058#endif
c62a0ef4 1059 dev_dbg(dev->hw_dev, "pcl818_ai_cmd_mode() end\n");
4da6a1d8
MD
1060 return 0;
1061}
1062
1063#ifdef unused
1064/*
1065==============================================================================
1066 ANALOG OUTPUT MODE 1 or 3, 818 cards
1067*/
1068#ifdef PCL818_MODE13_AO
0a85b6f0
MT
1069static int pcl818_ao_mode13(int mode, struct comedi_device *dev,
1070 struct comedi_subdevice *s, comedi_trig * it)
4da6a1d8 1071{
48b1aff5 1072 int divisor1 = 0, divisor2 = 0;
4da6a1d8
MD
1073
1074 if (!dev->irq) {
1075 comedi_error(dev, "IRQ not defined!");
1076 return -EINVAL;
1077 }
1078
1079 if (devpriv->irq_blocked)
1080 return -EBUSY;
1081
0109253d 1082 start_pacer(dev, -1, 0, 0); /* stop pacer */
4da6a1d8
MD
1083
1084 devpriv->int13_act_scan = it->n;
1085 devpriv->int13_act_chan = 0;
1086 devpriv->irq_blocked = 1;
1087 devpriv->irq_was_now_closed = 0;
1088 devpriv->neverending_ai = 0;
1089 devpriv->act_chanlist_pos = 0;
1090
1091 if (mode == 1) {
1092 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
0a85b6f0
MT
1093 &divisor2, &it->trigvar,
1094 TRIG_ROUND_NEAREST);
4da6a1d8
MD
1095 if (divisor1 == 1) { /* PCL818 crash if any divisor is set to 1 */
1096 divisor1 = 2;
1097 divisor2 /= 2;
1098 }
1099 if (divisor2 == 1) {
1100 divisor2 = 2;
1101 divisor1 /= 2;
1102 }
1103 }
1104
1105 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1106 if (mode == 1) {
1107 devpriv->int818_mode = INT_TYPE_AO1_INT;
1108 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */
1109 } else {
1110 devpriv->int818_mode = INT_TYPE_AO3_INT;
1111 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */
1112 };
1113
1114 start_pacer(dev, mode, divisor1, divisor2);
1115
1116 return 0;
1117}
1118
1119/*
1120==============================================================================
1121 ANALOG OUTPUT MODE 1, 818 cards
1122*/
0a85b6f0
MT
1123static int pcl818_ao_mode1(struct comedi_device *dev,
1124 struct comedi_subdevice *s, comedi_trig * it)
4da6a1d8
MD
1125{
1126 return pcl818_ao_mode13(1, dev, s, it);
1127}
1128
1129/*
1130==============================================================================
1131 ANALOG OUTPUT MODE 3, 818 cards
1132*/
0a85b6f0
MT
1133static int pcl818_ao_mode3(struct comedi_device *dev,
1134 struct comedi_subdevice *s, comedi_trig * it)
4da6a1d8
MD
1135{
1136 return pcl818_ao_mode13(3, dev, s, it);
1137}
1138#endif
1139#endif
1140
1141/*
1142==============================================================================
1143 Start/stop pacer onboard pacer
1144*/
0a85b6f0
MT
1145static void start_pacer(struct comedi_device *dev, int mode,
1146 unsigned int divisor1, unsigned int divisor2)
4da6a1d8
MD
1147{
1148 outb(0xb4, dev->iobase + PCL818_CTRCTL);
1149 outb(0x74, dev->iobase + PCL818_CTRCTL);
5f74ea14 1150 udelay(1);
4da6a1d8
MD
1151
1152 if (mode == 1) {
1153 outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
1154 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
1155 outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
1156 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
1157 }
1158}
1159
1160/*
1161==============================================================================
1162 Check if channel list from user is builded correctly
1163 If it's ok, then program scan/gain logic
1164*/
0a85b6f0
MT
1165static int check_channel_list(struct comedi_device *dev,
1166 struct comedi_subdevice *s,
1167 unsigned int *chanlist, unsigned int n_chan)
4da6a1d8
MD
1168{
1169 unsigned int chansegment[16];
1170 unsigned int i, nowmustbechan, seglen, segpos;
1171
1172 /* correct channel and range number check itself comedi/range.c */
1173 if (n_chan < 1) {
1174 comedi_error(dev, "range/channel list is empty!");
1175 return 0;
1176 }
1177
1178 if (n_chan > 1) {
25985edc 1179 /* first channel is every time ok */
4da6a1d8 1180 chansegment[0] = chanlist[0];
0109253d 1181 /* build part of chanlist */
4da6a1d8 1182 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
0109253d 1183
5f74ea14 1184 /* printk("%d. %d * %d\n",i,
0109253d
BP
1185 * CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));*/
1186
1187 /* we detect loop, this must by finish */
1188
4da6a1d8
MD
1189 if (chanlist[0] == chanlist[i])
1190 break;
1191 nowmustbechan =
0a85b6f0 1192 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
25985edc 1193 if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */
5f74ea14 1194 printk
25985edc 1195 ("comedi%d: pcl818: channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
0a85b6f0
MT
1196 dev->minor, i, CR_CHAN(chanlist[i]),
1197 nowmustbechan, CR_CHAN(chanlist[0]));
4da6a1d8
MD
1198 return 0;
1199 }
0109253d 1200 /* well, this is next correct channel in list */
4da6a1d8
MD
1201 chansegment[i] = chanlist[i];
1202 }
1203
0109253d 1204 /* check whole chanlist */
4da6a1d8 1205 for (i = 0, segpos = 0; i < n_chan; i++) {
5f74ea14 1206 /* 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 1207 if (chanlist[i] != chansegment[i % seglen]) {
5f74ea14 1208 printk
0a85b6f0
MT
1209 ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1210 dev->minor, i, CR_CHAN(chansegment[i]),
1211 CR_RANGE(chansegment[i]),
1212 CR_AREF(chansegment[i]),
1213 CR_CHAN(chanlist[i % seglen]),
1214 CR_RANGE(chanlist[i % seglen]),
1215 CR_AREF(chansegment[i % seglen]));
0109253d 1216 return 0; /* chan/gain list is strange */
4da6a1d8
MD
1217 }
1218 }
1219 } else {
1220 seglen = 1;
1221 }
5f74ea14 1222 printk("check_channel_list: seglen %d\n", seglen);
4da6a1d8
MD
1223 return seglen;
1224}
1225
0a85b6f0
MT
1226static void setup_channel_list(struct comedi_device *dev,
1227 struct comedi_subdevice *s,
1228 unsigned int *chanlist, unsigned int n_chan,
1229 unsigned int seglen)
4da6a1d8
MD
1230{
1231 int i;
1232
1233 devpriv->act_chanlist_len = seglen;
1234 devpriv->act_chanlist_pos = 0;
1235
0109253d 1236 for (i = 0; i < seglen; i++) { /* store range list to card */
4da6a1d8
MD
1237 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
1238 outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */
1239 outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */
1240 }
1241
5f74ea14 1242 udelay(1);
4da6a1d8
MD
1243
1244 /* select channel interval to scan */
1245 outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen -
0a85b6f0
MT
1246 1] << 4),
1247 dev->iobase + PCL818_MUX);
4da6a1d8
MD
1248}
1249
1250/*
1251==============================================================================
1252 Check if board is switched to SE (1) or DIFF(0) mode
1253*/
1254static int check_single_ended(unsigned int port)
1255{
fc950139 1256 if (inb(port + PCL818_STATUS) & 0x20)
4da6a1d8 1257 return 1;
fc950139 1258 return 0;
4da6a1d8
MD
1259}
1260
1261/*
1262==============================================================================
1263*/
da91b269 1264static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 1265 struct comedi_cmd *cmd)
4da6a1d8
MD
1266{
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) {
1337 if (cmd->convert_arg < this_board->ns_min) {
1338 cmd->convert_arg = this_board->ns_min;
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);
4da6a1d8
MD
1374 if (cmd->convert_arg < this_board->ns_min)
1375 cmd->convert_arg = this_board->ns_min;
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{
0109253d 1522 if (devpriv->usefifo) { /* FIFO shutdown */
4da6a1d8
MD
1523 outb(0, dev->iobase + PCL818_FI_INTCLR);
1524 outb(0, dev->iobase + PCL818_FI_FLUSH);
1525 outb(0, dev->iobase + PCL818_FI_ENABLE);
1526 }
0109253d 1527 outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */
4da6a1d8 1528 outb(0, dev->iobase + PCL818_DA_HI);
5f74ea14 1529 udelay(1);
0109253d 1530 outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */
4da6a1d8 1531 outb(0, dev->iobase + PCL818_DO_LO);
5f74ea14 1532 udelay(1);
4da6a1d8
MD
1533 outb(0, dev->iobase + PCL818_CONTROL);
1534 outb(0, dev->iobase + PCL818_CNTENABLE);
1535 outb(0, dev->iobase + PCL818_MUX);
1536 outb(0, dev->iobase + PCL818_CLRINT);
1537 outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */
1538 outb(0x70, dev->iobase + PCL818_CTRCTL);
1539 outb(0x30, dev->iobase + PCL818_CTRCTL);
1540 if (this_board->is_818) {
1541 outb(0, dev->iobase + PCL818_RANGE);
1542 } else {
1543 outb(0, dev->iobase + PCL718_DA2_LO);
1544 outb(0, dev->iobase + PCL718_DA2_HI);
1545 }
1546}
1547
1548#ifdef unused
1549/*
1550==============================================================================
1551 Enable(1)/disable(0) periodic interrupts from RTC
1552*/
1553static int set_rtc_irq_bit(unsigned char bit)
1554{
1555 unsigned char val;
1556 unsigned long flags;
1557
1558 if (bit == 1) {
1559 RTC_timer_lock++;
1560 if (RTC_timer_lock > 1)
1561 return 0;
1562 } else {
1563 RTC_timer_lock--;
1564 if (RTC_timer_lock < 0)
1565 RTC_timer_lock = 0;
1566 if (RTC_timer_lock > 0)
1567 return 0;
1568 }
1569
1570 save_flags(flags);
1571 cli();
1572 val = CMOS_READ(RTC_CONTROL);
fc950139 1573 if (bit)
4da6a1d8 1574 val |= RTC_PIE;
fc950139 1575 else
4da6a1d8 1576 val &= ~RTC_PIE;
fc950139 1577
4da6a1d8
MD
1578 CMOS_WRITE(val, RTC_CONTROL);
1579 CMOS_READ(RTC_INTR_FLAGS);
1580 restore_flags(flags);
1581 return 0;
1582}
1583
1584/*
1585==============================================================================
1586 Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers)
1587*/
1588static void rtc_dropped_irq(unsigned long data)
1589{
71b5f4f1 1590 struct comedi_device *dev = (void *)data;
4da6a1d8
MD
1591 unsigned long flags, tmp;
1592
1593 switch (devpriv->int818_mode) {
1594 case INT_TYPE_AI1_DMA_RTC:
1595 case INT_TYPE_AI3_DMA_RTC:
1596 mod_timer(&devpriv->rtc_irq_timer,
0a85b6f0 1597 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
4da6a1d8
MD
1598 save_flags(flags);
1599 cli();
1600 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */
1601 restore_flags(flags);
1602 break;
95cd17c9 1603 }
4da6a1d8
MD
1604}
1605
1606/*
1607==============================================================================
1608 Set frequency of interrupts from RTC
1609*/
1610static int rtc_setfreq_irq(int freq)
1611{
1612 int tmp = 0;
1613 int rtc_freq;
1614 unsigned char val;
1615 unsigned long flags;
1616
1617 if (freq < 2)
1618 freq = 2;
1619 if (freq > 8192)
1620 freq = 8192;
1621
1622 while (freq > (1 << tmp))
1623 tmp++;
1624
1625 rtc_freq = 1 << tmp;
1626
1627 save_flags(flags);
1628 cli();
1629 val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
1630 val |= (16 - tmp);
1631 CMOS_WRITE(val, RTC_FREQ_SELECT);
1632 restore_flags(flags);
1633 return rtc_freq;
1634}
1635#endif
1636
1637/*
1638==============================================================================
1639 Free any resources that we have claimed
1640*/
da91b269 1641static void free_resources(struct comedi_device *dev)
4da6a1d8 1642{
5f74ea14 1643 /* printk("free_resource()\n"); */
4da6a1d8
MD
1644 if (dev->private) {
1645 pcl818_ai_cancel(dev, devpriv->sub_ai);
1646 pcl818_reset(dev);
1647 if (devpriv->dma)
1648 free_dma(devpriv->dma);
1649 if (devpriv->dmabuf[0])
1650 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1651 if (devpriv->dmabuf[1])
1652 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1653#ifdef unused
1654 if (devpriv->rtc_irq)
5f74ea14 1655 free_irq(devpriv->rtc_irq, dev);
4da6a1d8
MD
1656 if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1657 if (devpriv->rtc_iobase)
1658 release_region(devpriv->rtc_iobase,
0a85b6f0 1659 devpriv->rtc_iosize);
4da6a1d8
MD
1660 }
1661 if (devpriv->dma_rtc)
1662 RTC_lock--;
1663#endif
1664 }
1665
1666 if (dev->irq)
1667 free_irq(dev->irq, dev);
1668 if (dev->iobase)
1669 release_region(dev->iobase, devpriv->io_range);
5f74ea14 1670 /* printk("free_resource() end\n"); */
4da6a1d8
MD
1671}
1672
da91b269 1673static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
4da6a1d8
MD
1674{
1675 int ret;
1676 unsigned long iobase;
a71f18d2
IA
1677 unsigned int irq;
1678 int dma;
4da6a1d8 1679 unsigned long pages;
34c43922 1680 struct comedi_subdevice *s;
4da6a1d8 1681
c3744138
BP
1682 ret = alloc_private(dev, sizeof(struct pcl818_private));
1683 if (ret < 0)
4da6a1d8
MD
1684 return ret; /* Can't alloc mem */
1685
1686 /* claim our I/O space */
1687 iobase = it->options[0];
26ba666c
RM
1688 printk
1689 ("comedi%d: pcl818: board=%s, ioport=0x%03lx",
1690 dev->minor, this_board->name, iobase);
4da6a1d8 1691 devpriv->io_range = this_board->io_range;
0109253d 1692 if ((this_board->fifo) && (it->options[2] == -1)) { /* we've board with FIFO and we want to use FIFO */
4da6a1d8
MD
1693 devpriv->io_range = PCLx1xFIFO_RANGE;
1694 devpriv->usefifo = 1;
1695 }
1696 if (!request_region(iobase, devpriv->io_range, "pcl818")) {
26ba666c 1697 comedi_error(dev, "I/O port conflict\n");
4da6a1d8
MD
1698 return -EIO;
1699 }
1700
1701 dev->iobase = iobase;
1702
1703 if (pcl818_check(iobase)) {
26ba666c 1704 comedi_error(dev, "I can't detect board. FAIL!\n");
4da6a1d8
MD
1705 return -EIO;
1706 }
1707
1708 /* set up some name stuff */
1709 dev->board_name = this_board->name;
1710 /* grab our IRQ */
1711 irq = 0;
1712 if (this_board->IRQbits != 0) { /* board support IRQ */
1713 irq = it->options[1];
1714 if (irq) { /* we want to use IRQ */
1715 if (((1 << irq) & this_board->IRQbits) == 0) {
5f74ea14 1716 printk
0a85b6f0
MT
1717 (", IRQ %u is out of allowed range, DISABLING IT",
1718 irq);
4da6a1d8
MD
1719 irq = 0; /* Bad IRQ */
1720 } else {
0a85b6f0
MT
1721 if (request_irq
1722 (irq, interrupt_pcl818, 0, "pcl818", dev)) {
5f74ea14 1723 printk
0a85b6f0
MT
1724 (", unable to allocate IRQ %u, DISABLING IT",
1725 irq);
4da6a1d8
MD
1726 irq = 0; /* Can't use IRQ */
1727 } else {
26ba666c 1728 printk(KERN_DEBUG "irq=%u", irq);
4da6a1d8
MD
1729 }
1730 }
1731 }
1732 }
1733
1734 dev->irq = irq;
fc950139
RM
1735 if (irq)
1736 devpriv->irq_free = 1; /* 1=we have allocated irq */
1737 else
4da6a1d8 1738 devpriv->irq_free = 0;
fc950139 1739
4da6a1d8
MD
1740 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
1741 devpriv->ai_mode = 0; /* mode of irq */
1742
1743#ifdef unused
1744 /* grab RTC for DMA operations */
1745 devpriv->dma_rtc = 0;
0109253d 1746 if (it->options[2] > 0) { /* we want to use DMA */
4da6a1d8
MD
1747 if (RTC_lock == 0) {
1748 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
0a85b6f0 1749 "pcl818 (RTC)"))
4da6a1d8
MD
1750 goto no_rtc;
1751 }
1752 devpriv->rtc_iobase = RTC_PORT(0);
1753 devpriv->rtc_iosize = RTC_IO_EXTENT;
1754 RTC_lock++;
5f74ea14 1755 if (!request_irq(RTC_IRQ, interrupt_pcl818_ai_mode13_dma_rtc, 0,
0a85b6f0 1756 "pcl818 DMA (RTC)", dev)) {
4da6a1d8
MD
1757 devpriv->dma_rtc = 1;
1758 devpriv->rtc_irq = RTC_IRQ;
26ba666c 1759 printk(KERN_DEBUG "dma_irq=%u", devpriv->rtc_irq);
4da6a1d8
MD
1760 } else {
1761 RTC_lock--;
1762 if (RTC_lock == 0) {
1763 if (devpriv->rtc_iobase)
1764 release_region(devpriv->rtc_iobase,
0a85b6f0 1765 devpriv->rtc_iosize);
4da6a1d8
MD
1766 }
1767 devpriv->rtc_iobase = 0;
1768 devpriv->rtc_iosize = 0;
1769 }
1770 }
1771
0a85b6f0 1772no_rtc:
4da6a1d8
MD
1773#endif
1774 /* grab our DMA */
1775 dma = 0;
1776 devpriv->dma = dma;
1777 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1778 goto no_dma; /* if we haven't IRQ, we can't use DMA */
1779 if (this_board->DMAbits != 0) { /* board support DMA */
1780 dma = it->options[2];
1781 if (dma < 1)
1782 goto no_dma; /* DMA disabled */
1783 if (((1 << dma) & this_board->DMAbits) == 0) {
408f6bcd 1784 printk(KERN_ERR "DMA is out of allowed range, FAIL!\n");
4da6a1d8
MD
1785 return -EINVAL; /* Bad DMA */
1786 }
1787 ret = request_dma(dma, "pcl818");
408f6bcd 1788 if (ret)
4da6a1d8 1789 return -EBUSY; /* DMA isn't free */
4da6a1d8 1790 devpriv->dma = dma;
4da6a1d8
MD
1791 pages = 2; /* we need 16KB */
1792 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
408f6bcd 1793 if (!devpriv->dmabuf[0])
4da6a1d8
MD
1794 /* maybe experiment with try_to_free_pages() will help .... */
1795 return -EBUSY; /* no buffer :-( */
4da6a1d8
MD
1796 devpriv->dmapages[0] = pages;
1797 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1798 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
5f74ea14 1799 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
0109253d 1800 if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */
4da6a1d8 1801 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
408f6bcd 1802 if (!devpriv->dmabuf[1])
4da6a1d8 1803 return -EBUSY;
4da6a1d8
MD
1804 devpriv->dmapages[1] = pages;
1805 devpriv->hwdmaptr[1] =
0a85b6f0 1806 virt_to_bus((void *)devpriv->dmabuf[1]);
4da6a1d8
MD
1807 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1808 }
1809 }
1810
0a85b6f0 1811no_dma:
4da6a1d8 1812
c3744138
BP
1813 ret = alloc_subdevices(dev, 4);
1814 if (ret < 0)
4da6a1d8
MD
1815 return ret;
1816
1817 s = dev->subdevices + 0;
1818 if (!this_board->n_aichan_se) {
1819 s->type = COMEDI_SUBD_UNUSED;
1820 } else {
1821 s->type = COMEDI_SUBD_AI;
1822 devpriv->sub_ai = s;
1823 s->subdev_flags = SDF_READABLE;
1824 if (check_single_ended(dev->iobase)) {
1825 s->n_chan = this_board->n_aichan_se;
1826 s->subdev_flags |= SDF_COMMON | SDF_GROUND;
1827 printk(", %dchans S.E. DAC", s->n_chan);
1828 } else {
1829 s->n_chan = this_board->n_aichan_diff;
1830 s->subdev_flags |= SDF_DIFF;
1831 printk(", %dchans DIFF DAC", s->n_chan);
1832 }
1833 s->maxdata = this_board->ai_maxdata;
1834 s->len_chanlist = s->n_chan;
1835 s->range_table = this_board->ai_range_type;
1836 s->cancel = pcl818_ai_cancel;
1837 s->insn_read = pcl818_ai_insn_read;
1838 if ((irq) || (devpriv->dma_rtc)) {
1839 dev->read_subdev = s;
1840 s->subdev_flags |= SDF_CMD_READ;
1841 s->do_cmdtest = ai_cmdtest;
1842 s->do_cmd = ai_cmd;
1843 }
1844 if (this_board->is_818) {
1845 if ((it->options[4] == 1) || (it->options[4] == 10))
0109253d 1846 s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */
4da6a1d8
MD
1847 } else {
1848 switch (it->options[4]) {
1849 case 0:
1850 s->range_table = &range_bipolar10;
1851 break;
1852 case 1:
1853 s->range_table = &range_bipolar5;
1854 break;
1855 case 2:
1856 s->range_table = &range_bipolar2_5;
1857 break;
1858 case 3:
1859 s->range_table = &range718_bipolar1;
1860 break;
1861 case 4:
1862 s->range_table = &range718_bipolar0_5;
1863 break;
1864 case 6:
1865 s->range_table = &range_unipolar10;
1866 break;
1867 case 7:
1868 s->range_table = &range_unipolar5;
1869 break;
1870 case 8:
1871 s->range_table = &range718_unipolar2;
1872 break;
1873 case 9:
1874 s->range_table = &range718_unipolar1;
1875 break;
1876 default:
1877 s->range_table = &range_unknown;
1878 break;
1879 }
1880 }
1881 }
1882
1883 s = dev->subdevices + 1;
1884 if (!this_board->n_aochan) {
1885 s->type = COMEDI_SUBD_UNUSED;
1886 } else {
1887 s->type = COMEDI_SUBD_AO;
1888 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1889 s->n_chan = this_board->n_aochan;
1890 s->maxdata = this_board->ao_maxdata;
1891 s->len_chanlist = this_board->n_aochan;
1892 s->range_table = this_board->ao_range_type;
1893 s->insn_read = pcl818_ao_insn_read;
1894 s->insn_write = pcl818_ao_insn_write;
1895#ifdef unused
1896#ifdef PCL818_MODE13_AO
1897 if (irq) {
1898 s->trig[1] = pcl818_ao_mode1;
1899 s->trig[3] = pcl818_ao_mode3;
1900 }
1901#endif
1902#endif
1903 if (this_board->is_818) {
1904 if ((it->options[4] == 1) || (it->options[4] == 10))
1905 s->range_table = &range_unipolar10;
1906 if (it->options[4] == 2)
1907 s->range_table = &range_unknown;
1908 } else {
1909 if ((it->options[5] == 1) || (it->options[5] == 10))
1910 s->range_table = &range_unipolar10;
1911 if (it->options[5] == 2)
1912 s->range_table = &range_unknown;
1913 }
1914 }
1915
1916 s = dev->subdevices + 2;
1917 if (!this_board->n_dichan) {
1918 s->type = COMEDI_SUBD_UNUSED;
1919 } else {
1920 s->type = COMEDI_SUBD_DI;
1921 s->subdev_flags = SDF_READABLE;
1922 s->n_chan = this_board->n_dichan;
1923 s->maxdata = 1;
1924 s->len_chanlist = this_board->n_dichan;
1925 s->range_table = &range_digital;
1926 s->insn_bits = pcl818_di_insn_bits;
1927 }
1928
1929 s = dev->subdevices + 3;
1930 if (!this_board->n_dochan) {
1931 s->type = COMEDI_SUBD_UNUSED;
1932 } else {
1933 s->type = COMEDI_SUBD_DO;
1934 s->subdev_flags = SDF_WRITABLE;
1935 s->n_chan = this_board->n_dochan;
1936 s->maxdata = 1;
1937 s->len_chanlist = this_board->n_dochan;
1938 s->range_table = &range_digital;
1939 s->insn_bits = pcl818_do_insn_bits;
1940 }
1941
1942 /* select 1/10MHz oscilator */
fc950139 1943 if ((it->options[3] == 0) || (it->options[3] == 10))
4da6a1d8 1944 devpriv->i8253_osc_base = 100;
fc950139 1945 else
4da6a1d8 1946 devpriv->i8253_osc_base = 1000;
4da6a1d8
MD
1947
1948 /* max sampling speed */
1949 devpriv->ns_min = this_board->ns_min;
1950
1951 if (!this_board->is_818) {
1952 if ((it->options[6] == 1) || (it->options[6] == 100))
1953 devpriv->ns_min = 10000; /* extended PCL718 to 100kHz DAC */
1954 }
1955
1956 pcl818_reset(dev);
1957
5f74ea14 1958 printk("\n");
4da6a1d8
MD
1959
1960 return 0;
1961}
1962
da91b269 1963static int pcl818_detach(struct comedi_device *dev)
4da6a1d8 1964{
5f74ea14 1965 /* printk("comedi%d: pcl818: remove\n", dev->minor); */
4da6a1d8
MD
1966 free_resources(dev);
1967 return 0;
1968}
90f703d3 1969
f6aafa10
HS
1970static const struct pcl818_board boardtypes[] = {
1971 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
1972 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1973 0x0a, 0xfff, 0xfff, 0, 1},
1974 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
1975 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1976 0x0a, 0xfff, 0xfff, 0, 1},
1977 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
1978 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1979 0x0a, 0xfff, 0xfff, 1, 1},
1980 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
1981 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1982 0x0a, 0xfff, 0xfff, 1, 1},
1983 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
1984 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1985 0x0a, 0xfff, 0xfff, 0, 1},
1986 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
1987 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1988 0x0a, 0xfff, 0xfff, 0, 0},
1989 /* pcm3718 */
1990 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
1991 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1992 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
1993};
1994
1995static struct comedi_driver driver_pcl818 = {
1996 .driver_name = "pcl818",
1997 .module = THIS_MODULE,
1998 .attach = pcl818_attach,
1999 .detach = pcl818_detach,
2000 .board_name = &boardtypes[0].name,
2001 .num_names = ARRAY_SIZE(boardtypes),
2002 .offset = sizeof(struct pcl818_board),
2003};
2004
2005static int __init driver_pcl818_init_module(void)
2006{
2007 return comedi_driver_register(&driver_pcl818);
2008}
2009module_init(driver_pcl818_init_module);
2010
2011static void __exit driver_pcl818_cleanup_module(void)
2012{
2013 comedi_driver_unregister(&driver_pcl818);
2014}
2015module_exit(driver_pcl818_cleanup_module);
2016
90f703d3
AT
2017MODULE_AUTHOR("Comedi http://www.comedi.org");
2018MODULE_DESCRIPTION("Comedi low-level driver");
2019MODULE_LICENSE("GPL");