upload tizen1.0 source
[kernel/linux-2.6.36.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 <asm/dma.h>
42
43 #include "8253.h"
44
45 #define DEBUG(x) x
46
47 /* boards constants */
48 /* IO space len */
49 #define PCLx1x_RANGE 16
50
51 /* #define outb(x,y)  printk("OUTB(%x, 200+%d)\n", x,y-0x200); outb(x,y) */
52
53 /* INTEL 8254 counters */
54 #define PCL816_CTR0 4
55 #define PCL816_CTR1 5
56 #define PCL816_CTR2 6
57 /* R: counter read-back register W: counter control */
58 #define PCL816_CTRCTL 7
59
60 /* R: A/D high byte W: A/D range control */
61 #define PCL816_RANGE 9
62 /* W: clear INT request */
63 #define PCL816_CLRINT 10
64 /* R: next mux scan channel W: mux scan channel & range control pointer */
65 #define PCL816_MUX 11
66 /* R/W: operation control register */
67 #define PCL816_CONTROL 12
68
69 /* R: return status byte  W: set DMA/IRQ */
70 #define PCL816_STATUS 13
71 #define PCL816_STATUS_DRDY_MASK 0x80
72
73 /* R: low byte of A/D W: soft A/D trigger */
74 #define PCL816_AD_LO 8
75 /* R: high byte of A/D W: A/D range control */
76 #define PCL816_AD_HI 9
77
78 /* type of interrupt handler */
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
87 /* RTC stuff... */
88 #define RTC_IRQ         8
89 #define RTC_IO_EXTENT   0x10
90 #endif
91
92 #define MAGIC_DMA_WORD 0x5a5a
93
94 static const struct comedi_lrange range_pcl816 = { 8, {
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                                                        }
104 };
105
106 struct pcl816_board {
107
108         const char *name;       /*  board name */
109         int n_ranges;           /*  len of range list */
110         int n_aichan;           /*  num of A/D chans in diferencial mode */
111         unsigned int ai_ns_min; /*  minimal alllowed delay between samples (in ns) */
112         int n_aochan;           /*  num of D/A chans */
113         int n_dichan;           /*  num of DI chans */
114         int n_dochan;           /*  num of DO chans */
115         const struct comedi_lrange *ai_range_type;      /*  default A/D rangelist */
116         const struct comedi_lrange *ao_range_type;      /*  default D/A rangelist */
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 */
125 };
126
127 static const struct pcl816_board boardtypes[] = {
128         {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816,
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},
137         {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816,
138          &range_pcl816, PCLx1x_RANGE,
139          0x00fc,
140          0x0a,
141          0x3fff,                /* 14 bit card */
142          0x3fff,
143          1024,
144          1,
145          100},
146 };
147
148 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl816_board))
149 #define devpriv ((struct pcl816_private *)dev->private)
150 #define this_board ((const struct pcl816_board *)dev->board_ptr)
151
152 static int pcl816_attach(struct comedi_device *dev,
153                          struct comedi_devconfig *it);
154 static int pcl816_detach(struct comedi_device *dev);
155
156 #ifdef unused
157 static int RTC_lock = 0;        /* RTC lock */
158 static int RTC_timer_lock = 0;  /* RTC int lock */
159 #endif
160
161 static struct comedi_driver driver_pcl816 = {
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),
169 };
170
171 static int __init driver_pcl816_init_module(void)
172 {
173         return comedi_driver_register(&driver_pcl816);
174 }
175
176 static void __exit driver_pcl816_cleanup_module(void)
177 {
178         comedi_driver_unregister(&driver_pcl816);
179 }
180
181 module_init(driver_pcl816_init_module);
182 module_exit(driver_pcl816_cleanup_module);
183
184 struct pcl816_private {
185
186         unsigned int dma;       /*  used DMA, 0=don't use DMA */
187         int dma_rtc;            /*  1=RTC used with DMA, 0=no RTC alloc */
188 #ifdef unused
189         unsigned long rtc_iobase;       /*  RTC port region */
190         unsigned int rtc_iosize;
191         unsigned int rtc_irq;
192 #endif
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 */
207 #ifdef unused
208         int rtc_irq_blocked;    /*  1=we now do AI with DMA&RTC */
209 #endif
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 */
217         unsigned int ai_n_chan;         /*  how many channels per scan */
218         unsigned int ai_poll_ptr;       /*  how many sampes transfer poll */
219         struct comedi_subdevice *sub_ai;        /*  ptr to AI subdevice */
220 #ifdef unused
221         struct timer_list rtc_irq_timer;        /*  timer for RTC sanity check */
222         unsigned long rtc_freq; /*  RTC int freq */
223 #endif
224 };
225
226 /*
227 ==============================================================================
228 */
229 static int check_channel_list(struct comedi_device *dev,
230                               struct comedi_subdevice *s,
231                               unsigned int *chanlist, unsigned int chanlen);
232 static void setup_channel_list(struct comedi_device *dev,
233                                struct comedi_subdevice *s,
234                                unsigned int *chanlist, unsigned int seglen);
235 static int pcl816_ai_cancel(struct comedi_device *dev,
236                             struct comedi_subdevice *s);
237 static void start_pacer(struct comedi_device *dev, int mode,
238                         unsigned int divisor1, unsigned int divisor2);
239 #ifdef unused
240 static int set_rtc_irq_bit(unsigned char bit);
241 #endif
242
243 static int pcl816_ai_cmdtest(struct comedi_device *dev,
244                              struct comedi_subdevice *s,
245                              struct comedi_cmd *cmd);
246 static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
247
248 /*
249 ==============================================================================
250    ANALOG INPUT MODE0, 816 cards, slow version
251 */
252 static int pcl816_ai_insn_read(struct comedi_device *dev,
253                                struct comedi_subdevice *s,
254                                struct comedi_insn *insn, unsigned int *data)
255 {
256         int n;
257         int timeout;
258
259         DPRINTK("mode 0 analog input\n");
260         /*  software trigger, DMA and INT off */
261         outb(0, dev->iobase + PCL816_CONTROL);
262         /*  clear INT (conversion end) flag */
263         outb(0, dev->iobase + PCL816_CLRINT);
264
265         /*  Set the input channel */
266         outb(CR_CHAN(insn->chanspec) & 0xf, dev->iobase + PCL816_MUX);
267         /* select gain */
268         outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE);
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) &
277                               PCL816_STATUS_DRDY_MASK)) {
278                                 /*  return read value */
279                                 data[n] =
280                                     ((inb(dev->iobase +
281                                           PCL816_AD_HI) << 8) |
282                                      (inb(dev->iobase + PCL816_AD_LO)));
283                                 /* clear INT (conversion end) flag */
284                                 outb(0, dev->iobase + PCL816_CLRINT);
285                                 break;
286                         }
287                         udelay(1);
288                 }
289                 /*  Return timeout error */
290                 if (!timeout) {
291                         comedi_error(dev, "A/D insn timeout\n");
292                         data[0] = 0;
293                         /* clear INT (conversion end) flag */
294                         outb(0, dev->iobase + PCL816_CLRINT);
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 */
307 static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d)
308 {
309         struct comedi_device *dev = d;
310         struct comedi_subdevice *s = dev->subdevices + 0;
311         int low, hi;
312         int timeout = 50;       /* wait max 50us */
313
314         while (timeout--) {
315                 if (!(inb(dev->iobase + PCL816_STATUS) &
316                       PCL816_STATUS_DRDY_MASK))
317                         break;
318                 udelay(1);
319         }
320         if (!timeout) {         /*  timeout, bail error */
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
330         /*  get the sample */
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
341         s->async->cur_chan++;
342         if (s->async->cur_chan >= devpriv->ai_n_chan) {
343                 s->async->cur_chan = 0;
344                 devpriv->ai_act_scan++;
345         }
346
347         if (!devpriv->ai_neverending)
348                                         /* all data sampled */
349                 if (devpriv->ai_act_scan >= devpriv->ai_scans) {
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 */
362 static void transfer_from_dma_buf(struct comedi_device *dev,
363                                   struct comedi_subdevice *s, short *ptr,
364                                   unsigned int bufptr, unsigned int len)
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 >=
375                     devpriv->ai_act_chanlist_len) {
376                         devpriv->ai_act_chanlist_pos = 0;
377                 }
378
379                 s->async->cur_chan++;
380                 if (s->async->cur_chan >= devpriv->ai_n_chan) {
381                         s->async->cur_chan = 0;
382                         devpriv->ai_act_scan++;
383                 }
384
385                 if (!devpriv->ai_neverending)
386                                                 /*  all data sampled */
387                         if (devpriv->ai_act_scan >= devpriv->ai_scans) {
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
398 static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d)
399 {
400         struct comedi_device *dev = d;
401         struct comedi_subdevice *s = dev->subdevices + 0;
402         int len, bufptr, this_dma_buf;
403         unsigned long dma_flags;
404         short *ptr;
405
406         disable_dma(devpriv->dma);
407         this_dma_buf = devpriv->next_dma_buf;
408
409         /*  switch dma bufs */
410         if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) {
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();
415 /* clear_dma_ff (devpriv->dma); */
416                 set_dma_addr(devpriv->dma,
417                              devpriv->hwdmaptr[devpriv->next_dma_buf]);
418                 if (devpriv->dma_runs_to_end) {
419                         set_dma_count(devpriv->dma,
420                                       devpriv->hwdmasize[devpriv->
421                                                          next_dma_buf]);
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
432         ptr = (short *)devpriv->dmabuf[this_dma_buf];
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 */
446 static irqreturn_t interrupt_pcl816(int irq, void *d)
447 {
448         struct comedi_device *dev = d;
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) |
467             (!devpriv->int816_mode)) {
468                 if (devpriv->irq_was_now_closed) {
469                         devpriv->irq_was_now_closed = 0;
470                         /*  comedi_error(dev,"last IRQ.."); */
471                         return IRQ_HANDLED;
472                 }
473                 comedi_error(dev, "bad IRQ!");
474                 return IRQ_NONE;
475         }
476         comedi_error(dev, "IRQ from unknown source!");
477         return IRQ_NONE;
478 }
479
480 /*
481 ==============================================================================
482    COMMAND MODE
483 */
484 static void pcl816_cmdtest_out(int e, struct comedi_cmd *cmd)
485 {
486         printk(KERN_INFO "pcl816 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
487                cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
488         printk(KERN_INFO "pcl816 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
489                cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
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);
494 }
495
496 /*
497 ==============================================================================
498 */
499 static int pcl816_ai_cmdtest(struct comedi_device *dev,
500                              struct comedi_subdevice *s, struct comedi_cmd *cmd)
501 {
502         int err = 0;
503         int tmp, divisor1 = 0, divisor2 = 0;
504
505         DEBUG(printk(KERN_INFO "pcl816 pcl812_ai_cmdtest\n");
506               pcl816_cmdtest_out(-1, cmd);
507              );
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
520         tmp = cmd->convert_src;
521         cmd->convert_src &= TRIG_EXT | TRIG_TIMER;
522         if (!cmd->convert_src || tmp != cmd->convert_src)
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
535         if (err)
536                 return 1;
537
538
539         /*
540          * step 2: make sure trigger sources
541          * are unique and mutually compatible
542          */
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
567         if (err)
568                 return 2;
569
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
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
609         if (err)
610                 return 3;
611
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,
617                                           &divisor1, &divisor2,
618                                           &cmd->convert_arg,
619                                           cmd->flags & TRIG_ROUND_MASK);
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
626         if (err)
627                 return 4;
628
629
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
638         return 0;
639 }
640
641 static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
642 {
643         unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq;
644         struct comedi_cmd *cmd = &s->async->cmd;
645         unsigned int seglen;
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;
655 /* if(cmd->chanlist_len>MAX_CHANLIST_LEN) return -EINVAL; */
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,
664                                           &divisor2, &cmd->convert_arg,
665                                           cmd->flags & TRIG_ROUND_MASK);
666
667                 /*  PCL816 crash if any divisor is set to 1 */
668                 if (divisor1 == 1) {
669                         divisor1 = 2;
670                         divisor2 /= 2;
671                 }
672                 if (divisor2 == 1) {
673                         divisor2 = 2;
674                         divisor1 /= 2;
675                 }
676         }
677
678         start_pacer(dev, -1, 0, 0);     /*  stop pacer */
679
680         seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len);
681         if (seglen < 1)
682                 return -EINVAL;
683         setup_channel_list(dev, s, cmd->chanlist, seglen);
684         udelay(1);
685
686         devpriv->ai_n_chan = cmd->chanlist_len;
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
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");
705                 /*               devpriv->ai_eos=1; */
706                 /* if (devpriv->ai_n_chan==1) */
707                 /*       devpriv->dma=0; // DMA is useless for this situation */
708         }
709
710         if (devpriv->dma) {
711                 bytes = devpriv->hwdmasize[0];
712                 if (!devpriv->ai_neverending) {
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];
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;
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);
752                 break;
753
754         default:
755                 devpriv->int816_mode = INT_TYPE_AI3_DMA;
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);
762                 break;
763         }
764
765         DPRINTK("pcl816 END: pcl812_ai_cmd()\n");
766         return 0;
767 }
768
769 static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
770 {
771         unsigned long flags;
772         unsigned int top1, top2, i;
773
774         if (!devpriv->dma)
775                 return 0;       /*  poll is valid only for DMA transfer */
776
777         spin_lock_irqsave(&dev->spinlock, flags);
778
779         for (i = 0; i < 20; i++) {
780                 top1 = get_dma_residue(devpriv->dma);   /*  where is now DMA */
781                 top2 = get_dma_residue(devpriv->dma);
782                 if (top1 == top2)
783                         break;
784         }
785         if (top1 != top2) {
786                 spin_unlock_irqrestore(&dev->spinlock, flags);
787                 return 0;
788         }
789
790         /*  where is now DMA in buffer */
791         top1 = devpriv->hwdmasize[0] - top1;
792         top1 >>= 1;             /*  sample position */
793         top2 = top1 - devpriv->ai_poll_ptr;
794         if (top2 < 1) {         /*  no new samples */
795                 spin_unlock_irqrestore(&dev->spinlock, flags);
796                 return 0;
797         }
798
799         transfer_from_dma_buf(dev, s,
800                               (short *)devpriv->dmabuf[devpriv->next_dma_buf],
801                               devpriv->ai_poll_ptr, top2);
802
803         devpriv->ai_poll_ptr = top1;    /*  new buffer position */
804         spin_unlock_irqrestore(&dev->spinlock, flags);
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 */
813 static int pcl816_ai_cancel(struct comedi_device *dev,
814                             struct comedi_subdevice *s)
815 {
816 /* DEBUG(printk("pcl816_ai_cancel()\n");) */
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:
823                         set_rtc_irq_bit(0);     /*  stop RTC */
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:
831                         outb(inb(dev->iobase + PCL816_CONTROL) & 0x73,
832                              dev->iobase + PCL816_CONTROL);     /* Stop A/D */
833                         udelay(1);
834                         outb(0, dev->iobase + PCL816_CONTROL);  /* Stop A/D */
835
836                         /* Stop pacer */
837                         outb(0xb0, dev->iobase + PCL816_CTRCTL);
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);
842
843                         /* clear INT request */
844                         outb(0, dev->iobase + PCL816_CLRINT);
845
846                         /* Stop A/D */
847                         outb(0, dev->iobase + PCL816_CONTROL);
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;
852 /* s->busy = 0; */
853                         break;
854                 }
855         }
856
857         DEBUG(printk("comedi: pcl816_ai_cancel() successful\n");)
858             return 0;
859 }
860
861 /*
862 ==============================================================================
863  chech for PCL816
864 */
865 static int pcl816_check(unsigned long iobase)
866 {
867         outb(0x00, iobase + PCL816_MUX);
868         udelay(1);
869         if (inb(iobase + PCL816_MUX) != 0x00)
870                 return 1;       /* there isn't card */
871         outb(0x55, iobase + PCL816_MUX);
872         udelay(1);
873         if (inb(iobase + PCL816_MUX) != 0x55)
874                 return 1;       /* there isn't card */
875         outb(0x00, iobase + PCL816_MUX);
876         udelay(1);
877         outb(0x18, iobase + PCL816_CONTROL);
878         udelay(1);
879         if (inb(iobase + PCL816_CONTROL) != 0x18)
880                 return 1;       /* there isn't card */
881         return 0;               /*  ok, card exist */
882 }
883
884 /*
885 ==============================================================================
886  reset whole PCL-816 cards
887 */
888 static void pcl816_reset(struct comedi_device *dev)
889 {
890 /* outb (0, dev->iobase + PCL818_DA_LO);         DAC=0V */
891 /* outb (0, dev->iobase + PCL818_DA_HI); */
892 /* udelay (1); */
893 /* outb (0, dev->iobase + PCL818_DO_HI);        DO=$0000 */
894 /* outb (0, dev->iobase + PCL818_DO_LO); */
895 /* udelay (1); */
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 */
909 static void
910 start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1,
911             unsigned int divisor2)
912 {
913         outb(0x32, dev->iobase + PCL816_CTRCTL);
914         outb(0xff, dev->iobase + PCL816_CTR0);
915         outb(0x00, dev->iobase + PCL816_CTR0);
916         udelay(1);
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);
922         udelay(1);
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) */
934 /* outb(0, dev->iobase + PCL816_CLRINT); */
935 }
936
937 /*
938 ==============================================================================
939  Check if channel list from user is builded correctly
940  If it's ok, then return non-zero length of repeated segment of channel list
941 */
942 static int
943 check_channel_list(struct comedi_device *dev,
944                    struct comedi_subdevice *s, unsigned int *chanlist,
945                    unsigned int chanlen)
946 {
947         unsigned int chansegment[16];
948         unsigned int i, nowmustbechan, seglen, segpos;
949
950         /*  correct channel and range number check itself comedi/range.c */
951         if (chanlen < 1) {
952                 comedi_error(dev, "range/channel list is empty!");
953                 return 0;
954         }
955
956         if (chanlen > 1) {
957                 /*  first channel is everytime ok */
958                 chansegment[0] = chanlist[0];
959                 for (i = 1, seglen = 1; i < chanlen; i++, seglen++) {
960                         /*  build part of chanlist */
961                         DEBUG(printk(KERN_INFO "%d. %d %d\n", i,
962                                      CR_CHAN(chanlist[i]),
963                                      CR_RANGE(chanlist[i]));)
964
965                         /*  we detect loop, this must by finish */
966                             if (chanlist[0] == chanlist[i])
967                                 break;
968                         nowmustbechan =
969                             (CR_CHAN(chansegment[i - 1]) + 1) % chanlen;
970                         if (nowmustbechan != CR_CHAN(chanlist[i])) {
971                                 /*  channel list isn't continous :-( */
972                                 printk(KERN_WARNING
973                                        "comedi%d: pcl816: channel list must "
974                                        "be continous! chanlist[%i]=%d but "
975                                        "must be %d or %d!\n", dev->minor,
976                                        i, CR_CHAN(chanlist[i]), nowmustbechan,
977                                        CR_CHAN(chanlist[0]));
978                                 return 0;
979                         }
980                         /*  well, this is next correct channel in list */
981                         chansegment[i] = chanlist[i];
982                 }
983
984                 /*  check whole chanlist */
985                 for (i = 0, segpos = 0; i < chanlen; i++) {
986                         DEBUG(printk("%d %d=%d %d\n",
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]) {
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]));
1002                                 return 0;       /*  chan/gain list is strange */
1003                         }
1004                 }
1005         } else {
1006                 seglen = 1;
1007         }
1008
1009         return seglen;  /*  we can serve this with MUX logic */
1010 }
1011
1012 /*
1013 ==============================================================================
1014  Program scan/gain logic with channel list.
1015 */
1016 static void
1017 setup_channel_list(struct comedi_device *dev,
1018                    struct comedi_subdevice *s, unsigned int *chanlist,
1019                    unsigned int seglen)
1020 {
1021         unsigned int i;
1022
1023         devpriv->ai_act_chanlist_len = seglen;
1024         devpriv->ai_act_chanlist_pos = 0;
1025
1026         for (i = 0; i < seglen; i++) {  /*  store range list to card */
1027                 devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]);
1028                 outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX);
1029                 /* select gain */
1030                 outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE);
1031         }
1032
1033         udelay(1);
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);
1038 }
1039
1040 #ifdef unused
1041 /*
1042 ==============================================================================
1043   Enable(1)/disable(0) periodic interrupts from RTC
1044 */
1045 static 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);
1065         if (bit)
1066                 val |= RTC_PIE;
1067         else
1068                 val &= ~RTC_PIE;
1069
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 */
1081 static void free_resources(struct comedi_device *dev)
1082 {
1083         /* printk("free_resource()\n"); */
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)
1095                         free_irq(devpriv->rtc_irq, dev);
1096                 if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1097                         if (devpriv->rtc_iobase)
1098                                 release_region(devpriv->rtc_iobase,
1099                                                devpriv->rtc_iosize);
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);
1108         /* printk("free_resource() end\n"); */
1109 }
1110
1111 /*
1112 ==============================================================================
1113
1114    Initialization
1115
1116 */
1117 static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1118 {
1119         int ret;
1120         unsigned long iobase;
1121         unsigned int irq, dma;
1122         unsigned long pages;
1123         /* int i; */
1124         struct comedi_subdevice *s;
1125
1126         /* claim our I/O space */
1127         iobase = it->options[0];
1128         printk("comedi%d: pcl816:  board=%s, ioport=0x%03lx", dev->minor,
1129                this_board->name, iobase);
1130
1131         if (!request_region(iobase, this_board->io_range, "pcl816")) {
1132                 printk("I/O port conflict\n");
1133                 return -EIO;
1134         }
1135
1136         dev->iobase = iobase;
1137
1138         if (pcl816_check(iobase)) {
1139                 printk(KERN_ERR ", I cann't detect board. FAIL!\n");
1140                 return -EIO;
1141         }
1142
1143         ret = alloc_private(dev, sizeof(struct pcl816_private));
1144         if (ret < 0)
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) {
1156                                 printk
1157                                     (", IRQ %u is out of allowed range, "
1158                                      "DISABLING IT", irq);
1159                                 irq = 0;        /* Bad IRQ */
1160                         } else {
1161                                 if (request_irq
1162                                     (irq, interrupt_pcl816, 0, "pcl816", dev)) {
1163                                         printk
1164                                             (", unable to allocate IRQ %u, "
1165                                              "DISABLING IT", irq);
1166                                         irq = 0;        /* Can't use IRQ */
1167                                 } else {
1168                                         printk(KERN_INFO ", irq=%u", irq);
1169                                 }
1170                         }
1171                 }
1172         }
1173
1174         dev->irq = irq;
1175         if (irq)        /* 1=we have allocated irq */
1176                 devpriv->irq_free = 1;
1177         else
1178                 devpriv->irq_free = 0;
1179
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;
1186         if (it->options[2] > 0) {       /*  we want to use DMA */
1187                 if (RTC_lock == 0) {
1188                         if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
1189                                             "pcl816 (RTC)"))
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
1196                 if (!request_irq(RTC_IRQ, interrupt_pcl816_ai_mode13_dma_rtc, 0,
1197                                  "pcl816 DMA (RTC)", dev)) {
1198                         devpriv->dma_rtc = 1;
1199                         devpriv->rtc_irq = RTC_IRQ;
1200                         printk(", dma_irq=%u", devpriv->rtc_irq);
1201                 } else {
1202                         RTC_lock--;
1203                         if (RTC_lock == 0) {
1204                                 if (devpriv->rtc_iobase)
1205                                         release_region(devpriv->rtc_iobase,
1206                                                        devpriv->rtc_iosize);
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
1217 no_rtc:
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) {
1231                         printk(", DMA is out of allowed range, FAIL!\n");
1232                         return -EINVAL; /* Bad DMA */
1233                 }
1234                 ret = request_dma(dma, "pcl816");
1235                 if (ret) {
1236                         printk(KERN_ERR
1237                                ", unable to allocate DMA %u, FAIL!\n", dma);
1238                         return -EBUSY;  /* DMA isn't free */
1239                 }
1240
1241                 devpriv->dma = dma;
1242                 printk(KERN_INFO ", dma=%u", dma);
1243                 pages = 2;      /* we need 16KB */
1244                 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1245
1246                 if (!devpriv->dmabuf[0]) {
1247                         printk(", unable to allocate DMA buffer, FAIL!\n");
1248                         /*
1249                          * maybe experiment with try_to_free_pages()
1250                          * will help ....
1251                          */
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;
1257                 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
1258
1259                 if (devpriv->dma_rtc == 0) {    /*  we must do duble buff :-( */
1260                         devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1261                         if (!devpriv->dmabuf[1]) {
1262                                 printk(KERN_ERR
1263                                        ", unable to allocate DMA buffer, "
1264                                        "FAIL!\n");
1265                                 return -EBUSY;
1266                         }
1267                         devpriv->dmapages[1] = pages;
1268                         devpriv->hwdmaptr[1] =
1269                             virt_to_bus((void *)devpriv->dmabuf[1]);
1270                         devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1271                 }
1272         }
1273
1274 no_dma:
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 */
1283
1284         ret = alloc_subdevices(dev, 1);
1285         if (ret < 0)
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;
1296                 /* printk (", %dchans DIFF DAC - %d", s->n_chan, i); */
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
1310 case 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
1318 case 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
1326 case 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
1337         printk("\n");
1338
1339         return 0;
1340 }
1341
1342 /*
1343 ==============================================================================
1344   Removes device
1345  */
1346 static int pcl816_detach(struct comedi_device *dev)
1347 {
1348         DEBUG(printk(KERN_INFO "comedi%d: pcl816: remove\n", dev->minor);)
1349             free_resources(dev);
1350 #ifdef unused
1351         if (devpriv->dma_rtc)
1352                 RTC_lock--;
1353 #endif
1354         return 0;
1355 }
1356
1357 MODULE_AUTHOR("Comedi http://www.comedi.org");
1358 MODULE_DESCRIPTION("Comedi low-level driver");
1359 MODULE_LICENSE("GPL");