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