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