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