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