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