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