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