Merge branch 'for-linus' of git://git.kernel.dk/linux-block
[pandora-kernel.git] / drivers / staging / comedi / drivers / pcl816.c
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 = 0;        /* RTC lock */
159 static int RTC_timer_lock = 0;  /* 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
172 static int __init driver_pcl816_init_module(void)
173 {
174         return comedi_driver_register(&driver_pcl816);
175 }
176
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 */
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 */
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 */
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
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 */
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 */
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 */
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
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
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 */
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 */
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 */
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
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
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
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 */
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 */
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 */
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  */
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");