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