Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[firefly-linux-kernel-4.4.55.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/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         int 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, short *ptr,
285                                   unsigned int bufptr, unsigned int len)
286 {
287         struct pcl816_private *devpriv = dev->private;
288         int i;
289
290         s->async->events = 0;
291
292         for (i = 0; i < len; i++) {
293
294                 comedi_buf_put(s->async, ptr[bufptr++]);
295
296                 if (++devpriv->ai_act_chanlist_pos >=
297                     devpriv->ai_act_chanlist_len) {
298                         devpriv->ai_act_chanlist_pos = 0;
299                 }
300
301                 s->async->cur_chan++;
302                 if (s->async->cur_chan >= devpriv->ai_n_chan) {
303                         s->async->cur_chan = 0;
304                         devpriv->ai_act_scan++;
305                 }
306
307                 if (!devpriv->ai_neverending)
308                                                 /*  all data sampled */
309                         if (devpriv->ai_act_scan >= devpriv->ai_scans) {
310                                 pcl816_ai_cancel(dev, s);
311                                 s->async->events |= COMEDI_CB_EOA;
312                                 s->async->events |= COMEDI_CB_BLOCK;
313                                 break;
314                         }
315         }
316
317         comedi_event(dev, s);
318 }
319
320 static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d)
321 {
322         struct comedi_device *dev = d;
323         struct pcl816_private *devpriv = dev->private;
324         struct comedi_subdevice *s = &dev->subdevices[0];
325         int len, bufptr, this_dma_buf;
326         unsigned long dma_flags;
327         short *ptr;
328
329         disable_dma(devpriv->dma);
330         this_dma_buf = devpriv->next_dma_buf;
331
332         /*  switch dma bufs */
333         if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) {
334
335                 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
336                 set_dma_mode(devpriv->dma, DMA_MODE_READ);
337                 dma_flags = claim_dma_lock();
338 /* clear_dma_ff (devpriv->dma); */
339                 set_dma_addr(devpriv->dma,
340                              devpriv->hwdmaptr[devpriv->next_dma_buf]);
341                 if (devpriv->dma_runs_to_end) {
342                         set_dma_count(devpriv->dma,
343                                       devpriv->hwdmasize[devpriv->
344                                                          next_dma_buf]);
345                 } else {
346                         set_dma_count(devpriv->dma, devpriv->last_dma_run);
347                 }
348                 release_dma_lock(dma_flags);
349                 enable_dma(devpriv->dma);
350         }
351
352         devpriv->dma_runs_to_end--;
353         outb(0, dev->iobase + PCL816_CLRINT);   /* clear INT request */
354
355         ptr = (short *)devpriv->dmabuf[this_dma_buf];
356
357         len = (devpriv->hwdmasize[0] >> 1) - devpriv->ai_poll_ptr;
358         bufptr = devpriv->ai_poll_ptr;
359         devpriv->ai_poll_ptr = 0;
360
361         transfer_from_dma_buf(dev, s, ptr, bufptr, len);
362         return IRQ_HANDLED;
363 }
364
365 /*
366 ==============================================================================
367     INT procedure
368 */
369 static irqreturn_t interrupt_pcl816(int irq, void *d)
370 {
371         struct comedi_device *dev = d;
372         struct pcl816_private *devpriv = dev->private;
373
374         DPRINTK("<I>");
375
376         if (!dev->attached) {
377                 comedi_error(dev, "premature interrupt");
378                 return IRQ_HANDLED;
379         }
380
381         switch (devpriv->int816_mode) {
382         case INT_TYPE_AI1_DMA:
383         case INT_TYPE_AI3_DMA:
384                 return interrupt_pcl816_ai_mode13_dma(irq, d);
385         case INT_TYPE_AI1_INT:
386         case INT_TYPE_AI3_INT:
387                 return interrupt_pcl816_ai_mode13_int(irq, d);
388         }
389
390         outb(0, dev->iobase + PCL816_CLRINT);   /* clear INT request */
391         if (!dev->irq || !devpriv->irq_free || !devpriv->irq_blocked ||
392             !devpriv->int816_mode) {
393                 if (devpriv->irq_was_now_closed) {
394                         devpriv->irq_was_now_closed = 0;
395                         /*  comedi_error(dev,"last IRQ.."); */
396                         return IRQ_HANDLED;
397                 }
398                 comedi_error(dev, "bad IRQ!");
399                 return IRQ_NONE;
400         }
401         comedi_error(dev, "IRQ from unknown source!");
402         return IRQ_NONE;
403 }
404
405 /*
406 ==============================================================================
407    COMMAND MODE
408 */
409 static void pcl816_cmdtest_out(int e, struct comedi_cmd *cmd)
410 {
411         printk(KERN_INFO "pcl816 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
412                cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
413         printk(KERN_INFO "pcl816 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
414                cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
415         printk(KERN_INFO "pcl816 e=%d stopsrc=%x scanend=%x\n", e,
416                cmd->stop_src, cmd->scan_end_src);
417         printk(KERN_INFO "pcl816 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
418                e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
419 }
420
421 /*
422 ==============================================================================
423 */
424 static int pcl816_ai_cmdtest(struct comedi_device *dev,
425                              struct comedi_subdevice *s, struct comedi_cmd *cmd)
426 {
427         const struct pcl816_board *board = comedi_board(dev);
428         int err = 0;
429         int tmp, divisor1 = 0, divisor2 = 0;
430
431         DEBUG(printk(KERN_INFO "pcl816 pcl812_ai_cmdtest\n");
432               pcl816_cmdtest_out(-1, cmd);
433              );
434
435         /* Step 1 : check if triggers are trivially valid */
436
437         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
438         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
439         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_EXT | TRIG_TIMER);
440         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
441         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
442
443         if (err)
444                 return 1;
445
446         /* Step 2a : make sure trigger sources are unique */
447
448         err |= cfc_check_trigger_is_unique(cmd->convert_src);
449         err |= cfc_check_trigger_is_unique(cmd->stop_src);
450
451         /* Step 2b : and mutually compatible */
452
453         if (err)
454                 return 2;
455
456
457         /* Step 3: check if arguments are trivially valid */
458
459         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
460         err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
461
462         if (cmd->convert_src == TRIG_TIMER)
463                 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
464                                                  board->ai_ns_min);
465         else    /* TRIG_EXT */
466                 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
467
468         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
469
470         if (cmd->stop_src == TRIG_COUNT)
471                 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
472         else    /* TRIG_NONE */
473                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
474
475         if (err)
476                 return 3;
477
478
479         /* step 4: fix up any arguments */
480         if (cmd->convert_src == TRIG_TIMER) {
481                 tmp = cmd->convert_arg;
482                 i8253_cascade_ns_to_timer(board->i8254_osc_base,
483                                           &divisor1, &divisor2,
484                                           &cmd->convert_arg,
485                                           cmd->flags & TRIG_ROUND_MASK);
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, &divisor1,
532                                           &divisor2, &cmd->convert_arg,
533                                           cmd->flags & TRIG_ROUND_MASK);
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                               (short *)devpriv->dmabuf[devpriv->next_dma_buf],
670                               devpriv->ai_poll_ptr, top2);
671
672         devpriv->ai_poll_ptr = top1;    /*  new buffer position */
673         spin_unlock_irqrestore(&dev->spinlock, flags);
674
675         return s->async->buf_write_count - s->async->buf_read_count;
676 }
677
678 /*
679 ==============================================================================
680  cancel any mode 1-4 AI
681 */
682 static int pcl816_ai_cancel(struct comedi_device *dev,
683                             struct comedi_subdevice *s)
684 {
685         struct pcl816_private *devpriv = dev->private;
686
687 /* DEBUG(printk("pcl816_ai_cancel()\n");) */
688
689         if (devpriv->irq_blocked > 0) {
690                 switch (devpriv->int816_mode) {
691                 case INT_TYPE_AI1_DMA:
692                 case INT_TYPE_AI3_DMA:
693                         disable_dma(devpriv->dma);
694                 case INT_TYPE_AI1_INT:
695                 case INT_TYPE_AI3_INT:
696                         outb(inb(dev->iobase + PCL816_CONTROL) & 0x73,
697                              dev->iobase + PCL816_CONTROL);     /* Stop A/D */
698                         udelay(1);
699                         outb(0, dev->iobase + PCL816_CONTROL);  /* Stop A/D */
700
701                         /* Stop pacer */
702                         outb(0xb0, dev->iobase + PCL816_CTRCTL);
703                         outb(0x70, dev->iobase + PCL816_CTRCTL);
704                         outb(0, dev->iobase + PCL816_AD_LO);
705                         inb(dev->iobase + PCL816_AD_LO);
706                         inb(dev->iobase + PCL816_AD_HI);
707
708                         /* clear INT request */
709                         outb(0, dev->iobase + PCL816_CLRINT);
710
711                         /* Stop A/D */
712                         outb(0, dev->iobase + PCL816_CONTROL);
713                         devpriv->irq_blocked = 0;
714                         devpriv->irq_was_now_closed = devpriv->int816_mode;
715                         devpriv->int816_mode = 0;
716                         devpriv->last_int_sub = s;
717 /* s->busy = 0; */
718                         break;
719                 }
720         }
721
722         DEBUG(printk("comedi: pcl816_ai_cancel() successful\n");)
723             return 0;
724 }
725
726 /*
727 ==============================================================================
728  chech for PCL816
729 */
730 static int pcl816_check(unsigned long iobase)
731 {
732         outb(0x00, iobase + PCL816_MUX);
733         udelay(1);
734         if (inb(iobase + PCL816_MUX) != 0x00)
735                 return 1;       /* there isn't card */
736         outb(0x55, iobase + PCL816_MUX);
737         udelay(1);
738         if (inb(iobase + PCL816_MUX) != 0x55)
739                 return 1;       /* there isn't card */
740         outb(0x00, iobase + PCL816_MUX);
741         udelay(1);
742         outb(0x18, iobase + PCL816_CONTROL);
743         udelay(1);
744         if (inb(iobase + PCL816_CONTROL) != 0x18)
745                 return 1;       /* there isn't card */
746         return 0;               /*  ok, card exist */
747 }
748
749 /*
750 ==============================================================================
751  reset whole PCL-816 cards
752 */
753 static void pcl816_reset(struct comedi_device *dev)
754 {
755 /* outb (0, dev->iobase + PCL818_DA_LO);         DAC=0V */
756 /* outb (0, dev->iobase + PCL818_DA_HI); */
757 /* udelay (1); */
758 /* outb (0, dev->iobase + PCL818_DO_HI);        DO=$0000 */
759 /* outb (0, dev->iobase + PCL818_DO_LO); */
760 /* udelay (1); */
761         outb(0, dev->iobase + PCL816_CONTROL);
762         outb(0, dev->iobase + PCL816_MUX);
763         outb(0, dev->iobase + PCL816_CLRINT);
764         outb(0xb0, dev->iobase + PCL816_CTRCTL);        /* Stop pacer */
765         outb(0x70, dev->iobase + PCL816_CTRCTL);
766         outb(0x30, dev->iobase + PCL816_CTRCTL);
767         outb(0, dev->iobase + PCL816_RANGE);
768 }
769
770 /*
771 ==============================================================================
772  Start/stop pacer onboard pacer
773 */
774 static void
775 start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1,
776             unsigned int divisor2)
777 {
778         outb(0x32, dev->iobase + PCL816_CTRCTL);
779         outb(0xff, dev->iobase + PCL816_CTR0);
780         outb(0x00, dev->iobase + PCL816_CTR0);
781         udelay(1);
782
783         /*  set counter 2 as mode 3 */
784         outb(0xb4, dev->iobase + PCL816_CTRCTL);
785         /*  set counter 1 as mode 3 */
786         outb(0x74, dev->iobase + PCL816_CTRCTL);
787         udelay(1);
788
789         if (mode == 1) {
790                 DPRINTK("mode %d, divisor1 %d, divisor2 %d\n", mode, divisor1,
791                         divisor2);
792                 outb(divisor2 & 0xff, dev->iobase + PCL816_CTR2);
793                 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL816_CTR2);
794                 outb(divisor1 & 0xff, dev->iobase + PCL816_CTR1);
795                 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL816_CTR1);
796         }
797
798         /* clear pending interrupts (just in case) */
799 /* outb(0, dev->iobase + PCL816_CLRINT); */
800 }
801
802 /*
803 ==============================================================================
804  Check if channel list from user is built correctly
805  If it's ok, then return non-zero length of repeated segment of channel list
806 */
807 static int
808 check_channel_list(struct comedi_device *dev,
809                    struct comedi_subdevice *s, unsigned int *chanlist,
810                    unsigned int chanlen)
811 {
812         unsigned int chansegment[16];
813         unsigned int i, nowmustbechan, seglen, segpos;
814
815         /*  correct channel and range number check itself comedi/range.c */
816         if (chanlen < 1) {
817                 comedi_error(dev, "range/channel list is empty!");
818                 return 0;
819         }
820
821         if (chanlen > 1) {
822                 /*  first channel is every time ok */
823                 chansegment[0] = chanlist[0];
824                 for (i = 1, seglen = 1; i < chanlen; i++, seglen++) {
825                         /*  build part of chanlist */
826                         DEBUG(printk(KERN_INFO "%d. %d %d\n", i,
827                                      CR_CHAN(chanlist[i]),
828                                      CR_RANGE(chanlist[i]));)
829
830                         /*  we detect loop, this must by finish */
831                             if (chanlist[0] == chanlist[i])
832                                 break;
833                         nowmustbechan =
834                             (CR_CHAN(chansegment[i - 1]) + 1) % chanlen;
835                         if (nowmustbechan != CR_CHAN(chanlist[i])) {
836                                 /*  channel list isn't continuous :-( */
837                                 printk(KERN_WARNING
838                                        "comedi%d: pcl816: channel list must "
839                                        "be continuous! chanlist[%i]=%d but "
840                                        "must be %d or %d!\n", dev->minor,
841                                        i, CR_CHAN(chanlist[i]), nowmustbechan,
842                                        CR_CHAN(chanlist[0]));
843                                 return 0;
844                         }
845                         /*  well, this is next correct channel in list */
846                         chansegment[i] = chanlist[i];
847                 }
848
849                 /*  check whole chanlist */
850                 for (i = 0, segpos = 0; i < chanlen; i++) {
851                         DEBUG(printk("%d %d=%d %d\n",
852                                      CR_CHAN(chansegment[i % seglen]),
853                                      CR_RANGE(chansegment[i % seglen]),
854                                      CR_CHAN(chanlist[i]),
855                                      CR_RANGE(chanlist[i]));)
856                             if (chanlist[i] != chansegment[i % seglen]) {
857                                 printk(KERN_WARNING
858                                        "comedi%d: pcl816: bad channel or range"
859                                        " number! chanlist[%i]=%d,%d,%d and not"
860                                        " %d,%d,%d!\n", dev->minor, i,
861                                        CR_CHAN(chansegment[i]),
862                                        CR_RANGE(chansegment[i]),
863                                        CR_AREF(chansegment[i]),
864                                        CR_CHAN(chanlist[i % seglen]),
865                                        CR_RANGE(chanlist[i % seglen]),
866                                        CR_AREF(chansegment[i % seglen]));
867                                 return 0;       /*  chan/gain list is strange */
868                         }
869                 }
870         } else {
871                 seglen = 1;
872         }
873
874         return seglen;  /*  we can serve this with MUX logic */
875 }
876
877 /*
878 ==============================================================================
879  Program scan/gain logic with channel list.
880 */
881 static void
882 setup_channel_list(struct comedi_device *dev,
883                    struct comedi_subdevice *s, unsigned int *chanlist,
884                    unsigned int seglen)
885 {
886         struct pcl816_private *devpriv = dev->private;
887         unsigned int i;
888
889         devpriv->ai_act_chanlist_len = seglen;
890         devpriv->ai_act_chanlist_pos = 0;
891
892         for (i = 0; i < seglen; i++) {  /*  store range list to card */
893                 devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]);
894                 outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX);
895                 /* select gain */
896                 outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE);
897         }
898
899         udelay(1);
900         /* select channel interval to scan */
901         outb(devpriv->ai_act_chanlist[0] |
902              (devpriv->ai_act_chanlist[seglen - 1] << 4),
903              dev->iobase + PCL816_MUX);
904 }
905
906 static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
907 {
908         const struct pcl816_board *board = comedi_board(dev);
909         struct pcl816_private *devpriv;
910         int ret;
911         unsigned int irq, dma;
912         unsigned long pages;
913         /* int i; */
914         struct comedi_subdevice *s;
915
916         ret = comedi_request_region(dev, it->options[0], board->io_range);
917         if (ret)
918                 return ret;
919
920         if (pcl816_check(dev->iobase)) {
921                 printk(KERN_ERR ", I cann't detect board. FAIL!\n");
922                 return -EIO;
923         }
924
925         devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
926         if (!devpriv)
927                 return -ENOMEM;
928         dev->private = devpriv;
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          100},
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          100},
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");