1 /*
2 comedi/drivers/pcl816.c
3
4 Author: Juan Grigera <juan@grigera.com.ar>
5 based on pcl818 by Michal Dobes <dobes@tesnet.cz> and bits of pcl812
6
7 hardware driver for Advantech cards:
8 card: PCL-816, PCL814B
9 driver: pcl816
10 */
11 /*
12 Driver: pcl816
13 Description: Advantech PCL-816 cards, PCL-814
14 Author: Juan Grigera <juan@grigera.com.ar>
15 Devices: [Advantech] PCL-816 (pcl816), PCL-814B (pcl814b)
16 Status: works
17 Updated: Tue, 2 Apr 2002 23:15:21 -0800
18
19 PCL 816 and 814B have 16 SE/DIFF ADCs, 16 DACs, 16 DI and 16 DO.
20 Differences are at resolution (16 vs 12 bits).
21
22 The driver support AI command mode, other subdevices not written.
23
24 Analog output and digital input and output are not supported.
25
26 Configuration Options:
27 [0] - IO Base
28 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
29 [2] - DMA (0=disable, 1, 3)
30 [3] - 0, 10=10MHz clock for 8254
31 1= 1MHz clock for 8254
32
33 */
34
35 #include "../comedidev.h"
36
37 #include <linux/ioport.h>
38 #include <linux/mc146818rtc.h>
39 #include <linux/gfp.h>
40 #include <linux/delay.h>
41 #include <linux/io.h>
42 #include <asm/dma.h>
43
44 #include "8253.h"
45
46 #define DEBUG(x) x
47
48 /* boards constants */
49 /* IO space len */
50 #define PCLx1x_RANGE 16
51
52 /* #define outb(x,y) printk("OUTB(%x, 200+%d)\n", x,y-0x200); outb(x,y) */
53
54 /* INTEL 8254 counters */
55 #define PCL816_CTR0 4
56 #define PCL816_CTR1 5
57 #define PCL816_CTR2 6
58 /* R: counter read-back register W: counter control */
59 #define PCL816_CTRCTL 7
60
61 /* R: A/D high byte W: A/D range control */
62 #define PCL816_RANGE 9
63 /* W: clear INT request */
64 #define PCL816_CLRINT 10
65 /* R: next mux scan channel W: mux scan channel & range control pointer */
66 #define PCL816_MUX 11
67 /* R/W: operation control register */
68 #define PCL816_CONTROL 12
69
70 /* R: return status byte W: set DMA/IRQ */
71 #define PCL816_STATUS 13
72 #define PCL816_STATUS_DRDY_MASK 0x80
73
74 /* R: low byte of A/D W: soft A/D trigger */
75 #define PCL816_AD_LO 8
76 /* R: high byte of A/D W: A/D range control */
77 #define PCL816_AD_HI 9
78
79 /* type of interrupt handler */
80 #define INT_TYPE_AI1_INT 1
81 #define INT_TYPE_AI1_DMA 2
82 #define INT_TYPE_AI3_INT 4
83 #define INT_TYPE_AI3_DMA 5
84 #ifdef unused
85 #define INT_TYPE_AI1_DMA_RTC 9
86 #define INT_TYPE_AI3_DMA_RTC 10
87
88 /* RTC stuff... */
89 #define RTC_IRQ 8
90 #define RTC_IO_EXTENT 0x10
91 #endif
92
93 #define MAGIC_DMA_WORD 0x5a5a
94
95 static const struct comedi_lrange range_pcl816 = { 8, {
96 BIP_RANGE(10),
97 BIP_RANGE(5),
98 BIP_RANGE(2.5),
99 BIP_RANGE(1.25),
100 UNI_RANGE(10),
101 UNI_RANGE(5),
102 UNI_RANGE(2.5),
103 UNI_RANGE(1.25),
104 }
105 };
106
107 struct pcl816_board {
108
109 const char *name; /* board name */
110 int n_ranges; /* len of range list */
111 int n_aichan; /* num of A/D chans in diferencial mode */
112 unsigned int ai_ns_min; /* minimal allowed delay between samples (in ns) */
113 int n_aochan; /* num of D/A chans */
114 int n_dichan; /* num of DI chans */
115 int n_dochan; /* num of DO chans */
116 const struct comedi_lrange *ai_range_type; /* default A/D rangelist */
117 const struct comedi_lrange *ao_range_type; /* default D/A rangelist */
118 unsigned int io_range; /* len of IO space */
119 unsigned int IRQbits; /* allowed interrupts */
120 unsigned int DMAbits; /* allowed DMA chans */
121 int ai_maxdata; /* maxdata for A/D */
122 int ao_maxdata; /* maxdata for D/A */
123 int ai_chanlist; /* allowed len of channel list A/D */
124 int ao_chanlist; /* allowed len of channel list D/A */
125 int i8254_osc_base; /* 1/frequency of on board oscilator in ns */
126 };
127
128 static const struct pcl816_board boardtypes[] = {
129 {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816,
130 &range_pcl816, PCLx1x_RANGE,
131 0x00fc, /* IRQ mask */
132 0x0a, /* DMA mask */
133 0xffff, /* 16-bit card */
134 0xffff, /* D/A maxdata */
135 1024,
136 1, /* ao chan list */
137 100},
138 {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816,
139 &range_pcl816, PCLx1x_RANGE,
140 0x00fc,
141 0x0a,
142 0x3fff, /* 14 bit card */
143 0x3fff,
144 1024,
145 1,
146 100},
147 };
148
149 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl816_board))
150 #define devpriv ((struct pcl816_private *)dev->private)
151 #define this_board ((const struct pcl816_board *)dev->board_ptr)
152
153 static int pcl816_attach(struct comedi_device *dev,
154 struct comedi_devconfig *it);
155 static int pcl816_detach(struct comedi_device *dev);
156
157 #ifdef unused
158 static int RTC_lock; /* RTC lock */
159 static int RTC_timer_lock; /* RTC int lock */
160 #endif
161
162 static struct comedi_driver driver_pcl816 = {
163 .driver_name = "pcl816",
164 .module = THIS_MODULE,
165 .attach = pcl816_attach,
166 .detach = pcl816_detach,
167 .board_name = &boardtypes[0].name,
168 .num_names = n_boardtypes,
169 .offset = sizeof(struct pcl816_board),
170 };
171
driver_pcl816_init_module(void)172 static int __init driver_pcl816_init_module(void)
173 {
174 return comedi_driver_register(&driver_pcl816);
175 }
176
driver_pcl816_cleanup_module(void)177 static void __exit driver_pcl816_cleanup_module(void)
178 {
179 comedi_driver_unregister(&driver_pcl816);
180 }
181
182 module_init(driver_pcl816_init_module);
183 module_exit(driver_pcl816_cleanup_module);
184
185 struct pcl816_private {
186
187 unsigned int dma; /* used DMA, 0=don't use DMA */
188 int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */
189 #ifdef unused
190 unsigned long rtc_iobase; /* RTC port region */
191 unsigned int rtc_iosize;
192 unsigned int rtc_irq;
193 #endif
194 unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
195 unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */
196 unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
197 unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */
198 unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */
199 unsigned int last_top_dma; /* DMA pointer in last RTC int */
200 int next_dma_buf; /* which DMA buffer will be used next round */
201 long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
202 unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
203
204 unsigned int ai_scans; /* len of scanlist */
205 unsigned char ai_neverending; /* if=1, then we do neverending record (you must use cancel()) */
206 int irq_free; /* 1=have allocated IRQ */
207 int irq_blocked; /* 1=IRQ now uses any subdev */
208 #ifdef unused
209 int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */
210 #endif
211 int irq_was_now_closed; /* when IRQ finish, there's stored int816_mode for last interrupt */
212 int int816_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
213 struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */
214 int ai_act_scan; /* how many scans we finished */
215 unsigned int ai_act_chanlist[16]; /* MUX setting for actual AI operations */
216 unsigned int ai_act_chanlist_len; /* how long is actual MUX list */
217 unsigned int ai_act_chanlist_pos; /* actual position in MUX list */
218 unsigned int ai_n_chan; /* how many channels per scan */
219 unsigned int ai_poll_ptr; /* how many sampes transfer poll */
220 struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */
221 #ifdef unused
222 struct timer_list rtc_irq_timer; /* timer for RTC sanity check */
223 unsigned long rtc_freq; /* RTC int freq */
224 #endif
225 };
226
227 /*
228 ==============================================================================
229 */
230 static int check_channel_list(struct comedi_device *dev,
231 struct comedi_subdevice *s,
232 unsigned int *chanlist, unsigned int chanlen);
233 static void setup_channel_list(struct comedi_device *dev,
234 struct comedi_subdevice *s,
235 unsigned int *chanlist, unsigned int seglen);
236 static int pcl816_ai_cancel(struct comedi_device *dev,
237 struct comedi_subdevice *s);
238 static void start_pacer(struct comedi_device *dev, int mode,
239 unsigned int divisor1, unsigned int divisor2);
240 #ifdef unused
241 static int set_rtc_irq_bit(unsigned char bit);
242 #endif
243
244 static int pcl816_ai_cmdtest(struct comedi_device *dev,
245 struct comedi_subdevice *s,
246 struct comedi_cmd *cmd);
247 static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
248
249 /*
250 ==============================================================================
251 ANALOG INPUT MODE0, 816 cards, slow version
252 */
pcl816_ai_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)253 static int pcl816_ai_insn_read(struct comedi_device *dev,
254 struct comedi_subdevice *s,
255 struct comedi_insn *insn, unsigned int *data)
256 {
257 int n;
258 int timeout;
259
260 DPRINTK("mode 0 analog input\n");
261 /* software trigger, DMA and INT off */
262 outb(0, dev->iobase + PCL816_CONTROL);
263 /* clear INT (conversion end) flag */
264 outb(0, dev->iobase + PCL816_CLRINT);
265
266 /* Set the input channel */
267 outb(CR_CHAN(insn->chanspec) & 0xf, dev->iobase + PCL816_MUX);
268 /* select gain */
269 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE);
270
271 for (n = 0; n < insn->n; n++) {
272
273 outb(0, dev->iobase + PCL816_AD_LO); /* start conversion */
274
275 timeout = 100;
276 while (timeout--) {
277 if (!(inb(dev->iobase + PCL816_STATUS) &
278 PCL816_STATUS_DRDY_MASK)) {
279 /* return read value */
280 data[n] =
281 ((inb(dev->iobase +
282 PCL816_AD_HI) << 8) |
283 (inb(dev->iobase + PCL816_AD_LO)));
284 /* clear INT (conversion end) flag */
285 outb(0, dev->iobase + PCL816_CLRINT);
286 break;
287 }
288 udelay(1);
289 }
290 /* Return timeout error */
291 if (!timeout) {
292 comedi_error(dev, "A/D insn timeout\n");
293 data[0] = 0;
294 /* clear INT (conversion end) flag */
295 outb(0, dev->iobase + PCL816_CLRINT);
296 return -EIO;
297 }
298
299 }
300 return n;
301 }
302
303 /*
304 ==============================================================================
305 analog input interrupt mode 1 & 3, 818 cards
306 one sample per interrupt version
307 */
interrupt_pcl816_ai_mode13_int(int irq,void * d)308 static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d)
309 {
310 struct comedi_device *dev = d;
311 struct comedi_subdevice *s = dev->subdevices + 0;
312 int low, hi;
313 int timeout = 50; /* wait max 50us */
314
315 while (timeout--) {
316 if (!(inb(dev->iobase + PCL816_STATUS) &
317 PCL816_STATUS_DRDY_MASK))
318 break;
319 udelay(1);
320 }
321 if (!timeout) { /* timeout, bail error */
322 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
323 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
324 pcl816_ai_cancel(dev, s);
325 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
326 comedi_event(dev, s);
327 return IRQ_HANDLED;
328
329 }
330
331 /* get the sample */
332 low = inb(dev->iobase + PCL816_AD_LO);
333 hi = inb(dev->iobase + PCL816_AD_HI);
334
335 comedi_buf_put(s->async, (hi << 8) | low);
336
337 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
338
339 if (++devpriv->ai_act_chanlist_pos >= devpriv->ai_act_chanlist_len)
340 devpriv->ai_act_chanlist_pos = 0;
341
342 s->async->cur_chan++;
343 if (s->async->cur_chan >= devpriv->ai_n_chan) {
344 s->async->cur_chan = 0;
345 devpriv->ai_act_scan++;
346 }
347
348 if (!devpriv->ai_neverending)
349 /* all data sampled */
350 if (devpriv->ai_act_scan >= devpriv->ai_scans) {
351 /* all data sampled */
352 pcl816_ai_cancel(dev, s);
353 s->async->events |= COMEDI_CB_EOA;
354 }
355 comedi_event(dev, s);
356 return IRQ_HANDLED;
357 }
358
359 /*
360 ==============================================================================
361 analog input dma mode 1 & 3, 816 cards
362 */
transfer_from_dma_buf(struct comedi_device * dev,struct comedi_subdevice * s,short * ptr,unsigned int bufptr,unsigned int len)363 static void transfer_from_dma_buf(struct comedi_device *dev,
364 struct comedi_subdevice *s, short *ptr,
365 unsigned int bufptr, unsigned int len)
366 {
367 int i;
368
369 s->async->events = 0;
370
371 for (i = 0; i < len; i++) {
372
373 comedi_buf_put(s->async, ptr[bufptr++]);
374
375 if (++devpriv->ai_act_chanlist_pos >=
376 devpriv->ai_act_chanlist_len) {
377 devpriv->ai_act_chanlist_pos = 0;
378 }
379
380 s->async->cur_chan++;
381 if (s->async->cur_chan >= devpriv->ai_n_chan) {
382 s->async->cur_chan = 0;
383 devpriv->ai_act_scan++;
384 }
385
386 if (!devpriv->ai_neverending)
387 /* all data sampled */
388 if (devpriv->ai_act_scan >= devpriv->ai_scans) {
389 pcl816_ai_cancel(dev, s);
390 s->async->events |= COMEDI_CB_EOA;
391 s->async->events |= COMEDI_CB_BLOCK;
392 break;
393 }
394 }
395
396 comedi_event(dev, s);
397 }
398
interrupt_pcl816_ai_mode13_dma(int irq,void * d)399 static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d)
400 {
401 struct comedi_device *dev = d;
402 struct comedi_subdevice *s = dev->subdevices + 0;
403 int len, bufptr, this_dma_buf;
404 unsigned long dma_flags;
405 short *ptr;
406
407 disable_dma(devpriv->dma);
408 this_dma_buf = devpriv->next_dma_buf;
409
410 /* switch dma bufs */
411 if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) {
412
413 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
414 set_dma_mode(devpriv->dma, DMA_MODE_READ);
415 dma_flags = claim_dma_lock();
416 /* clear_dma_ff (devpriv->dma); */
417 set_dma_addr(devpriv->dma,
418 devpriv->hwdmaptr[devpriv->next_dma_buf]);
419 if (devpriv->dma_runs_to_end) {
420 set_dma_count(devpriv->dma,
421 devpriv->hwdmasize[devpriv->
422 next_dma_buf]);
423 } else {
424 set_dma_count(devpriv->dma, devpriv->last_dma_run);
425 }
426 release_dma_lock(dma_flags);
427 enable_dma(devpriv->dma);
428 }
429
430 devpriv->dma_runs_to_end--;
431 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
432
433 ptr = (short *)devpriv->dmabuf[this_dma_buf];
434
435 len = (devpriv->hwdmasize[0] >> 1) - devpriv->ai_poll_ptr;
436 bufptr = devpriv->ai_poll_ptr;
437 devpriv->ai_poll_ptr = 0;
438
439 transfer_from_dma_buf(dev, s, ptr, bufptr, len);
440 return IRQ_HANDLED;
441 }
442
443 /*
444 ==============================================================================
445 INT procedure
446 */
interrupt_pcl816(int irq,void * d)447 static irqreturn_t interrupt_pcl816(int irq, void *d)
448 {
449 struct comedi_device *dev = d;
450 DPRINTK("<I>");
451
452 if (!dev->attached) {
453 comedi_error(dev, "premature interrupt");
454 return IRQ_HANDLED;
455 }
456
457 switch (devpriv->int816_mode) {
458 case INT_TYPE_AI1_DMA:
459 case INT_TYPE_AI3_DMA:
460 return interrupt_pcl816_ai_mode13_dma(irq, d);
461 case INT_TYPE_AI1_INT:
462 case INT_TYPE_AI3_INT:
463 return interrupt_pcl816_ai_mode13_int(irq, d);
464 }
465
466 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
467 if ((!dev->irq) | (!devpriv->irq_free) | (!devpriv->irq_blocked) |
468 (!devpriv->int816_mode)) {
469 if (devpriv->irq_was_now_closed) {
470 devpriv->irq_was_now_closed = 0;
471 /* comedi_error(dev,"last IRQ.."); */
472 return IRQ_HANDLED;
473 }
474 comedi_error(dev, "bad IRQ!");
475 return IRQ_NONE;
476 }
477 comedi_error(dev, "IRQ from unknown source!");
478 return IRQ_NONE;
479 }
480
481 /*
482 ==============================================================================
483 COMMAND MODE
484 */
pcl816_cmdtest_out(int e,struct comedi_cmd * cmd)485 static void pcl816_cmdtest_out(int e, struct comedi_cmd *cmd)
486 {
487 printk(KERN_INFO "pcl816 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
488 cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
489 printk(KERN_INFO "pcl816 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
490 cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
491 printk(KERN_INFO "pcl816 e=%d stopsrc=%x scanend=%x\n", e,
492 cmd->stop_src, cmd->scan_end_src);
493 printk(KERN_INFO "pcl816 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
494 e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
495 }
496
497 /*
498 ==============================================================================
499 */
pcl816_ai_cmdtest(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)500 static int pcl816_ai_cmdtest(struct comedi_device *dev,
501 struct comedi_subdevice *s, struct comedi_cmd *cmd)
502 {
503 int err = 0;
504 int tmp, divisor1 = 0, divisor2 = 0;
505
506 DEBUG(printk(KERN_INFO "pcl816 pcl812_ai_cmdtest\n");
507 pcl816_cmdtest_out(-1, cmd);
508 );
509
510 /* step 1: make sure trigger sources are trivially valid */
511 tmp = cmd->start_src;
512 cmd->start_src &= TRIG_NOW;
513 if (!cmd->start_src || tmp != cmd->start_src)
514 err++;
515
516 tmp = cmd->scan_begin_src;
517 cmd->scan_begin_src &= TRIG_FOLLOW;
518 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
519 err++;
520
521 tmp = cmd->convert_src;
522 cmd->convert_src &= TRIG_EXT | TRIG_TIMER;
523 if (!cmd->convert_src || tmp != cmd->convert_src)
524 err++;
525
526 tmp = cmd->scan_end_src;
527 cmd->scan_end_src &= TRIG_COUNT;
528 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
529 err++;
530
531 tmp = cmd->stop_src;
532 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
533 if (!cmd->stop_src || tmp != cmd->stop_src)
534 err++;
535
536 if (err)
537 return 1;
538
539
540 /*
541 * step 2: make sure trigger sources
542 * are unique and mutually compatible
543 */
544
545 if (cmd->start_src != TRIG_NOW) {
546 cmd->start_src = TRIG_NOW;
547 err++;
548 }
549
550 if (cmd->scan_begin_src != TRIG_FOLLOW) {
551 cmd->scan_begin_src = TRIG_FOLLOW;
552 err++;
553 }
554
555 if (cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_TIMER) {
556 cmd->convert_src = TRIG_TIMER;
557 err++;
558 }
559
560 if (cmd->scan_end_src != TRIG_COUNT) {
561 cmd->scan_end_src = TRIG_COUNT;
562 err++;
563 }
564
565 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
566 err++;
567
568 if (err)
569 return 2;
570
571
572 /* step 3: make sure arguments are trivially compatible */
573 if (cmd->start_arg != 0) {
574 cmd->start_arg = 0;
575 err++;
576 }
577
578 if (cmd->scan_begin_arg != 0) {
579 cmd->scan_begin_arg = 0;
580 err++;
581 }
582 if (cmd->convert_src == TRIG_TIMER) {
583 if (cmd->convert_arg < this_board->ai_ns_min) {
584 cmd->convert_arg = this_board->ai_ns_min;
585 err++;
586 }
587 } else { /* TRIG_EXT */
588 if (cmd->convert_arg != 0) {
589 cmd->convert_arg = 0;
590 err++;
591 }
592 }
593
594 if (cmd->scan_end_arg != cmd->chanlist_len) {
595 cmd->scan_end_arg = cmd->chanlist_len;
596 err++;
597 }
598 if (cmd->stop_src == TRIG_COUNT) {
599 if (!cmd->stop_arg) {
600 cmd->stop_arg = 1;
601 err++;
602 }
603 } else { /* TRIG_NONE */
604 if (cmd->stop_arg != 0) {
605 cmd->stop_arg = 0;
606 err++;
607 }
608 }
609
610 if (err)
611 return 3;
612
613
614 /* step 4: fix up any arguments */
615 if (cmd->convert_src == TRIG_TIMER) {
616 tmp = cmd->convert_arg;
617 i8253_cascade_ns_to_timer(this_board->i8254_osc_base,
618 &divisor1, &divisor2,
619 &cmd->convert_arg,
620 cmd->flags & TRIG_ROUND_MASK);
621 if (cmd->convert_arg < this_board->ai_ns_min)
622 cmd->convert_arg = this_board->ai_ns_min;
623 if (tmp != cmd->convert_arg)
624 err++;
625 }
626
627 if (err)
628 return 4;
629
630
631 /* step 5: complain about special chanlist considerations */
632
633 if (cmd->chanlist) {
634 if (!check_channel_list(dev, s, cmd->chanlist,
635 cmd->chanlist_len))
636 return 5; /* incorrect channels list */
637 }
638
639 return 0;
640 }
641
pcl816_ai_cmd(struct comedi_device * dev,struct comedi_subdevice * s)642 static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
643 {
644 unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq;
645 struct comedi_cmd *cmd = &s->async->cmd;
646 unsigned int seglen;
647
648 if (cmd->start_src != TRIG_NOW)
649 return -EINVAL;
650 if (cmd->scan_begin_src != TRIG_FOLLOW)
651 return -EINVAL;
652 if (cmd->scan_end_src != TRIG_COUNT)
653 return -EINVAL;
654 if (cmd->scan_end_arg != cmd->chanlist_len)
655 return -EINVAL;
656 /* if(cmd->chanlist_len>MAX_CHANLIST_LEN) return -EINVAL; */
657 if (devpriv->irq_blocked)
658 return -EBUSY;
659
660 if (cmd->convert_src == TRIG_TIMER) {
661 if (cmd->convert_arg < this_board->ai_ns_min)
662 cmd->convert_arg = this_board->ai_ns_min;
663
664 i8253_cascade_ns_to_timer(this_board->i8254_osc_base, &divisor1,
665 &divisor2, &cmd->convert_arg,
666 cmd->flags & TRIG_ROUND_MASK);
667
668 /* PCL816 crash if any divisor is set to 1 */
669 if (divisor1 == 1) {
670 divisor1 = 2;
671 divisor2 /= 2;
672 }
673 if (divisor2 == 1) {
674 divisor2 = 2;
675 divisor1 /= 2;
676 }
677 }
678
679 start_pacer(dev, -1, 0, 0); /* stop pacer */
680
681 seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len);
682 if (seglen < 1)
683 return -EINVAL;
684 setup_channel_list(dev, s, cmd->chanlist, seglen);
685 udelay(1);
686
687 devpriv->ai_n_chan = cmd->chanlist_len;
688 devpriv->ai_act_scan = 0;
689 s->async->cur_chan = 0;
690 devpriv->irq_blocked = 1;
691 devpriv->ai_poll_ptr = 0;
692 devpriv->irq_was_now_closed = 0;
693
694 if (cmd->stop_src == TRIG_COUNT) {
695 devpriv->ai_scans = cmd->stop_arg;
696 devpriv->ai_neverending = 0;
697 } else {
698 devpriv->ai_scans = 0;
699 devpriv->ai_neverending = 1;
700 }
701
702 /* don't we want wake up every scan? */
703 if ((cmd->flags & TRIG_WAKE_EOS)) {
704 printk(KERN_INFO
705 "pl816: You wankt WAKE_EOS but I dont want handle it");
706 /* devpriv->ai_eos=1; */
707 /* if (devpriv->ai_n_chan==1) */
708 /* devpriv->dma=0; // DMA is useless for this situation */
709 }
710
711 if (devpriv->dma) {
712 bytes = devpriv->hwdmasize[0];
713 if (!devpriv->ai_neverending) {
714 /* how many */
715 bytes = s->async->cmd.chanlist_len *
716 s->async->cmd.chanlist_len *
717 sizeof(short);
718
719 /* how many DMA pages we must fill */
720 devpriv->dma_runs_to_end = bytes /
721 devpriv->hwdmasize[0];
722
723 /* on last dma transfer must be moved */
724 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0];
725 devpriv->dma_runs_to_end--;
726 if (devpriv->dma_runs_to_end >= 0)
727 bytes = devpriv->hwdmasize[0];
728 } else
729 devpriv->dma_runs_to_end = -1;
730
731 devpriv->next_dma_buf = 0;
732 set_dma_mode(devpriv->dma, DMA_MODE_READ);
733 dma_flags = claim_dma_lock();
734 clear_dma_ff(devpriv->dma);
735 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
736 set_dma_count(devpriv->dma, bytes);
737 release_dma_lock(dma_flags);
738 enable_dma(devpriv->dma);
739 }
740
741 start_pacer(dev, 1, divisor1, divisor2);
742 dmairq = ((devpriv->dma & 0x3) << 4) | (dev->irq & 0x7);
743
744 switch (cmd->convert_src) {
745 case TRIG_TIMER:
746 devpriv->int816_mode = INT_TYPE_AI1_DMA;
747
748 /* Pacer+IRQ+DMA */
749 outb(0x32, dev->iobase + PCL816_CONTROL);
750
751 /* write irq and DMA to card */
752 outb(dmairq, dev->iobase + PCL816_STATUS);
753 break;
754
755 default:
756 devpriv->int816_mode = INT_TYPE_AI3_DMA;
757
758 /* Ext trig+IRQ+DMA */
759 outb(0x34, dev->iobase + PCL816_CONTROL);
760
761 /* write irq to card */
762 outb(dmairq, dev->iobase + PCL816_STATUS);
763 break;
764 }
765
766 DPRINTK("pcl816 END: pcl812_ai_cmd()\n");
767 return 0;
768 }
769
pcl816_ai_poll(struct comedi_device * dev,struct comedi_subdevice * s)770 static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
771 {
772 unsigned long flags;
773 unsigned int top1, top2, i;
774
775 if (!devpriv->dma)
776 return 0; /* poll is valid only for DMA transfer */
777
778 spin_lock_irqsave(&dev->spinlock, flags);
779
780 for (i = 0; i < 20; i++) {
781 top1 = get_dma_residue(devpriv->dma); /* where is now DMA */
782 top2 = get_dma_residue(devpriv->dma);
783 if (top1 == top2)
784 break;
785 }
786 if (top1 != top2) {
787 spin_unlock_irqrestore(&dev->spinlock, flags);
788 return 0;
789 }
790
791 /* where is now DMA in buffer */
792 top1 = devpriv->hwdmasize[0] - top1;
793 top1 >>= 1; /* sample position */
794 top2 = top1 - devpriv->ai_poll_ptr;
795 if (top2 < 1) { /* no new samples */
796 spin_unlock_irqrestore(&dev->spinlock, flags);
797 return 0;
798 }
799
800 transfer_from_dma_buf(dev, s,
801 (short *)devpriv->dmabuf[devpriv->next_dma_buf],
802 devpriv->ai_poll_ptr, top2);
803
804 devpriv->ai_poll_ptr = top1; /* new buffer position */
805 spin_unlock_irqrestore(&dev->spinlock, flags);
806
807 return s->async->buf_write_count - s->async->buf_read_count;
808 }
809
810 /*
811 ==============================================================================
812 cancel any mode 1-4 AI
813 */
pcl816_ai_cancel(struct comedi_device * dev,struct comedi_subdevice * s)814 static int pcl816_ai_cancel(struct comedi_device *dev,
815 struct comedi_subdevice *s)
816 {
817 /* DEBUG(printk("pcl816_ai_cancel()\n");) */
818
819 if (devpriv->irq_blocked > 0) {
820 switch (devpriv->int816_mode) {
821 #ifdef unused
822 case INT_TYPE_AI1_DMA_RTC:
823 case INT_TYPE_AI3_DMA_RTC:
824 set_rtc_irq_bit(0); /* stop RTC */
825 del_timer(&devpriv->rtc_irq_timer);
826 #endif
827 case INT_TYPE_AI1_DMA:
828 case INT_TYPE_AI3_DMA:
829 disable_dma(devpriv->dma);
830 case INT_TYPE_AI1_INT:
831 case INT_TYPE_AI3_INT:
832 outb(inb(dev->iobase + PCL816_CONTROL) & 0x73,
833 dev->iobase + PCL816_CONTROL); /* Stop A/D */
834 udelay(1);
835 outb(0, dev->iobase + PCL816_CONTROL); /* Stop A/D */
836
837 /* Stop pacer */
838 outb(0xb0, dev->iobase + PCL816_CTRCTL);
839 outb(0x70, dev->iobase + PCL816_CTRCTL);
840 outb(0, dev->iobase + PCL816_AD_LO);
841 inb(dev->iobase + PCL816_AD_LO);
842 inb(dev->iobase + PCL816_AD_HI);
843
844 /* clear INT request */
845 outb(0, dev->iobase + PCL816_CLRINT);
846
847 /* Stop A/D */
848 outb(0, dev->iobase + PCL816_CONTROL);
849 devpriv->irq_blocked = 0;
850 devpriv->irq_was_now_closed = devpriv->int816_mode;
851 devpriv->int816_mode = 0;
852 devpriv->last_int_sub = s;
853 /* s->busy = 0; */
854 break;
855 }
856 }
857
858 DEBUG(printk("comedi: pcl816_ai_cancel() successful\n");)
859 return 0;
860 }
861
862 /*
863 ==============================================================================
864 chech for PCL816
865 */
pcl816_check(unsigned long iobase)866 static int pcl816_check(unsigned long iobase)
867 {
868 outb(0x00, iobase + PCL816_MUX);
869 udelay(1);
870 if (inb(iobase + PCL816_MUX) != 0x00)
871 return 1; /* there isn't card */
872 outb(0x55, iobase + PCL816_MUX);
873 udelay(1);
874 if (inb(iobase + PCL816_MUX) != 0x55)
875 return 1; /* there isn't card */
876 outb(0x00, iobase + PCL816_MUX);
877 udelay(1);
878 outb(0x18, iobase + PCL816_CONTROL);
879 udelay(1);
880 if (inb(iobase + PCL816_CONTROL) != 0x18)
881 return 1; /* there isn't card */
882 return 0; /* ok, card exist */
883 }
884
885 /*
886 ==============================================================================
887 reset whole PCL-816 cards
888 */
pcl816_reset(struct comedi_device * dev)889 static void pcl816_reset(struct comedi_device *dev)
890 {
891 /* outb (0, dev->iobase + PCL818_DA_LO); DAC=0V */
892 /* outb (0, dev->iobase + PCL818_DA_HI); */
893 /* udelay (1); */
894 /* outb (0, dev->iobase + PCL818_DO_HI); DO=$0000 */
895 /* outb (0, dev->iobase + PCL818_DO_LO); */
896 /* udelay (1); */
897 outb(0, dev->iobase + PCL816_CONTROL);
898 outb(0, dev->iobase + PCL816_MUX);
899 outb(0, dev->iobase + PCL816_CLRINT);
900 outb(0xb0, dev->iobase + PCL816_CTRCTL); /* Stop pacer */
901 outb(0x70, dev->iobase + PCL816_CTRCTL);
902 outb(0x30, dev->iobase + PCL816_CTRCTL);
903 outb(0, dev->iobase + PCL816_RANGE);
904 }
905
906 /*
907 ==============================================================================
908 Start/stop pacer onboard pacer
909 */
910 static void
start_pacer(struct comedi_device * dev,int mode,unsigned int divisor1,unsigned int divisor2)911 start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1,
912 unsigned int divisor2)
913 {
914 outb(0x32, dev->iobase + PCL816_CTRCTL);
915 outb(0xff, dev->iobase + PCL816_CTR0);
916 outb(0x00, dev->iobase + PCL816_CTR0);
917 udelay(1);
918
919 /* set counter 2 as mode 3 */
920 outb(0xb4, dev->iobase + PCL816_CTRCTL);
921 /* set counter 1 as mode 3 */
922 outb(0x74, dev->iobase + PCL816_CTRCTL);
923 udelay(1);
924
925 if (mode == 1) {
926 DPRINTK("mode %d, divisor1 %d, divisor2 %d\n", mode, divisor1,
927 divisor2);
928 outb(divisor2 & 0xff, dev->iobase + PCL816_CTR2);
929 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL816_CTR2);
930 outb(divisor1 & 0xff, dev->iobase + PCL816_CTR1);
931 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL816_CTR1);
932 }
933
934 /* clear pending interrupts (just in case) */
935 /* outb(0, dev->iobase + PCL816_CLRINT); */
936 }
937
938 /*
939 ==============================================================================
940 Check if channel list from user is builded correctly
941 If it's ok, then return non-zero length of repeated segment of channel list
942 */
943 static int
check_channel_list(struct comedi_device * dev,struct comedi_subdevice * s,unsigned int * chanlist,unsigned int chanlen)944 check_channel_list(struct comedi_device *dev,
945 struct comedi_subdevice *s, unsigned int *chanlist,
946 unsigned int chanlen)
947 {
948 unsigned int chansegment[16];
949 unsigned int i, nowmustbechan, seglen, segpos;
950
951 /* correct channel and range number check itself comedi/range.c */
952 if (chanlen < 1) {
953 comedi_error(dev, "range/channel list is empty!");
954 return 0;
955 }
956
957 if (chanlen > 1) {
958 /* first channel is every time ok */
959 chansegment[0] = chanlist[0];
960 for (i = 1, seglen = 1; i < chanlen; i++, seglen++) {
961 /* build part of chanlist */
962 DEBUG(printk(KERN_INFO "%d. %d %d\n", i,
963 CR_CHAN(chanlist[i]),
964 CR_RANGE(chanlist[i]));)
965
966 /* we detect loop, this must by finish */
967 if (chanlist[0] == chanlist[i])
968 break;
969 nowmustbechan =
970 (CR_CHAN(chansegment[i - 1]) + 1) % chanlen;
971 if (nowmustbechan != CR_CHAN(chanlist[i])) {
972 /* channel list isn't continuous :-( */
973 printk(KERN_WARNING
974 "comedi%d: pcl816: channel list must "
975 "be continuous! chanlist[%i]=%d but "
976 "must be %d or %d!\n", dev->minor,
977 i, CR_CHAN(chanlist[i]), nowmustbechan,
978 CR_CHAN(chanlist[0]));
979 return 0;
980 }
981 /* well, this is next correct channel in list */
982 chansegment[i] = chanlist[i];
983 }
984
985 /* check whole chanlist */
986 for (i = 0, segpos = 0; i < chanlen; i++) {
987 DEBUG(printk("%d %d=%d %d\n",
988 CR_CHAN(chansegment[i % seglen]),
989 CR_RANGE(chansegment[i % seglen]),
990 CR_CHAN(chanlist[i]),
991 CR_RANGE(chanlist[i]));)
992 if (chanlist[i] != chansegment[i % seglen]) {
993 printk(KERN_WARNING
994 "comedi%d: pcl816: bad channel or range"
995 " number! chanlist[%i]=%d,%d,%d and not"
996 " %d,%d,%d!\n", dev->minor, i,
997 CR_CHAN(chansegment[i]),
998 CR_RANGE(chansegment[i]),
999 CR_AREF(chansegment[i]),
1000 CR_CHAN(chanlist[i % seglen]),
1001 CR_RANGE(chanlist[i % seglen]),
1002 CR_AREF(chansegment[i % seglen]));
1003 return 0; /* chan/gain list is strange */
1004 }
1005 }
1006 } else {
1007 seglen = 1;
1008 }
1009
1010 return seglen; /* we can serve this with MUX logic */
1011 }
1012
1013 /*
1014 ==============================================================================
1015 Program scan/gain logic with channel list.
1016 */
1017 static void
setup_channel_list(struct comedi_device * dev,struct comedi_subdevice * s,unsigned int * chanlist,unsigned int seglen)1018 setup_channel_list(struct comedi_device *dev,
1019 struct comedi_subdevice *s, unsigned int *chanlist,
1020 unsigned int seglen)
1021 {
1022 unsigned int i;
1023
1024 devpriv->ai_act_chanlist_len = seglen;
1025 devpriv->ai_act_chanlist_pos = 0;
1026
1027 for (i = 0; i < seglen; i++) { /* store range list to card */
1028 devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]);
1029 outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX);
1030 /* select gain */
1031 outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE);
1032 }
1033
1034 udelay(1);
1035 /* select channel interval to scan */
1036 outb(devpriv->ai_act_chanlist[0] |
1037 (devpriv->ai_act_chanlist[seglen - 1] << 4),
1038 dev->iobase + PCL816_MUX);
1039 }
1040
1041 #ifdef unused
1042 /*
1043 ==============================================================================
1044 Enable(1)/disable(0) periodic interrupts from RTC
1045 */
set_rtc_irq_bit(unsigned char bit)1046 static int set_rtc_irq_bit(unsigned char bit)
1047 {
1048 unsigned char val;
1049 unsigned long flags;
1050
1051 if (bit == 1) {
1052 RTC_timer_lock++;
1053 if (RTC_timer_lock > 1)
1054 return 0;
1055 } else {
1056 RTC_timer_lock--;
1057 if (RTC_timer_lock < 0)
1058 RTC_timer_lock = 0;
1059 if (RTC_timer_lock > 0)
1060 return 0;
1061 }
1062
1063 save_flags(flags);
1064 cli();
1065 val = CMOS_READ(RTC_CONTROL);
1066 if (bit)
1067 val |= RTC_PIE;
1068 else
1069 val &= ~RTC_PIE;
1070
1071 CMOS_WRITE(val, RTC_CONTROL);
1072 CMOS_READ(RTC_INTR_FLAGS);
1073 restore_flags(flags);
1074 return 0;
1075 }
1076 #endif
1077
1078 /*
1079 ==============================================================================
1080 Free any resources that we have claimed
1081 */
free_resources(struct comedi_device * dev)1082 static void free_resources(struct comedi_device *dev)
1083 {
1084 /* printk("free_resource()\n"); */
1085 if (dev->private) {
1086 pcl816_ai_cancel(dev, devpriv->sub_ai);
1087 pcl816_reset(dev);
1088 if (devpriv->dma)
1089 free_dma(devpriv->dma);
1090 if (devpriv->dmabuf[0])
1091 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1092 if (devpriv->dmabuf[1])
1093 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1094 #ifdef unused
1095 if (devpriv->rtc_irq)
1096 free_irq(devpriv->rtc_irq, dev);
1097 if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1098 if (devpriv->rtc_iobase)
1099 release_region(devpriv->rtc_iobase,
1100 devpriv->rtc_iosize);
1101 }
1102 #endif
1103 }
1104
1105 if (dev->irq)
1106 free_irq(dev->irq, dev);
1107 if (dev->iobase)
1108 release_region(dev->iobase, this_board->io_range);
1109 /* printk("free_resource() end\n"); */
1110 }
1111
1112 /*
1113 ==============================================================================
1114
1115 Initialization
1116
1117 */
pcl816_attach(struct comedi_device * dev,struct comedi_devconfig * it)1118 static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1119 {
1120 int ret;
1121 unsigned long iobase;
1122 unsigned int irq, dma;
1123 unsigned long pages;
1124 /* int i; */
1125 struct comedi_subdevice *s;
1126
1127 /* claim our I/O space */
1128 iobase = it->options[0];
1129 printk("comedi%d: pcl816: board=%s, ioport=0x%03lx", dev->minor,
1130 this_board->name, iobase);
1131
1132 if (!request_region(iobase, this_board->io_range, "pcl816")) {
1133 printk("I/O port conflict\n");
1134 return -EIO;
1135 }
1136
1137 dev->iobase = iobase;
1138
1139 if (pcl816_check(iobase)) {
1140 printk(KERN_ERR ", I cann't detect board. FAIL!\n");
1141 return -EIO;
1142 }
1143
1144 ret = alloc_private(dev, sizeof(struct pcl816_private));
1145 if (ret < 0)
1146 return ret; /* Can't alloc mem */
1147
1148 /* set up some name stuff */
1149 dev->board_name = this_board->name;
1150
1151 /* grab our IRQ */
1152 irq = 0;
1153 if (this_board->IRQbits != 0) { /* board support IRQ */
1154 irq = it->options[1];
1155 if (irq) { /* we want to use IRQ */
1156 if (((1 << irq) & this_board->IRQbits) == 0) {
1157 printk
1158 (", IRQ %u is out of allowed range, "
1159 "DISABLING IT", irq);
1160 irq = 0; /* Bad IRQ */
1161 } else {
1162 if (request_irq
1163 (irq, interrupt_pcl816, 0, "pcl816", dev)) {
1164 printk
1165 (", unable to allocate IRQ %u, "
1166 "DISABLING IT", irq);
1167 irq = 0; /* Can't use IRQ */
1168 } else {
1169 printk(KERN_INFO ", irq=%u", irq);
1170 }
1171 }
1172 }
1173 }
1174
1175 dev->irq = irq;
1176 if (irq) /* 1=we have allocated irq */
1177 devpriv->irq_free = 1;
1178 else
1179 devpriv->irq_free = 0;
1180
1181 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
1182 devpriv->int816_mode = 0; /* mode of irq */
1183
1184 #ifdef unused
1185 /* grab RTC for DMA operations */
1186 devpriv->dma_rtc = 0;
1187 if (it->options[2] > 0) { /* we want to use DMA */
1188 if (RTC_lock == 0) {
1189 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
1190 "pcl816 (RTC)"))
1191 goto no_rtc;
1192 }
1193 devpriv->rtc_iobase = RTC_PORT(0);
1194 devpriv->rtc_iosize = RTC_IO_EXTENT;
1195 RTC_lock++;
1196 #ifdef UNTESTED_CODE
1197 if (!request_irq(RTC_IRQ, interrupt_pcl816_ai_mode13_dma_rtc, 0,
1198 "pcl816 DMA (RTC)", dev)) {
1199 devpriv->dma_rtc = 1;
1200 devpriv->rtc_irq = RTC_IRQ;
1201 printk(", dma_irq=%u", devpriv->rtc_irq);
1202 } else {
1203 RTC_lock--;
1204 if (RTC_lock == 0) {
1205 if (devpriv->rtc_iobase)
1206 release_region(devpriv->rtc_iobase,
1207 devpriv->rtc_iosize);
1208 }
1209 devpriv->rtc_iobase = 0;
1210 devpriv->rtc_iosize = 0;
1211 }
1212 #else
1213 printk("pcl816: RTC code missing");
1214 #endif
1215
1216 }
1217
1218 no_rtc:
1219 #endif
1220 /* grab our DMA */
1221 dma = 0;
1222 devpriv->dma = dma;
1223 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1224 goto no_dma; /* if we haven't IRQ, we can't use DMA */
1225
1226 if (this_board->DMAbits != 0) { /* board support DMA */
1227 dma = it->options[2];
1228 if (dma < 1)
1229 goto no_dma; /* DMA disabled */
1230
1231 if (((1 << dma) & this_board->DMAbits) == 0) {
1232 printk(", DMA is out of allowed range, FAIL!\n");
1233 return -EINVAL; /* Bad DMA */
1234 }
1235 ret = request_dma(dma, "pcl816");
1236 if (ret) {
1237 printk(KERN_ERR
1238 ", unable to allocate DMA %u, FAIL!\n", dma);
1239 return -EBUSY; /* DMA isn't free */
1240 }
1241
1242 devpriv->dma = dma;
1243 printk(KERN_INFO ", dma=%u", dma);
1244 pages = 2; /* we need 16KB */
1245 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1246
1247 if (!devpriv->dmabuf[0]) {
1248 printk(", unable to allocate DMA buffer, FAIL!\n");
1249 /*
1250 * maybe experiment with try_to_free_pages()
1251 * will help ....
1252 */
1253 return -EBUSY; /* no buffer :-( */
1254 }
1255 devpriv->dmapages[0] = pages;
1256 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1257 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
1258 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
1259
1260 if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */
1261 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1262 if (!devpriv->dmabuf[1]) {
1263 printk(KERN_ERR
1264 ", unable to allocate DMA buffer, "
1265 "FAIL!\n");
1266 return -EBUSY;
1267 }
1268 devpriv->dmapages[1] = pages;
1269 devpriv->hwdmaptr[1] =
1270 virt_to_bus((void *)devpriv->dmabuf[1]);
1271 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1272 }
1273 }
1274
1275 no_dma:
1276
1277 /* if (this_board->n_aochan > 0)
1278 subdevs[1] = COMEDI_SUBD_AO;
1279 if (this_board->n_dichan > 0)
1280 subdevs[2] = COMEDI_SUBD_DI;
1281 if (this_board->n_dochan > 0)
1282 subdevs[3] = COMEDI_SUBD_DO;
1283 */
1284
1285 ret = alloc_subdevices(dev, 1);
1286 if (ret < 0)
1287 return ret;
1288
1289 s = dev->subdevices + 0;
1290 if (this_board->n_aichan > 0) {
1291 s->type = COMEDI_SUBD_AI;
1292 devpriv->sub_ai = s;
1293 dev->read_subdev = s;
1294 s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
1295 s->n_chan = this_board->n_aichan;
1296 s->subdev_flags |= SDF_DIFF;
1297 /* printk (", %dchans DIFF DAC - %d", s->n_chan, i); */
1298 s->maxdata = this_board->ai_maxdata;
1299 s->len_chanlist = this_board->ai_chanlist;
1300 s->range_table = this_board->ai_range_type;
1301 s->cancel = pcl816_ai_cancel;
1302 s->do_cmdtest = pcl816_ai_cmdtest;
1303 s->do_cmd = pcl816_ai_cmd;
1304 s->poll = pcl816_ai_poll;
1305 s->insn_read = pcl816_ai_insn_read;
1306 } else {
1307 s->type = COMEDI_SUBD_UNUSED;
1308 }
1309
1310 #if 0
1311 case COMEDI_SUBD_AO:
1312 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1313 s->n_chan = this_board->n_aochan;
1314 s->maxdata = this_board->ao_maxdata;
1315 s->len_chanlist = this_board->ao_chanlist;
1316 s->range_table = this_board->ao_range_type;
1317 break;
1318
1319 case COMEDI_SUBD_DI:
1320 s->subdev_flags = SDF_READABLE;
1321 s->n_chan = this_board->n_dichan;
1322 s->maxdata = 1;
1323 s->len_chanlist = this_board->n_dichan;
1324 s->range_table = &range_digital;
1325 break;
1326
1327 case COMEDI_SUBD_DO:
1328 s->subdev_flags = SDF_WRITABLE;
1329 s->n_chan = this_board->n_dochan;
1330 s->maxdata = 1;
1331 s->len_chanlist = this_board->n_dochan;
1332 s->range_table = &range_digital;
1333 break;
1334 #endif
1335
1336 pcl816_reset(dev);
1337
1338 printk("\n");
1339
1340 return 0;
1341 }
1342
1343 /*
1344 ==============================================================================
1345 Removes device
1346 */
pcl816_detach(struct comedi_device * dev)1347 static int pcl816_detach(struct comedi_device *dev)
1348 {
1349 DEBUG(printk(KERN_INFO "comedi%d: pcl816: remove\n", dev->minor);)
1350 free_resources(dev);
1351 #ifdef unused
1352 if (devpriv->dma_rtc)
1353 RTC_lock--;
1354 #endif
1355 return 0;
1356 }
1357
1358 MODULE_AUTHOR("Comedi http://www.comedi.org");
1359 MODULE_DESCRIPTION("Comedi low-level driver");
1360 MODULE_LICENSE("GPL");
1361