]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/staging/comedi/drivers/pcl818.c
staging: comedi: pcl816: remove subdevice pointer math
[mirror_ubuntu-hirsute-kernel.git] / drivers / staging / comedi / drivers / pcl818.c
CommitLineData
4da6a1d8
MD
1/*
2 comedi/drivers/pcl818.c
3
4 Author: Michal Dobes <dobes@tesnet.cz>
5
6 hardware driver for Advantech cards:
7 card: PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818, PCL-718
8 driver: pcl818l, pcl818h, pcl818hd, pcl818hg, pcl818, pcl718
9*/
10/*
11Driver: pcl818
12Description: Advantech PCL-818 cards, PCL-718
13Author: Michal Dobes <dobes@tesnet.cz>
14Devices: [Advantech] PCL-818L (pcl818l), PCL-818H (pcl818h),
15 PCL-818HD (pcl818hd), PCL-818HG (pcl818hg), PCL-818 (pcl818),
16 PCL-718 (pcl718)
17Status: works
18
19All cards have 16 SE/8 DIFF ADCs, one or two DACs, 16 DI and 16 DO.
20Differences are only at maximal sample speed, range list and FIFO
21support.
22The driver support AI mode 0, 1, 3 other subdevices (AO, DI, DO) support
23only mode 0. If DMA/FIFO/INT are disabled then AI support only mode 0.
24PCL-818HD and PCL-818HG support 1kword FIFO. Driver support this FIFO
25but this code is untested.
26A word or two about DMA. Driver support DMA operations at two ways:
271) DMA uses two buffers and after one is filled then is generated
28 INT and DMA restart with second buffer. With this mode I'm unable run
29 more that 80Ksamples/secs without data dropouts on K6/233.
302) DMA uses one buffer and run in autoinit mode and the data are
31 from DMA buffer moved on the fly with 2kHz interrupts from RTC.
32 This mode is used if the interrupt 8 is available for allocation.
33 If not, then first DMA mode is used. With this I can run at
34 full speed one card (100ksamples/secs) or two cards with
35 60ksamples/secs each (more is problem on account of ISA limitations).
36 To use this mode you must have compiled kernel with disabled
37 "Enhanced Real Time Clock Support".
38 Maybe you can have problems if you use xntpd or similar.
39 If you've data dropouts with DMA mode 2 then:
40 a) disable IDE DMA
41 b) switch text mode console to fb.
42
43 Options for PCL-818L:
44 [0] - IO Base
45 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
46 [2] - DMA (0=disable, 1, 3)
47 [3] - 0, 10=10MHz clock for 8254
48 1= 1MHz clock for 8254
49 [4] - 0, 5=A/D input -5V.. +5V
50 1, 10=A/D input -10V..+10V
51 [5] - 0, 5=D/A output 0-5V (internal reference -5V)
52 1, 10=D/A output 0-10V (internal reference -10V)
bbc9a991 53 2 =D/A output unknown (external reference)
4da6a1d8
MD
54
55 Options for PCL-818, PCL-818H:
56 [0] - IO Base
57 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
58 [2] - DMA (0=disable, 1, 3)
59 [3] - 0, 10=10MHz clock for 8254
60 1= 1MHz clock for 8254
61 [4] - 0, 5=D/A output 0-5V (internal reference -5V)
62 1, 10=D/A output 0-10V (internal reference -10V)
bbc9a991 63 2 =D/A output unknown (external reference)
4da6a1d8
MD
64
65 Options for PCL-818HD, PCL-818HG:
66 [0] - IO Base
67 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
68 [2] - DMA/FIFO (-1=use FIFO, 0=disable both FIFO and DMA,
69 1=use DMA ch 1, 3=use DMA ch 3)
70 [3] - 0, 10=10MHz clock for 8254
71 1= 1MHz clock for 8254
72 [4] - 0, 5=D/A output 0-5V (internal reference -5V)
73 1, 10=D/A output 0-10V (internal reference -10V)
bbc9a991 74 2 =D/A output unknown (external reference)
4da6a1d8
MD
75
76 Options for PCL-718:
77 [0] - IO Base
78 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
79 [2] - DMA (0=disable, 1, 3)
80 [3] - 0, 10=10MHz clock for 8254
81 1= 1MHz clock for 8254
82 [4] - 0=A/D Range is +/-10V
83 1= +/-5V
84 2= +/-2.5V
85 3= +/-1V
86 4= +/-0.5V
87 5= user defined bipolar
88 6= 0-10V
89 7= 0-5V
90 8= 0-2V
91 9= 0-1V
92 10= user defined unipolar
93 [5] - 0, 5=D/A outputs 0-5V (internal reference -5V)
94 1, 10=D/A outputs 0-10V (internal reference -10V)
bbc9a991 95 2=D/A outputs unknown (external reference)
4da6a1d8
MD
96 [6] - 0, 60=max 60kHz A/D sampling
97 1,100=max 100kHz A/D sampling (PCL-718 with Option 001 installed)
98
99*/
100
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 444{
4da6a1d8 445 data[1] = inb(dev->iobase + PCL818_DI_LO) |
0a85b6f0 446 (inb(dev->iobase + PCL818_DI_HI) << 8);
4da6a1d8 447
a2714e3e 448 return insn->n;
4da6a1d8
MD
449}
450
451/*
452==============================================================================
453 DIGITAL OUTPUT MODE0, 818 cards
454
455 only one sample per call is supported
456*/
0a85b6f0
MT
457static int pcl818_do_insn_bits(struct comedi_device *dev,
458 struct comedi_subdevice *s,
459 struct comedi_insn *insn, unsigned int *data)
4da6a1d8 460{
4da6a1d8
MD
461 s->state &= ~data[0];
462 s->state |= (data[0] & data[1]);
463
464 outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
465 outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
466
467 data[1] = s->state;
468
a2714e3e 469 return insn->n;
4da6a1d8
MD
470}
471
472/*
473==============================================================================
474 analog input interrupt mode 1 & 3, 818 cards
475 one sample per interrupt version
476*/
477static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
478{
71b5f4f1 479 struct comedi_device *dev = d;
34c43922 480 struct comedi_subdevice *s = dev->subdevices + 0;
4da6a1d8
MD
481 int low;
482 int timeout = 50; /* wait max 50us */
483
484 while (timeout--) {
485 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
486 goto conv_finish;
5f74ea14 487 udelay(1);
4da6a1d8
MD
488 }
489 outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */
490 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
491 pcl818_ai_cancel(dev, s);
492 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
493 comedi_event(dev, s);
494 return IRQ_HANDLED;
495
0a85b6f0 496conv_finish:
4da6a1d8 497 low = inb(dev->iobase + PCL818_AD_LO);
0109253d 498 comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */
4da6a1d8
MD
499 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
500
0109253d 501 if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
5f74ea14 502 printk
0a85b6f0
MT
503 ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
504 (low & 0xf),
505 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
4da6a1d8
MD
506 pcl818_ai_cancel(dev, s);
507 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
508 comedi_event(dev, s);
509 return IRQ_HANDLED;
510 }
b3559cb1 511 devpriv->act_chanlist_pos++;
fc950139 512 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
b3559cb1 513 devpriv->act_chanlist_pos = 0;
fc950139 514
b3559cb1
IA
515 s->async->cur_chan++;
516 if (s->async->cur_chan >= devpriv->ai_n_chan) {
5f74ea14 517 /* printk("E"); */
b3559cb1 518 s->async->cur_chan = 0;
4da6a1d8
MD
519 devpriv->ai_act_scan--;
520 }
521
522 if (!devpriv->neverending_ai) {
523 if (devpriv->ai_act_scan == 0) { /* all data sampled */
524 pcl818_ai_cancel(dev, s);
525 s->async->events |= COMEDI_CB_EOA;
526 }
527 }
528 comedi_event(dev, s);
529 return IRQ_HANDLED;
530}
531
532/*
533==============================================================================
534 analog input dma mode 1 & 3, 818 cards
535*/
536static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
537{
71b5f4f1 538 struct comedi_device *dev = d;
34c43922 539 struct comedi_subdevice *s = dev->subdevices + 0;
4da6a1d8
MD
540 int i, len, bufptr;
541 unsigned long flags;
790c5541 542 short *ptr;
4da6a1d8
MD
543
544 disable_dma(devpriv->dma);
545 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
0109253d 546 if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */
4da6a1d8
MD
547 set_dma_mode(devpriv->dma, DMA_MODE_READ);
548 flags = claim_dma_lock();
549 set_dma_addr(devpriv->dma,
0a85b6f0 550 devpriv->hwdmaptr[devpriv->next_dma_buf]);
4da6a1d8
MD
551 if (devpriv->dma_runs_to_end || devpriv->neverending_ai) {
552 set_dma_count(devpriv->dma,
0a85b6f0
MT
553 devpriv->hwdmasize[devpriv->
554 next_dma_buf]);
4da6a1d8
MD
555 } else {
556 set_dma_count(devpriv->dma, devpriv->last_dma_run);
557 }
558 release_dma_lock(flags);
559 enable_dma(devpriv->dma);
560 }
5f74ea14 561 printk("comedi: A/D mode1/3 IRQ \n");
4da6a1d8
MD
562
563 devpriv->dma_runs_to_end--;
564 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
0a85b6f0 565 ptr = (short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
4da6a1d8
MD
566
567 len = devpriv->hwdmasize[0] >> 1;
568 bufptr = 0;
569
570 for (i = 0; i < len; i++) {
0109253d 571 if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
5f74ea14 572 printk
0a85b6f0
MT
573 ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
574 (ptr[bufptr] & 0xf),
575 devpriv->act_chanlist[devpriv->act_chanlist_pos],
576 devpriv->act_chanlist_pos);
4da6a1d8
MD
577 pcl818_ai_cancel(dev, s);
578 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
579 comedi_event(dev, s);
580 return IRQ_HANDLED;
581 }
582
0109253d 583 comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */
4da6a1d8
MD
584
585 devpriv->act_chanlist_pos++;
fc950139 586 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
4da6a1d8 587 devpriv->act_chanlist_pos = 0;
fc950139 588
b3559cb1
IA
589 s->async->cur_chan++;
590 if (s->async->cur_chan >= devpriv->ai_n_chan) {
591 s->async->cur_chan = 0;
592 devpriv->ai_act_scan--;
593 }
4da6a1d8
MD
594
595 if (!devpriv->neverending_ai)
596 if (devpriv->ai_act_scan == 0) { /* all data sampled */
597 pcl818_ai_cancel(dev, s);
598 s->async->events |= COMEDI_CB_EOA;
599 comedi_event(dev, s);
0109253d 600 /* printk("done int ai13 dma\n"); */
4da6a1d8
MD
601 return IRQ_HANDLED;
602 }
603 }
604
605 if (len > 0)
606 comedi_event(dev, s);
607 return IRQ_HANDLED;
608}
609
610#ifdef unused
611/*
612==============================================================================
613 analog input dma mode 1 & 3 over RTC, 818 cards
614*/
615static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d)
616{
71b5f4f1 617 struct comedi_device *dev = d;
34c43922 618 struct comedi_subdevice *s = dev->subdevices + 0;
4da6a1d8
MD
619 unsigned long tmp;
620 unsigned int top1, top2, i, bufptr;
621 long ofs_dats;
0a85b6f0 622 short *dmabuf = (short *)devpriv->dmabuf[0];
4da6a1d8 623
0109253d 624 /* outb(2,0x378); */
4da6a1d8
MD
625 switch (devpriv->ai_mode) {
626 case INT_TYPE_AI1_DMA_RTC:
627 case INT_TYPE_AI3_DMA_RTC:
628 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
629 mod_timer(&devpriv->rtc_irq_timer,
0a85b6f0 630 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
4da6a1d8
MD
631
632 for (i = 0; i < 10; i++) {
633 top1 = get_dma_residue(devpriv->dma);
634 top2 = get_dma_residue(devpriv->dma);
635 if (top1 == top2)
636 break;
637 }
638
639 if (top1 != top2)
640 return IRQ_HANDLED;
0109253d 641 top1 = devpriv->hwdmasize[0] - top1; /* where is now DMA in buffer */
4da6a1d8 642 top1 >>= 1;
0109253d 643 ofs_dats = top1 - devpriv->last_top_dma; /* new samples from last call */
4da6a1d8
MD
644 if (ofs_dats < 0)
645 ofs_dats = (devpriv->dmasamplsize) + ofs_dats;
646 if (!ofs_dats)
0109253d
BP
647 return IRQ_HANDLED; /* exit=no new samples from last call */
648 /* obsluz data */
4da6a1d8
MD
649 i = devpriv->last_top_dma - 1;
650 i &= (devpriv->dmasamplsize - 1);
651
0109253d 652 if (dmabuf[i] != MAGIC_DMA_WORD) { /* DMA overflow! */
4da6a1d8 653 comedi_error(dev, "A/D mode1/3 DMA buffer overflow!");
5f74ea14 654 /* printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize); */
4da6a1d8
MD
655 pcl818_ai_cancel(dev, s);
656 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
657 comedi_event(dev, s);
658 return IRQ_HANDLED;
659 }
5f74ea14 660 /* printk("r %ld ",ofs_dats); */
4da6a1d8
MD
661
662 bufptr = devpriv->last_top_dma;
663
664 for (i = 0; i < ofs_dats; i++) {
0109253d 665 if ((dmabuf[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
5f74ea14 666 printk
0a85b6f0
MT
667 ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",
668 (dmabuf[bufptr] & 0xf),
669 devpriv->
670 act_chanlist[devpriv->act_chanlist_pos]);
4da6a1d8
MD
671 pcl818_ai_cancel(dev, s);
672 s->async->events |=
0a85b6f0 673 COMEDI_CB_EOA | COMEDI_CB_ERROR;
4da6a1d8
MD
674 comedi_event(dev, s);
675 return IRQ_HANDLED;
676 }
677
0109253d 678 comedi_buf_put(s->async, dmabuf[bufptr++] >> 4); /* get one sample */
4da6a1d8
MD
679 bufptr &= (devpriv->dmasamplsize - 1);
680
b3559cb1
IA
681 devpriv->act_chanlist_pos++;
682 if (devpriv->act_chanlist_pos >=
683 devpriv->act_chanlist_len) {
684 devpriv->act_chanlist_pos = 0;
685 }
686 s->async->cur_chan++;
687 if (s->async->cur_chan >= devpriv->ai_n_chan) {
688 s->async->cur_chan = 0;
4da6a1d8
MD
689 devpriv->ai_act_scan--;
690 }
691
692 if (!devpriv->neverending_ai)
693 if (devpriv->ai_act_scan == 0) { /* all data sampled */
694 pcl818_ai_cancel(dev, s);
695 s->async->events |= COMEDI_CB_EOA;
696 comedi_event(dev, s);
0109253d 697 /* printk("done int ai13 dma\n"); */
4da6a1d8
MD
698 return IRQ_HANDLED;
699 }
700 }
701
702 devpriv->last_top_dma = bufptr;
703 bufptr--;
704 bufptr &= (devpriv->dmasamplsize - 1);
705 dmabuf[bufptr] = MAGIC_DMA_WORD;
706 comedi_event(dev, s);
0109253d 707 /* outb(0,0x378); */
4da6a1d8
MD
708 return IRQ_HANDLED;
709 }
710
0109253d 711 /* outb(0,0x378); */
4da6a1d8
MD
712 return IRQ_HANDLED;
713}
714#endif
715
716/*
717==============================================================================
718 analog input interrupt mode 1 & 3, 818HD/HG cards
719*/
720static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
721{
71b5f4f1 722 struct comedi_device *dev = d;
34c43922 723 struct comedi_subdevice *s = dev->subdevices + 0;
4da6a1d8
MD
724 int i, len, lo;
725
0109253d 726 outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */
4da6a1d8
MD
727
728 lo = inb(dev->iobase + PCL818_FI_STATUS);
729
730 if (lo & 4) {
731 comedi_error(dev, "A/D mode1/3 FIFO overflow!");
732 pcl818_ai_cancel(dev, s);
733 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
734 comedi_event(dev, s);
735 return IRQ_HANDLED;
736 }
737
738 if (lo & 1) {
739 comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!");
740 pcl818_ai_cancel(dev, s);
741 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
742 comedi_event(dev, s);
743 return IRQ_HANDLED;
744 }
745
fc950139 746 if (lo & 2)
4da6a1d8 747 len = 512;
fc950139 748 else
4da6a1d8 749 len = 0;
4da6a1d8
MD
750
751 for (i = 0; i < len; i++) {
752 lo = inb(dev->iobase + PCL818_FI_DATALO);
0109253d 753 if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
5f74ea14 754 printk
0a85b6f0
MT
755 ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
756 (lo & 0xf),
757 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
4da6a1d8
MD
758 pcl818_ai_cancel(dev, s);
759 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
760 comedi_event(dev, s);
761 return IRQ_HANDLED;
762 }
763
0109253d 764 comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */
4da6a1d8 765
b3559cb1 766 devpriv->act_chanlist_pos++;
fc950139 767 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
b3559cb1 768 devpriv->act_chanlist_pos = 0;
fc950139 769
b3559cb1
IA
770 s->async->cur_chan++;
771 if (s->async->cur_chan >= devpriv->ai_n_chan) {
772 s->async->cur_chan = 0;
4da6a1d8
MD
773 devpriv->ai_act_scan--;
774 }
775
776 if (!devpriv->neverending_ai)
777 if (devpriv->ai_act_scan == 0) { /* all data sampled */
778 pcl818_ai_cancel(dev, s);
779 s->async->events |= COMEDI_CB_EOA;
780 comedi_event(dev, s);
781 return IRQ_HANDLED;
782 }
783 }
784
785 if (len > 0)
786 comedi_event(dev, s);
787 return IRQ_HANDLED;
788}
789
790/*
791==============================================================================
792 INT procedure
793*/
70265d24 794static irqreturn_t interrupt_pcl818(int irq, void *d)
4da6a1d8 795{
71b5f4f1 796 struct comedi_device *dev = d;
4da6a1d8
MD
797
798 if (!dev->attached) {
799 comedi_error(dev, "premature interrupt");
800 return IRQ_HANDLED;
801 }
5f74ea14 802 /* printk("I\n"); */
4da6a1d8 803
e21de1a8
IA
804 if (devpriv->irq_blocked && devpriv->irq_was_now_closed) {
805 if ((devpriv->neverending_ai || (!devpriv->neverending_ai &&
0a85b6f0
MT
806 devpriv->ai_act_scan > 0)) &&
807 (devpriv->ai_mode == INT_TYPE_AI1_DMA ||
808 devpriv->ai_mode == INT_TYPE_AI3_DMA)) {
e21de1a8
IA
809 /* The cleanup from ai_cancel() has been delayed
810 until now because the card doesn't seem to like
811 being reprogrammed while a DMA transfer is in
812 progress.
813 */
814 struct comedi_subdevice *s = dev->subdevices + 0;
815 devpriv->ai_act_scan = 0;
816 devpriv->neverending_ai = 0;
817 pcl818_ai_cancel(dev, s);
818 }
819
820 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
821
822 return IRQ_HANDLED;
823 }
824
4da6a1d8
MD
825 switch (devpriv->ai_mode) {
826 case INT_TYPE_AI1_DMA:
827 case INT_TYPE_AI3_DMA:
828 return interrupt_pcl818_ai_mode13_dma(irq, d);
829 case INT_TYPE_AI1_INT:
830 case INT_TYPE_AI3_INT:
831 return interrupt_pcl818_ai_mode13_int(irq, d);
832 case INT_TYPE_AI1_FIFO:
833 case INT_TYPE_AI3_FIFO:
834 return interrupt_pcl818_ai_mode13_fifo(irq, d);
835#ifdef PCL818_MODE13_AO
836 case INT_TYPE_AO1_INT:
837 case INT_TYPE_AO3_INT:
838 return interrupt_pcl818_ao_mode13_int(irq, d);
839#endif
840 default:
841 break;
842 }
843
844 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
845
846 if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked)
0a85b6f0 847 || (!devpriv->ai_mode)) {
4da6a1d8
MD
848 comedi_error(dev, "bad IRQ!");
849 return IRQ_NONE;
850 }
851
bbc9a991 852 comedi_error(dev, "IRQ from unknown source!");
4da6a1d8
MD
853 return IRQ_NONE;
854}
855
856/*
857==============================================================================
858 ANALOG INPUT MODE 1 or 3 DMA , 818 cards
859*/
da91b269 860static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev,
0a85b6f0 861 struct comedi_subdevice *s)
4da6a1d8
MD
862{
863 unsigned int flags;
864 unsigned int bytes;
865
5f74ea14 866 printk("mode13dma_int, mode: %d\n", mode);
0109253d 867 disable_dma(devpriv->dma); /* disable dma */
4da6a1d8
MD
868 bytes = devpriv->hwdmasize[0];
869 if (!devpriv->neverending_ai) {
0109253d
BP
870 bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */
871 devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */
872 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */
4da6a1d8
MD
873 devpriv->dma_runs_to_end--;
874 if (devpriv->dma_runs_to_end >= 0)
875 bytes = devpriv->hwdmasize[0];
876 }
877
878 devpriv->next_dma_buf = 0;
879 set_dma_mode(devpriv->dma, DMA_MODE_READ);
880 flags = claim_dma_lock();
881 clear_dma_ff(devpriv->dma);
882 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
883 set_dma_count(devpriv->dma, bytes);
884 release_dma_lock(flags);
885 enable_dma(devpriv->dma);
886
887 if (mode == 1) {
888 devpriv->ai_mode = INT_TYPE_AI1_DMA;
889 outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */
890 } else {
891 devpriv->ai_mode = INT_TYPE_AI3_DMA;
892 outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */
893 };
894}
895
896#ifdef unused
897/*
898==============================================================================
899 ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards
900*/
da91b269 901static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device *dev,
0a85b6f0 902 struct comedi_subdevice *s)
4da6a1d8
MD
903{
904 unsigned int flags;
790c5541 905 short *pole;
4da6a1d8
MD
906
907 set_dma_mode(devpriv->dma, DMA_MODE_READ | DMA_AUTOINIT);
908 flags = claim_dma_lock();
909 clear_dma_ff(devpriv->dma);
910 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
911 set_dma_count(devpriv->dma, devpriv->hwdmasize[0]);
912 release_dma_lock(flags);
913 enable_dma(devpriv->dma);
0109253d 914 devpriv->last_top_dma = 0; /* devpriv->hwdmasize[0]; */
0a85b6f0 915 pole = (short *)devpriv->dmabuf[0];
4da6a1d8
MD
916 devpriv->dmasamplsize = devpriv->hwdmasize[0] / 2;
917 pole[devpriv->dmasamplsize - 1] = MAGIC_DMA_WORD;
918#ifdef unused
919 devpriv->rtc_freq = rtc_setfreq_irq(2048);
920 devpriv->rtc_irq_timer.expires =
0a85b6f0 921 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100;
4da6a1d8
MD
922 devpriv->rtc_irq_timer.data = (unsigned long)dev;
923 devpriv->rtc_irq_timer.function = rtc_dropped_irq;
924
925 add_timer(&devpriv->rtc_irq_timer);
926#endif
927
928 if (mode == 1) {
929 devpriv->int818_mode = INT_TYPE_AI1_DMA_RTC;
930 outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+DMA */
931 } else {
932 devpriv->int818_mode = INT_TYPE_AI3_DMA_RTC;
933 outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+DMA */
934 };
935}
936#endif
937
938/*
939==============================================================================
940 ANALOG INPUT MODE 1 or 3, 818 cards
941*/
da91b269 942static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
0a85b6f0 943 struct comedi_subdevice *s)
4da6a1d8 944{
ea6d0d4c 945 struct comedi_cmd *cmd = &s->async->cmd;
48b1aff5 946 int divisor1 = 0, divisor2 = 0;
4da6a1d8
MD
947 unsigned int seglen;
948
f41ad667 949 dev_dbg(dev->class_dev, "pcl818_ai_cmd_mode()\n");
4da6a1d8
MD
950 if ((!dev->irq) && (!devpriv->dma_rtc)) {
951 comedi_error(dev, "IRQ not defined!");
952 return -EINVAL;
953 }
954
955 if (devpriv->irq_blocked)
956 return -EBUSY;
957
0109253d 958 start_pacer(dev, -1, 0, 0); /* stop pacer */
4da6a1d8
MD
959
960 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
0a85b6f0 961 devpriv->ai_n_chan);
4da6a1d8
MD
962 if (seglen < 1)
963 return -EINVAL;
964 setup_channel_list(dev, s, devpriv->ai_chanlist,
0a85b6f0 965 devpriv->ai_n_chan, seglen);
4da6a1d8 966
5f74ea14 967 udelay(1);
4da6a1d8
MD
968
969 devpriv->ai_act_scan = devpriv->ai_scans;
970 devpriv->ai_act_chan = 0;
971 devpriv->irq_blocked = 1;
972 devpriv->irq_was_now_closed = 0;
973 devpriv->neverending_ai = 0;
974 devpriv->act_chanlist_pos = 0;
975 devpriv->dma_runs_to_end = 0;
976
977 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
0109253d 978 devpriv->neverending_ai = 1; /* well, user want neverending */
4da6a1d8
MD
979
980 if (mode == 1) {
981 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
0a85b6f0
MT
982 &divisor2, &cmd->convert_arg,
983 TRIG_ROUND_NEAREST);
4da6a1d8
MD
984 if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */
985 divisor1 = 2;
986 divisor2 /= 2;
987 }
988 if (divisor2 == 1) {
989 divisor2 = 2;
990 divisor1 /= 2;
991 }
992 }
993
994 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
995
996 switch (devpriv->dma) {
0109253d 997 case 1: /* DMA */
4da6a1d8
MD
998 case 3:
999 if (devpriv->dma_rtc == 0) {
1000 pcl818_ai_mode13dma_int(mode, dev, s);
1001 }
1002#ifdef unused
1003 else {
1004 pcl818_ai_mode13dma_rtc(mode, dev, s);
1005 }
1006#else
1007 else {
1008 return -EINVAL;
1009 }
1010#endif
1011 break;
a71f18d2
IA
1012 case 0:
1013 if (!devpriv->usefifo) {
1014 /* IRQ */
5f74ea14 1015 /* printk("IRQ\n"); */
a71f18d2
IA
1016 if (mode == 1) {
1017 devpriv->ai_mode = INT_TYPE_AI1_INT;
1018 /* Pacer+IRQ */
0a85b6f0
MT
1019 outb(0x83 | (dev->irq << 4),
1020 dev->iobase + PCL818_CONTROL);
a71f18d2
IA
1021 } else {
1022 devpriv->ai_mode = INT_TYPE_AI3_INT;
1023 /* Ext trig+IRQ */
0a85b6f0
MT
1024 outb(0x82 | (dev->irq << 4),
1025 dev->iobase + PCL818_CONTROL);
a71f18d2 1026 }
4da6a1d8 1027 } else {
a71f18d2
IA
1028 /* FIFO */
1029 /* enable FIFO */
1030 outb(1, dev->iobase + PCL818_FI_ENABLE);
1031 if (mode == 1) {
1032 devpriv->ai_mode = INT_TYPE_AI1_FIFO;
1033 /* Pacer */
1034 outb(0x03, dev->iobase + PCL818_CONTROL);
1035 } else {
1036 devpriv->ai_mode = INT_TYPE_AI3_FIFO;
1037 outb(0x02, dev->iobase + PCL818_CONTROL);
1038 }
1039 }
4da6a1d8
MD
1040 }
1041
1042 start_pacer(dev, mode, divisor1, divisor2);
1043
1044#ifdef unused
1045 switch (devpriv->ai_mode) {
1046 case INT_TYPE_AI1_DMA_RTC:
1047 case INT_TYPE_AI3_DMA_RTC:
1048 set_rtc_irq_bit(1); /* start RTC */
1049 break;
1050 }
1051#endif
f41ad667 1052 dev_dbg(dev->class_dev, "pcl818_ai_cmd_mode() end\n");
4da6a1d8
MD
1053 return 0;
1054}
1055
1056#ifdef unused
1057/*
1058==============================================================================
1059 ANALOG OUTPUT MODE 1 or 3, 818 cards
1060*/
1061#ifdef PCL818_MODE13_AO
0a85b6f0
MT
1062static int pcl818_ao_mode13(int mode, struct comedi_device *dev,
1063 struct comedi_subdevice *s, comedi_trig * it)
4da6a1d8 1064{
48b1aff5 1065 int divisor1 = 0, divisor2 = 0;
4da6a1d8
MD
1066
1067 if (!dev->irq) {
1068 comedi_error(dev, "IRQ not defined!");
1069 return -EINVAL;
1070 }
1071
1072 if (devpriv->irq_blocked)
1073 return -EBUSY;
1074
0109253d 1075 start_pacer(dev, -1, 0, 0); /* stop pacer */
4da6a1d8
MD
1076
1077 devpriv->int13_act_scan = it->n;
1078 devpriv->int13_act_chan = 0;
1079 devpriv->irq_blocked = 1;
1080 devpriv->irq_was_now_closed = 0;
1081 devpriv->neverending_ai = 0;
1082 devpriv->act_chanlist_pos = 0;
1083
1084 if (mode == 1) {
1085 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
0a85b6f0
MT
1086 &divisor2, &it->trigvar,
1087 TRIG_ROUND_NEAREST);
4da6a1d8
MD
1088 if (divisor1 == 1) { /* PCL818 crash if any divisor is set to 1 */
1089 divisor1 = 2;
1090 divisor2 /= 2;
1091 }
1092 if (divisor2 == 1) {
1093 divisor2 = 2;
1094 divisor1 /= 2;
1095 }
1096 }
1097
1098 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1099 if (mode == 1) {
1100 devpriv->int818_mode = INT_TYPE_AO1_INT;
1101 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */
1102 } else {
1103 devpriv->int818_mode = INT_TYPE_AO3_INT;
1104 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */
1105 };
1106
1107 start_pacer(dev, mode, divisor1, divisor2);
1108
1109 return 0;
1110}
1111
1112/*
1113==============================================================================
1114 ANALOG OUTPUT MODE 1, 818 cards
1115*/
0a85b6f0
MT
1116static int pcl818_ao_mode1(struct comedi_device *dev,
1117 struct comedi_subdevice *s, comedi_trig * it)
4da6a1d8
MD
1118{
1119 return pcl818_ao_mode13(1, dev, s, it);
1120}
1121
1122/*
1123==============================================================================
1124 ANALOG OUTPUT MODE 3, 818 cards
1125*/
0a85b6f0
MT
1126static int pcl818_ao_mode3(struct comedi_device *dev,
1127 struct comedi_subdevice *s, comedi_trig * it)
4da6a1d8
MD
1128{
1129 return pcl818_ao_mode13(3, dev, s, it);
1130}
1131#endif
1132#endif
1133
1134/*
1135==============================================================================
1136 Start/stop pacer onboard pacer
1137*/
0a85b6f0
MT
1138static void start_pacer(struct comedi_device *dev, int mode,
1139 unsigned int divisor1, unsigned int divisor2)
4da6a1d8
MD
1140{
1141 outb(0xb4, dev->iobase + PCL818_CTRCTL);
1142 outb(0x74, dev->iobase + PCL818_CTRCTL);
5f74ea14 1143 udelay(1);
4da6a1d8
MD
1144
1145 if (mode == 1) {
1146 outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
1147 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
1148 outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
1149 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
1150 }
1151}
1152
1153/*
1154==============================================================================
1155 Check if channel list from user is builded correctly
1156 If it's ok, then program scan/gain logic
1157*/
0a85b6f0
MT
1158static int check_channel_list(struct comedi_device *dev,
1159 struct comedi_subdevice *s,
1160 unsigned int *chanlist, unsigned int n_chan)
4da6a1d8
MD
1161{
1162 unsigned int chansegment[16];
1163 unsigned int i, nowmustbechan, seglen, segpos;
1164
1165 /* correct channel and range number check itself comedi/range.c */
1166 if (n_chan < 1) {
1167 comedi_error(dev, "range/channel list is empty!");
1168 return 0;
1169 }
1170
1171 if (n_chan > 1) {
25985edc 1172 /* first channel is every time ok */
4da6a1d8 1173 chansegment[0] = chanlist[0];
0109253d 1174 /* build part of chanlist */
4da6a1d8 1175 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
0109253d 1176
5f74ea14 1177 /* printk("%d. %d * %d\n",i,
0109253d
BP
1178 * CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));*/
1179
1180 /* we detect loop, this must by finish */
1181
4da6a1d8
MD
1182 if (chanlist[0] == chanlist[i])
1183 break;
1184 nowmustbechan =
0a85b6f0 1185 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
25985edc 1186 if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */
5f74ea14 1187 printk
25985edc 1188 ("comedi%d: pcl818: channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
0a85b6f0
MT
1189 dev->minor, i, CR_CHAN(chanlist[i]),
1190 nowmustbechan, CR_CHAN(chanlist[0]));
4da6a1d8
MD
1191 return 0;
1192 }
0109253d 1193 /* well, this is next correct channel in list */
4da6a1d8
MD
1194 chansegment[i] = chanlist[i];
1195 }
1196
0109253d 1197 /* check whole chanlist */
4da6a1d8 1198 for (i = 0, segpos = 0; i < n_chan; i++) {
5f74ea14 1199 /* 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 1200 if (chanlist[i] != chansegment[i % seglen]) {
5f74ea14 1201 printk
0a85b6f0
MT
1202 ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1203 dev->minor, i, CR_CHAN(chansegment[i]),
1204 CR_RANGE(chansegment[i]),
1205 CR_AREF(chansegment[i]),
1206 CR_CHAN(chanlist[i % seglen]),
1207 CR_RANGE(chanlist[i % seglen]),
1208 CR_AREF(chansegment[i % seglen]));
0109253d 1209 return 0; /* chan/gain list is strange */
4da6a1d8
MD
1210 }
1211 }
1212 } else {
1213 seglen = 1;
1214 }
5f74ea14 1215 printk("check_channel_list: seglen %d\n", seglen);
4da6a1d8
MD
1216 return seglen;
1217}
1218
0a85b6f0
MT
1219static void setup_channel_list(struct comedi_device *dev,
1220 struct comedi_subdevice *s,
1221 unsigned int *chanlist, unsigned int n_chan,
1222 unsigned int seglen)
4da6a1d8
MD
1223{
1224 int i;
1225
1226 devpriv->act_chanlist_len = seglen;
1227 devpriv->act_chanlist_pos = 0;
1228
0109253d 1229 for (i = 0; i < seglen; i++) { /* store range list to card */
4da6a1d8
MD
1230 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
1231 outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */
1232 outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */
1233 }
1234
5f74ea14 1235 udelay(1);
4da6a1d8
MD
1236
1237 /* select channel interval to scan */
1238 outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen -
0a85b6f0
MT
1239 1] << 4),
1240 dev->iobase + PCL818_MUX);
4da6a1d8
MD
1241}
1242
1243/*
1244==============================================================================
1245 Check if board is switched to SE (1) or DIFF(0) mode
1246*/
1247static int check_single_ended(unsigned int port)
1248{
fc950139 1249 if (inb(port + PCL818_STATUS) & 0x20)
4da6a1d8 1250 return 1;
fc950139 1251 return 0;
4da6a1d8
MD
1252}
1253
1254/*
1255==============================================================================
1256*/
da91b269 1257static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 1258 struct comedi_cmd *cmd)
4da6a1d8 1259{
dd8a4b47 1260 const struct pcl818_board *board = comedi_board(dev);
4da6a1d8 1261 int err = 0;
48b1aff5 1262 int tmp, divisor1 = 0, divisor2 = 0;
4da6a1d8
MD
1263
1264 /* step 1: make sure trigger sources are trivially valid */
1265
1266 tmp = cmd->start_src;
1267 cmd->start_src &= TRIG_NOW;
1268 if (!cmd->start_src || tmp != cmd->start_src)
1269 err++;
1270
1271 tmp = cmd->scan_begin_src;
1272 cmd->scan_begin_src &= TRIG_FOLLOW;
1273 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1274 err++;
1275
1276 tmp = cmd->convert_src;
1277 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
1278 if (!cmd->convert_src || tmp != cmd->convert_src)
1279 err++;
1280
1281 tmp = cmd->scan_end_src;
1282 cmd->scan_end_src &= TRIG_COUNT;
1283 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1284 err++;
1285
1286 tmp = cmd->stop_src;
1287 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
1288 if (!cmd->stop_src || tmp != cmd->stop_src)
1289 err++;
1290
fc950139 1291 if (err)
4da6a1d8 1292 return 1;
4da6a1d8
MD
1293
1294 /* step 2: make sure trigger sources are unique and mutually compatible */
1295
4da6a1d8
MD
1296 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
1297 err++;
1298
4da6a1d8
MD
1299 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
1300 err++;
1301
fc950139 1302 if (err)
4da6a1d8 1303 return 2;
4da6a1d8
MD
1304
1305 /* step 3: make sure arguments are trivially compatible */
1306
1307 if (cmd->start_arg != 0) {
1308 cmd->start_arg = 0;
1309 err++;
1310 }
1311
1312 if (cmd->scan_begin_arg != 0) {
1313 cmd->scan_begin_arg = 0;
1314 err++;
1315 }
1316
1317 if (cmd->convert_src == TRIG_TIMER) {
dd8a4b47
HS
1318 if (cmd->convert_arg < board->ns_min) {
1319 cmd->convert_arg = board->ns_min;
4da6a1d8
MD
1320 err++;
1321 }
1322 } else { /* TRIG_EXT */
1323 if (cmd->convert_arg != 0) {
1324 cmd->convert_arg = 0;
1325 err++;
1326 }
1327 }
1328
4da6a1d8
MD
1329 if (cmd->scan_end_arg != cmd->chanlist_len) {
1330 cmd->scan_end_arg = cmd->chanlist_len;
1331 err++;
1332 }
1333 if (cmd->stop_src == TRIG_COUNT) {
1334 if (!cmd->stop_arg) {
1335 cmd->stop_arg = 1;
1336 err++;
1337 }
1338 } else { /* TRIG_NONE */
1339 if (cmd->stop_arg != 0) {
1340 cmd->stop_arg = 0;
1341 err++;
1342 }
1343 }
1344
fc950139 1345 if (err)
4da6a1d8 1346 return 3;
4da6a1d8
MD
1347
1348 /* step 4: fix up any arguments */
1349
1350 if (cmd->convert_src == TRIG_TIMER) {
1351 tmp = cmd->convert_arg;
1352 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
0a85b6f0
MT
1353 &divisor2, &cmd->convert_arg,
1354 cmd->flags & TRIG_ROUND_MASK);
dd8a4b47
HS
1355 if (cmd->convert_arg < board->ns_min)
1356 cmd->convert_arg = board->ns_min;
4da6a1d8
MD
1357 if (tmp != cmd->convert_arg)
1358 err++;
1359 }
1360
fc950139 1361 if (err)
4da6a1d8 1362 return 4;
4da6a1d8
MD
1363
1364 /* step 5: complain about special chanlist considerations */
1365
1366 if (cmd->chanlist) {
1367 if (!check_channel_list(dev, s, cmd->chanlist,
0a85b6f0 1368 cmd->chanlist_len))
0109253d 1369 return 5; /* incorrect channels list */
4da6a1d8
MD
1370 }
1371
1372 return 0;
1373}
1374
1375/*
1376==============================================================================
1377*/
da91b269 1378static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
4da6a1d8 1379{
ea6d0d4c 1380 struct comedi_cmd *cmd = &s->async->cmd;
4da6a1d8
MD
1381 int retval;
1382
f41ad667 1383 dev_dbg(dev->class_dev, "pcl818_ai_cmd()\n");
4da6a1d8
MD
1384 devpriv->ai_n_chan = cmd->chanlist_len;
1385 devpriv->ai_chanlist = cmd->chanlist;
1386 devpriv->ai_flags = cmd->flags;
1387 devpriv->ai_data_len = s->async->prealloc_bufsz;
1388 devpriv->ai_data = s->async->prealloc_buf;
1389 devpriv->ai_timer1 = 0;
1390 devpriv->ai_timer2 = 0;
1391
fc950139 1392 if (cmd->stop_src == TRIG_COUNT)
4da6a1d8 1393 devpriv->ai_scans = cmd->stop_arg;
fc950139 1394 else
4da6a1d8 1395 devpriv->ai_scans = 0;
4da6a1d8 1396
0109253d
BP
1397 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */
1398 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */
4da6a1d8
MD
1399 devpriv->ai_timer1 = cmd->convert_arg;
1400 retval = pcl818_ai_cmd_mode(1, dev, s);
f41ad667 1401 dev_dbg(dev->class_dev, "pcl818_ai_cmd() end\n");
4da6a1d8
MD
1402 return retval;
1403 }
0109253d 1404 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
4da6a1d8
MD
1405 return pcl818_ai_cmd_mode(3, dev, s);
1406 }
1407 }
1408
1409 return -1;
1410}
1411
1412/*
1413==============================================================================
1414 cancel any mode 1-4 AI
1415*/
0a85b6f0
MT
1416static int pcl818_ai_cancel(struct comedi_device *dev,
1417 struct comedi_subdevice *s)
4da6a1d8
MD
1418{
1419 if (devpriv->irq_blocked > 0) {
f41ad667 1420 dev_dbg(dev->class_dev, "pcl818_ai_cancel()\n");
e21de1a8 1421 devpriv->irq_was_now_closed = 1;
4da6a1d8 1422
e21de1a8 1423 switch (devpriv->ai_mode) {
4da6a1d8
MD
1424#ifdef unused
1425 case INT_TYPE_AI1_DMA_RTC:
1426 case INT_TYPE_AI3_DMA_RTC:
0109253d 1427 set_rtc_irq_bit(0); /* stop RTC */
4da6a1d8
MD
1428 del_timer(&devpriv->rtc_irq_timer);
1429#endif
1430 case INT_TYPE_AI1_DMA:
1431 case INT_TYPE_AI3_DMA:
e21de1a8 1432 if (devpriv->neverending_ai ||
0a85b6f0
MT
1433 (!devpriv->neverending_ai &&
1434 devpriv->ai_act_scan > 0)) {
4da6a1d8
MD
1435 /* wait for running dma transfer to end, do cleanup in interrupt */
1436 goto end;
1437 }
1438 disable_dma(devpriv->dma);
1439 case INT_TYPE_AI1_INT:
1440 case INT_TYPE_AI3_INT:
1441 case INT_TYPE_AI1_FIFO:
1442 case INT_TYPE_AI3_FIFO:
1443#ifdef PCL818_MODE13_AO
1444 case INT_TYPE_AO1_INT:
1445 case INT_TYPE_AO3_INT:
1446#endif
1447 outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */
5f74ea14 1448 udelay(1);
4da6a1d8
MD
1449 start_pacer(dev, -1, 0, 0);
1450 outb(0, dev->iobase + PCL818_AD_LO);
1451 inb(dev->iobase + PCL818_AD_LO);
1452 inb(dev->iobase + PCL818_AD_HI);
1453 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
1454 outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */
0109253d 1455 if (devpriv->usefifo) { /* FIFO shutdown */
4da6a1d8
MD
1456 outb(0, dev->iobase + PCL818_FI_INTCLR);
1457 outb(0, dev->iobase + PCL818_FI_FLUSH);
1458 outb(0, dev->iobase + PCL818_FI_ENABLE);
1459 }
1460 devpriv->irq_blocked = 0;
1461 devpriv->last_int_sub = s;
1462 devpriv->neverending_ai = 0;
e21de1a8
IA
1463 devpriv->ai_mode = 0;
1464 devpriv->irq_was_now_closed = 0;
4da6a1d8
MD
1465 break;
1466 }
1467 }
1468
0a85b6f0 1469end:
f41ad667 1470 dev_dbg(dev->class_dev, "pcl818_ai_cancel() end\n");
4da6a1d8
MD
1471 return 0;
1472}
1473
1474/*
1475==============================================================================
1476 chech for PCL818
1477*/
1478static int pcl818_check(unsigned long iobase)
1479{
1480 outb(0x00, iobase + PCL818_MUX);
5f74ea14 1481 udelay(1);
4da6a1d8 1482 if (inb(iobase + PCL818_MUX) != 0x00)
0109253d 1483 return 1; /* there isn't card */
4da6a1d8 1484 outb(0x55, iobase + PCL818_MUX);
5f74ea14 1485 udelay(1);
4da6a1d8 1486 if (inb(iobase + PCL818_MUX) != 0x55)
0109253d 1487 return 1; /* there isn't card */
4da6a1d8 1488 outb(0x00, iobase + PCL818_MUX);
5f74ea14 1489 udelay(1);
4da6a1d8 1490 outb(0x18, iobase + PCL818_CONTROL);
5f74ea14 1491 udelay(1);
4da6a1d8 1492 if (inb(iobase + PCL818_CONTROL) != 0x18)
0109253d
BP
1493 return 1; /* there isn't card */
1494 return 0; /* ok, card exist */
4da6a1d8
MD
1495}
1496
1497/*
1498==============================================================================
1499 reset whole PCL-818 cards
1500*/
da91b269 1501static void pcl818_reset(struct comedi_device *dev)
4da6a1d8 1502{
dd8a4b47
HS
1503 const struct pcl818_board *board = comedi_board(dev);
1504
0109253d 1505 if (devpriv->usefifo) { /* FIFO shutdown */
4da6a1d8
MD
1506 outb(0, dev->iobase + PCL818_FI_INTCLR);
1507 outb(0, dev->iobase + PCL818_FI_FLUSH);
1508 outb(0, dev->iobase + PCL818_FI_ENABLE);
1509 }
0109253d 1510 outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */
4da6a1d8 1511 outb(0, dev->iobase + PCL818_DA_HI);
5f74ea14 1512 udelay(1);
0109253d 1513 outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */
4da6a1d8 1514 outb(0, dev->iobase + PCL818_DO_LO);
5f74ea14 1515 udelay(1);
4da6a1d8
MD
1516 outb(0, dev->iobase + PCL818_CONTROL);
1517 outb(0, dev->iobase + PCL818_CNTENABLE);
1518 outb(0, dev->iobase + PCL818_MUX);
1519 outb(0, dev->iobase + PCL818_CLRINT);
1520 outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */
1521 outb(0x70, dev->iobase + PCL818_CTRCTL);
1522 outb(0x30, dev->iobase + PCL818_CTRCTL);
dd8a4b47 1523 if (board->is_818) {
4da6a1d8
MD
1524 outb(0, dev->iobase + PCL818_RANGE);
1525 } else {
1526 outb(0, dev->iobase + PCL718_DA2_LO);
1527 outb(0, dev->iobase + PCL718_DA2_HI);
1528 }
1529}
1530
1531#ifdef unused
1532/*
1533==============================================================================
1534 Enable(1)/disable(0) periodic interrupts from RTC
1535*/
1536static int set_rtc_irq_bit(unsigned char bit)
1537{
1538 unsigned char val;
1539 unsigned long flags;
1540
1541 if (bit == 1) {
1542 RTC_timer_lock++;
1543 if (RTC_timer_lock > 1)
1544 return 0;
1545 } else {
1546 RTC_timer_lock--;
1547 if (RTC_timer_lock < 0)
1548 RTC_timer_lock = 0;
1549 if (RTC_timer_lock > 0)
1550 return 0;
1551 }
1552
1553 save_flags(flags);
1554 cli();
1555 val = CMOS_READ(RTC_CONTROL);
fc950139 1556 if (bit)
4da6a1d8 1557 val |= RTC_PIE;
fc950139 1558 else
4da6a1d8 1559 val &= ~RTC_PIE;
fc950139 1560
4da6a1d8
MD
1561 CMOS_WRITE(val, RTC_CONTROL);
1562 CMOS_READ(RTC_INTR_FLAGS);
1563 restore_flags(flags);
1564 return 0;
1565}
1566
1567/*
1568==============================================================================
1569 Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers)
1570*/
1571static void rtc_dropped_irq(unsigned long data)
1572{
71b5f4f1 1573 struct comedi_device *dev = (void *)data;
4da6a1d8
MD
1574 unsigned long flags, tmp;
1575
1576 switch (devpriv->int818_mode) {
1577 case INT_TYPE_AI1_DMA_RTC:
1578 case INT_TYPE_AI3_DMA_RTC:
1579 mod_timer(&devpriv->rtc_irq_timer,
0a85b6f0 1580 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
4da6a1d8
MD
1581 save_flags(flags);
1582 cli();
1583 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */
1584 restore_flags(flags);
1585 break;
95cd17c9 1586 }
4da6a1d8
MD
1587}
1588
1589/*
1590==============================================================================
1591 Set frequency of interrupts from RTC
1592*/
1593static int rtc_setfreq_irq(int freq)
1594{
1595 int tmp = 0;
1596 int rtc_freq;
1597 unsigned char val;
1598 unsigned long flags;
1599
1600 if (freq < 2)
1601 freq = 2;
1602 if (freq > 8192)
1603 freq = 8192;
1604
1605 while (freq > (1 << tmp))
1606 tmp++;
1607
1608 rtc_freq = 1 << tmp;
1609
1610 save_flags(flags);
1611 cli();
1612 val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
1613 val |= (16 - tmp);
1614 CMOS_WRITE(val, RTC_FREQ_SELECT);
1615 restore_flags(flags);
1616 return rtc_freq;
1617}
1618#endif
1619
da91b269 1620static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
4da6a1d8 1621{
dd8a4b47 1622 const struct pcl818_board *board = comedi_board(dev);
4da6a1d8
MD
1623 int ret;
1624 unsigned long iobase;
a71f18d2
IA
1625 unsigned int irq;
1626 int dma;
4da6a1d8 1627 unsigned long pages;
34c43922 1628 struct comedi_subdevice *s;
4da6a1d8 1629
c3744138
BP
1630 ret = alloc_private(dev, sizeof(struct pcl818_private));
1631 if (ret < 0)
4da6a1d8
MD
1632 return ret; /* Can't alloc mem */
1633
1634 /* claim our I/O space */
1635 iobase = it->options[0];
26ba666c
RM
1636 printk
1637 ("comedi%d: pcl818: board=%s, ioport=0x%03lx",
dd8a4b47
HS
1638 dev->minor, board->name, iobase);
1639 devpriv->io_range = board->io_range;
1640 if ((board->fifo) && (it->options[2] == -1)) {
1641 /* we've board with FIFO and we want to use FIFO */
4da6a1d8
MD
1642 devpriv->io_range = PCLx1xFIFO_RANGE;
1643 devpriv->usefifo = 1;
1644 }
1645 if (!request_region(iobase, devpriv->io_range, "pcl818")) {
26ba666c 1646 comedi_error(dev, "I/O port conflict\n");
4da6a1d8
MD
1647 return -EIO;
1648 }
1649
1650 dev->iobase = iobase;
1651
1652 if (pcl818_check(iobase)) {
26ba666c 1653 comedi_error(dev, "I can't detect board. FAIL!\n");
4da6a1d8
MD
1654 return -EIO;
1655 }
1656
dd8a4b47
HS
1657 dev->board_name = board->name;
1658
4da6a1d8
MD
1659 /* grab our IRQ */
1660 irq = 0;
dd8a4b47 1661 if (board->IRQbits != 0) { /* board support IRQ */
4da6a1d8
MD
1662 irq = it->options[1];
1663 if (irq) { /* we want to use IRQ */
dd8a4b47 1664 if (((1 << irq) & board->IRQbits) == 0) {
5f74ea14 1665 printk
0a85b6f0
MT
1666 (", IRQ %u is out of allowed range, DISABLING IT",
1667 irq);
4da6a1d8
MD
1668 irq = 0; /* Bad IRQ */
1669 } else {
0a85b6f0
MT
1670 if (request_irq
1671 (irq, interrupt_pcl818, 0, "pcl818", dev)) {
5f74ea14 1672 printk
0a85b6f0
MT
1673 (", unable to allocate IRQ %u, DISABLING IT",
1674 irq);
4da6a1d8
MD
1675 irq = 0; /* Can't use IRQ */
1676 } else {
26ba666c 1677 printk(KERN_DEBUG "irq=%u", irq);
4da6a1d8
MD
1678 }
1679 }
1680 }
1681 }
1682
1683 dev->irq = irq;
fc950139
RM
1684 if (irq)
1685 devpriv->irq_free = 1; /* 1=we have allocated irq */
1686 else
4da6a1d8 1687 devpriv->irq_free = 0;
fc950139 1688
4da6a1d8
MD
1689 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
1690 devpriv->ai_mode = 0; /* mode of irq */
1691
1692#ifdef unused
1693 /* grab RTC for DMA operations */
1694 devpriv->dma_rtc = 0;
0109253d 1695 if (it->options[2] > 0) { /* we want to use DMA */
4da6a1d8
MD
1696 if (RTC_lock == 0) {
1697 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
0a85b6f0 1698 "pcl818 (RTC)"))
4da6a1d8
MD
1699 goto no_rtc;
1700 }
1701 devpriv->rtc_iobase = RTC_PORT(0);
1702 devpriv->rtc_iosize = RTC_IO_EXTENT;
1703 RTC_lock++;
5f74ea14 1704 if (!request_irq(RTC_IRQ, interrupt_pcl818_ai_mode13_dma_rtc, 0,
0a85b6f0 1705 "pcl818 DMA (RTC)", dev)) {
4da6a1d8
MD
1706 devpriv->dma_rtc = 1;
1707 devpriv->rtc_irq = RTC_IRQ;
26ba666c 1708 printk(KERN_DEBUG "dma_irq=%u", devpriv->rtc_irq);
4da6a1d8
MD
1709 } else {
1710 RTC_lock--;
1711 if (RTC_lock == 0) {
1712 if (devpriv->rtc_iobase)
1713 release_region(devpriv->rtc_iobase,
0a85b6f0 1714 devpriv->rtc_iosize);
4da6a1d8
MD
1715 }
1716 devpriv->rtc_iobase = 0;
1717 devpriv->rtc_iosize = 0;
1718 }
1719 }
1720
0a85b6f0 1721no_rtc:
4da6a1d8
MD
1722#endif
1723 /* grab our DMA */
1724 dma = 0;
1725 devpriv->dma = dma;
1726 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1727 goto no_dma; /* if we haven't IRQ, we can't use DMA */
dd8a4b47 1728 if (board->DMAbits != 0) { /* board support DMA */
4da6a1d8
MD
1729 dma = it->options[2];
1730 if (dma < 1)
1731 goto no_dma; /* DMA disabled */
dd8a4b47 1732 if (((1 << dma) & board->DMAbits) == 0) {
408f6bcd 1733 printk(KERN_ERR "DMA is out of allowed range, FAIL!\n");
4da6a1d8
MD
1734 return -EINVAL; /* Bad DMA */
1735 }
1736 ret = request_dma(dma, "pcl818");
408f6bcd 1737 if (ret)
4da6a1d8 1738 return -EBUSY; /* DMA isn't free */
4da6a1d8 1739 devpriv->dma = dma;
4da6a1d8
MD
1740 pages = 2; /* we need 16KB */
1741 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
408f6bcd 1742 if (!devpriv->dmabuf[0])
4da6a1d8
MD
1743 /* maybe experiment with try_to_free_pages() will help .... */
1744 return -EBUSY; /* no buffer :-( */
4da6a1d8
MD
1745 devpriv->dmapages[0] = pages;
1746 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1747 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
5f74ea14 1748 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
0109253d 1749 if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */
4da6a1d8 1750 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
408f6bcd 1751 if (!devpriv->dmabuf[1])
4da6a1d8 1752 return -EBUSY;
4da6a1d8
MD
1753 devpriv->dmapages[1] = pages;
1754 devpriv->hwdmaptr[1] =
0a85b6f0 1755 virt_to_bus((void *)devpriv->dmabuf[1]);
4da6a1d8
MD
1756 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1757 }
1758 }
1759
0a85b6f0 1760no_dma:
4da6a1d8 1761
2f0b9d08 1762 ret = comedi_alloc_subdevices(dev, 4);
8b6c5694 1763 if (ret)
4da6a1d8
MD
1764 return ret;
1765
1766 s = dev->subdevices + 0;
dd8a4b47 1767 if (!board->n_aichan_se) {
4da6a1d8
MD
1768 s->type = COMEDI_SUBD_UNUSED;
1769 } else {
1770 s->type = COMEDI_SUBD_AI;
1771 devpriv->sub_ai = s;
1772 s->subdev_flags = SDF_READABLE;
1773 if (check_single_ended(dev->iobase)) {
dd8a4b47 1774 s->n_chan = board->n_aichan_se;
4da6a1d8
MD
1775 s->subdev_flags |= SDF_COMMON | SDF_GROUND;
1776 printk(", %dchans S.E. DAC", s->n_chan);
1777 } else {
dd8a4b47 1778 s->n_chan = board->n_aichan_diff;
4da6a1d8
MD
1779 s->subdev_flags |= SDF_DIFF;
1780 printk(", %dchans DIFF DAC", s->n_chan);
1781 }
dd8a4b47 1782 s->maxdata = board->ai_maxdata;
4da6a1d8 1783 s->len_chanlist = s->n_chan;
dd8a4b47 1784 s->range_table = board->ai_range_type;
4da6a1d8
MD
1785 s->cancel = pcl818_ai_cancel;
1786 s->insn_read = pcl818_ai_insn_read;
1787 if ((irq) || (devpriv->dma_rtc)) {
1788 dev->read_subdev = s;
1789 s->subdev_flags |= SDF_CMD_READ;
1790 s->do_cmdtest = ai_cmdtest;
1791 s->do_cmd = ai_cmd;
1792 }
dd8a4b47 1793 if (board->is_818) {
4da6a1d8 1794 if ((it->options[4] == 1) || (it->options[4] == 10))
0109253d 1795 s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */
4da6a1d8
MD
1796 } else {
1797 switch (it->options[4]) {
1798 case 0:
1799 s->range_table = &range_bipolar10;
1800 break;
1801 case 1:
1802 s->range_table = &range_bipolar5;
1803 break;
1804 case 2:
1805 s->range_table = &range_bipolar2_5;
1806 break;
1807 case 3:
1808 s->range_table = &range718_bipolar1;
1809 break;
1810 case 4:
1811 s->range_table = &range718_bipolar0_5;
1812 break;
1813 case 6:
1814 s->range_table = &range_unipolar10;
1815 break;
1816 case 7:
1817 s->range_table = &range_unipolar5;
1818 break;
1819 case 8:
1820 s->range_table = &range718_unipolar2;
1821 break;
1822 case 9:
1823 s->range_table = &range718_unipolar1;
1824 break;
1825 default:
1826 s->range_table = &range_unknown;
1827 break;
1828 }
1829 }
1830 }
1831
1832 s = dev->subdevices + 1;
dd8a4b47 1833 if (!board->n_aochan) {
4da6a1d8
MD
1834 s->type = COMEDI_SUBD_UNUSED;
1835 } else {
1836 s->type = COMEDI_SUBD_AO;
1837 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
dd8a4b47
HS
1838 s->n_chan = board->n_aochan;
1839 s->maxdata = board->ao_maxdata;
1840 s->len_chanlist = board->n_aochan;
1841 s->range_table = board->ao_range_type;
4da6a1d8
MD
1842 s->insn_read = pcl818_ao_insn_read;
1843 s->insn_write = pcl818_ao_insn_write;
1844#ifdef unused
1845#ifdef PCL818_MODE13_AO
1846 if (irq) {
1847 s->trig[1] = pcl818_ao_mode1;
1848 s->trig[3] = pcl818_ao_mode3;
1849 }
1850#endif
1851#endif
dd8a4b47 1852 if (board->is_818) {
4da6a1d8
MD
1853 if ((it->options[4] == 1) || (it->options[4] == 10))
1854 s->range_table = &range_unipolar10;
1855 if (it->options[4] == 2)
1856 s->range_table = &range_unknown;
1857 } else {
1858 if ((it->options[5] == 1) || (it->options[5] == 10))
1859 s->range_table = &range_unipolar10;
1860 if (it->options[5] == 2)
1861 s->range_table = &range_unknown;
1862 }
1863 }
1864
1865 s = dev->subdevices + 2;
dd8a4b47 1866 if (!board->n_dichan) {
4da6a1d8
MD
1867 s->type = COMEDI_SUBD_UNUSED;
1868 } else {
1869 s->type = COMEDI_SUBD_DI;
1870 s->subdev_flags = SDF_READABLE;
dd8a4b47 1871 s->n_chan = board->n_dichan;
4da6a1d8 1872 s->maxdata = 1;
dd8a4b47 1873 s->len_chanlist = board->n_dichan;
4da6a1d8
MD
1874 s->range_table = &range_digital;
1875 s->insn_bits = pcl818_di_insn_bits;
1876 }
1877
1878 s = dev->subdevices + 3;
dd8a4b47 1879 if (!board->n_dochan) {
4da6a1d8
MD
1880 s->type = COMEDI_SUBD_UNUSED;
1881 } else {
1882 s->type = COMEDI_SUBD_DO;
1883 s->subdev_flags = SDF_WRITABLE;
dd8a4b47 1884 s->n_chan = board->n_dochan;
4da6a1d8 1885 s->maxdata = 1;
dd8a4b47 1886 s->len_chanlist = board->n_dochan;
4da6a1d8
MD
1887 s->range_table = &range_digital;
1888 s->insn_bits = pcl818_do_insn_bits;
1889 }
1890
1891 /* select 1/10MHz oscilator */
fc950139 1892 if ((it->options[3] == 0) || (it->options[3] == 10))
4da6a1d8 1893 devpriv->i8253_osc_base = 100;
fc950139 1894 else
4da6a1d8 1895 devpriv->i8253_osc_base = 1000;
4da6a1d8
MD
1896
1897 /* max sampling speed */
dd8a4b47 1898 devpriv->ns_min = board->ns_min;
4da6a1d8 1899
dd8a4b47 1900 if (!board->is_818) {
4da6a1d8
MD
1901 if ((it->options[6] == 1) || (it->options[6] == 100))
1902 devpriv->ns_min = 10000; /* extended PCL718 to 100kHz DAC */
1903 }
1904
1905 pcl818_reset(dev);
1906
5f74ea14 1907 printk("\n");
4da6a1d8
MD
1908
1909 return 0;
1910}
1911
484ecc95 1912static void pcl818_detach(struct comedi_device *dev)
4da6a1d8 1913{
484ecc95
HS
1914 if (dev->private) {
1915 pcl818_ai_cancel(dev, devpriv->sub_ai);
1916 pcl818_reset(dev);
1917 if (devpriv->dma)
1918 free_dma(devpriv->dma);
1919 if (devpriv->dmabuf[0])
1920 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1921 if (devpriv->dmabuf[1])
1922 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1923#ifdef unused
1924 if (devpriv->rtc_irq)
1925 free_irq(devpriv->rtc_irq, dev);
1926 if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1927 if (devpriv->rtc_iobase)
1928 release_region(devpriv->rtc_iobase,
1929 devpriv->rtc_iosize);
1930 }
1931 if (devpriv->dma_rtc)
1932 RTC_lock--;
1933#endif
1934 }
1935 if (dev->irq)
1936 free_irq(dev->irq, dev);
1937 if (dev->iobase)
1938 release_region(dev->iobase, devpriv->io_range);
4da6a1d8 1939}
90f703d3 1940
f6aafa10
HS
1941static const struct pcl818_board boardtypes[] = {
1942 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
1943 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1944 0x0a, 0xfff, 0xfff, 0, 1},
1945 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
1946 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1947 0x0a, 0xfff, 0xfff, 0, 1},
1948 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
1949 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1950 0x0a, 0xfff, 0xfff, 1, 1},
1951 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
1952 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1953 0x0a, 0xfff, 0xfff, 1, 1},
1954 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
1955 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1956 0x0a, 0xfff, 0xfff, 0, 1},
1957 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
1958 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1959 0x0a, 0xfff, 0xfff, 0, 0},
1960 /* pcm3718 */
1961 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
1962 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1963 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
1964};
1965
294f930d 1966static struct comedi_driver pcl818_driver = {
f6aafa10
HS
1967 .driver_name = "pcl818",
1968 .module = THIS_MODULE,
1969 .attach = pcl818_attach,
1970 .detach = pcl818_detach,
1971 .board_name = &boardtypes[0].name,
1972 .num_names = ARRAY_SIZE(boardtypes),
1973 .offset = sizeof(struct pcl818_board),
1974};
294f930d 1975module_comedi_driver(pcl818_driver);
f6aafa10 1976
90f703d3
AT
1977MODULE_AUTHOR("Comedi http://www.comedi.org");
1978MODULE_DESCRIPTION("Comedi low-level driver");
1979MODULE_LICENSE("GPL");