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