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