Linux 3.18-rc3
[cascardo/linux.git] / drivers / staging / comedi / drivers / pcl818.c
1 /*
2    comedi/drivers/pcl818.c
3
4    Author:  Michal Dobes <dobes@tesnet.cz>
5
6    hardware driver for Advantech cards:
7     card:   PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818, PCL-718
8     driver: pcl818l,  pcl818h,  pcl818hd,  pcl818hg,  pcl818,  pcl718
9 */
10 /*
11 Driver: pcl818
12 Description: Advantech PCL-818 cards, PCL-718
13 Author: Michal Dobes <dobes@tesnet.cz>
14 Devices: [Advantech] PCL-818L (pcl818l), PCL-818H (pcl818h),
15   PCL-818HD (pcl818hd), PCL-818HG (pcl818hg), PCL-818 (pcl818),
16   PCL-718 (pcl718)
17 Status: works
18
19 All cards have 16 SE/8 DIFF ADCs, one or two DACs, 16 DI and 16 DO.
20 Differences are only at maximal sample speed, range list and FIFO
21 support.
22 The driver support AI mode 0, 1, 3 other subdevices (AO, DI, DO) support
23 only mode 0. If DMA/FIFO/INT are disabled then AI support only mode 0.
24 PCL-818HD and PCL-818HG support 1kword FIFO. Driver support this FIFO
25 but this code is untested.
26 A word or two about DMA. Driver support DMA operations at two ways:
27 1) DMA uses two buffers and after one is filled then is generated
28    INT and DMA restart with second buffer. With this mode I'm unable run
29    more that 80Ksamples/secs without data dropouts on K6/233.
30 2) DMA uses one buffer and run in autoinit mode and the data are
31    from DMA buffer moved on the fly with 2kHz interrupts from RTC.
32    This mode is used if the interrupt 8 is available for allocation.
33    If not, then first DMA mode is used. With this I can run at
34    full speed one card (100ksamples/secs) or two cards with
35    60ksamples/secs each (more is problem on account of ISA limitations).
36    To use this mode you must have compiled  kernel with disabled
37    "Enhanced Real Time Clock Support".
38    Maybe you can have problems if you use xntpd or similar.
39    If you've data dropouts with DMA mode 2 then:
40     a) disable IDE DMA
41     b) switch text mode console to fb.
42
43    Options for PCL-818L:
44     [0] - IO Base
45     [1] - IRQ   (0=disable, 2, 3, 4, 5, 6, 7)
46     [2] - DMA   (0=disable, 1, 3)
47     [3] - 0, 10=10MHz clock for 8254
48               1= 1MHz clock for 8254
49     [4] - 0,  5=A/D input  -5V.. +5V
50           1, 10=A/D input -10V..+10V
51     [5] - 0,  5=D/A output 0-5V  (internal reference -5V)
52           1, 10=D/A output 0-10V (internal reference -10V)
53           2    =D/A output unknown (external reference)
54
55    Options for PCL-818, PCL-818H:
56     [0] - IO Base
57     [1] - IRQ   (0=disable, 2, 3, 4, 5, 6, 7)
58     [2] - DMA   (0=disable, 1, 3)
59     [3] - 0, 10=10MHz clock for 8254
60               1= 1MHz clock for 8254
61     [4] - 0,  5=D/A output 0-5V  (internal reference -5V)
62           1, 10=D/A output 0-10V (internal reference -10V)
63           2    =D/A output unknown (external reference)
64
65    Options for PCL-818HD, PCL-818HG:
66     [0] - IO Base
67     [1] - IRQ   (0=disable, 2, 3, 4, 5, 6, 7)
68     [2] - DMA/FIFO  (-1=use FIFO, 0=disable both FIFO and DMA,
69                       1=use DMA ch 1, 3=use DMA ch 3)
70     [3] - 0, 10=10MHz clock for 8254
71               1= 1MHz clock for 8254
72     [4] - 0,  5=D/A output 0-5V  (internal reference -5V)
73           1, 10=D/A output 0-10V (internal reference -10V)
74           2    =D/A output unknown (external reference)
75
76    Options for PCL-718:
77     [0] - IO Base
78     [1] - IRQ   (0=disable, 2, 3, 4, 5, 6, 7)
79     [2] - DMA   (0=disable, 1, 3)
80     [3] - 0, 10=10MHz clock for 8254
81               1= 1MHz clock for 8254
82     [4] -     0=A/D Range is +/-10V
83               1=             +/-5V
84               2=             +/-2.5V
85               3=             +/-1V
86               4=             +/-0.5V
87               5=             user defined bipolar
88               6=             0-10V
89               7=             0-5V
90               8=             0-2V
91               9=             0-1V
92              10=             user defined unipolar
93     [5] - 0,  5=D/A outputs 0-5V  (internal reference -5V)
94           1, 10=D/A outputs 0-10V (internal reference -10V)
95               2=D/A outputs unknown (external reference)
96     [6] - 0, 60=max  60kHz A/D sampling
97           1,100=max 100kHz A/D sampling (PCL-718 with Option 001 installed)
98
99 */
100
101 #include <linux/module.h>
102 #include <linux/gfp.h>
103 #include <linux/delay.h>
104 #include <linux/io.h>
105 #include <linux/interrupt.h>
106 #include <asm/dma.h>
107
108 #include "../comedidev.h"
109
110 #include "comedi_fc.h"
111 #include "8253.h"
112
113 /* boards constants */
114
115 #define boardPCL818L 0
116 #define boardPCL818H 1
117 #define boardPCL818HD 2
118 #define boardPCL818HG 3
119 #define boardPCL818 4
120 #define boardPCL718 5
121
122 /*
123  * Register I/O map
124  */
125 #define PCL818_AI_LSB_REG                       0x00
126 #define PCL818_AI_MSB_REG                       0x01
127 #define PCL818_RANGE_REG                        0x01
128 #define PCL818_MUX_REG                          0x02
129 #define PCL818_MUX_SCAN(_first, _last)          (((_last) << 4) | (_first))
130 #define PCL818_DO_DI_LSB_REG                    0x03
131 #define PCL818_AO_LSB_REG(x)                    (0x04 + ((x) * 2))
132 #define PCL818_AO_MSB_REG(x)                    (0x05 + ((x) * 2))
133 #define PCL818_STATUS_REG                       0x08
134 #define PCL818_STATUS_NEXT_CHAN_MASK            (0xf << 0)
135 #define PCL818_STATUS_INT                       (1 << 4)
136 #define PCL818_STATUS_MUX                       (1 << 5)
137 #define PCL818_STATUS_UNI                       (1 << 6)
138 #define PCL818_STATUS_EOC                       (1 << 7)
139 #define PCL818_CTRL_REG                         0x09
140 #define PCL818_CTRL_DISABLE_TRIG                (0 << 0)
141 #define PCL818_CTRL_SOFT_TRIG                   (1 << 0)
142 #define PCL818_CTRL_EXT_TRIG                    (2 << 0)
143 #define PCL818_CTRL_PACER_TRIG                  (3 << 0)
144 #define PCL818_CTRL_DMAE                        (1 << 2)
145 #define PCL818_CTRL_IRQ(x)                      ((x) << 4)
146 #define PCL818_CTRL_INTE                        (1 << 7)
147 #define PCL818_CNTENABLE_REG                    0x0a
148 #define PCL818_CNTENABLE_PACER_ENA              (0 << 0)
149 #define PCL818_CNTENABLE_PACER_TRIG0            (1 << 0)
150 #define PCL818_CNTENABLE_CNT0_EXT_CLK           (0 << 1)
151 #define PCL818_CNTENABLE_CNT0_INT_CLK           (1 << 1)
152 #define PCL818_DO_DI_MSB_REG                    0x0b
153 #define PCL818_TIMER_BASE                       0x0c
154
155 /* W: fifo enable/disable */
156 #define PCL818_FI_ENABLE 6
157 /* W: fifo interrupt clear */
158 #define PCL818_FI_INTCLR 20
159 /* W: fifo interrupt clear */
160 #define PCL818_FI_FLUSH 25
161 /* R: fifo status */
162 #define PCL818_FI_STATUS 25
163 /* R: one record from FIFO */
164 #define PCL818_FI_DATALO 23
165 #define PCL818_FI_DATAHI 24
166
167 #define MAGIC_DMA_WORD 0x5a5a
168
169 static const struct comedi_lrange range_pcl818h_ai = {
170         9, {
171                 BIP_RANGE(5),
172                 BIP_RANGE(2.5),
173                 BIP_RANGE(1.25),
174                 BIP_RANGE(0.625),
175                 UNI_RANGE(10),
176                 UNI_RANGE(5),
177                 UNI_RANGE(2.5),
178                 UNI_RANGE(1.25),
179                 BIP_RANGE(10)
180         }
181 };
182
183 static const struct comedi_lrange range_pcl818hg_ai = {
184         10, {
185                 BIP_RANGE(5),
186                 BIP_RANGE(0.5),
187                 BIP_RANGE(0.05),
188                 BIP_RANGE(0.005),
189                 UNI_RANGE(10),
190                 UNI_RANGE(1),
191                 UNI_RANGE(0.1),
192                 UNI_RANGE(0.01),
193                 BIP_RANGE(10),
194                 BIP_RANGE(1),
195                 BIP_RANGE(0.1),
196                 BIP_RANGE(0.01)
197         }
198 };
199
200 static const struct comedi_lrange range_pcl818l_l_ai = {
201         4, {
202                 BIP_RANGE(5),
203                 BIP_RANGE(2.5),
204                 BIP_RANGE(1.25),
205                 BIP_RANGE(0.625)
206         }
207 };
208
209 static const struct comedi_lrange range_pcl818l_h_ai = {
210         4, {
211                 BIP_RANGE(10),
212                 BIP_RANGE(5),
213                 BIP_RANGE(2.5),
214                 BIP_RANGE(1.25)
215         }
216 };
217
218 static const struct comedi_lrange range718_bipolar1 = {
219         1, {
220                 BIP_RANGE(1)
221         }
222 };
223
224 static const struct comedi_lrange range718_bipolar0_5 = {
225         1, {
226                 BIP_RANGE(0.5)
227         }
228 };
229
230 static const struct comedi_lrange range718_unipolar2 = {
231         1, {
232                 UNI_RANGE(2)
233         }
234 };
235
236 static const struct comedi_lrange range718_unipolar1 = {
237         1, {
238                 BIP_RANGE(1)
239         }
240 };
241
242 struct pcl818_board {
243         const char *name;
244         unsigned int ns_min;
245         int n_aochan;
246         const struct comedi_lrange *ai_range_type;
247         unsigned int has_dma:1;
248         unsigned int has_fifo:1;
249         unsigned int is_818:1;
250 };
251
252 static const struct pcl818_board boardtypes[] = {
253         {
254                 .name           = "pcl818l",
255                 .ns_min         = 25000,
256                 .n_aochan       = 1,
257                 .ai_range_type  = &range_pcl818l_l_ai,
258                 .has_dma        = 1,
259                 .is_818         = 1,
260         }, {
261                 .name           = "pcl818h",
262                 .ns_min         = 10000,
263                 .n_aochan       = 1,
264                 .ai_range_type  = &range_pcl818h_ai,
265                 .has_dma        = 1,
266                 .is_818         = 1,
267         }, {
268                 .name           = "pcl818hd",
269                 .ns_min         = 10000,
270                 .n_aochan       = 1,
271                 .ai_range_type  = &range_pcl818h_ai,
272                 .has_dma        = 1,
273                 .has_fifo       = 1,
274                 .is_818         = 1,
275         }, {
276                 .name           = "pcl818hg",
277                 .ns_min         = 10000,
278                 .n_aochan       = 1,
279                 .ai_range_type  = &range_pcl818hg_ai,
280                 .has_dma        = 1,
281                 .has_fifo       = 1,
282                 .is_818         = 1,
283         }, {
284                 .name           = "pcl818",
285                 .ns_min         = 10000,
286                 .n_aochan       = 2,
287                 .ai_range_type  = &range_pcl818h_ai,
288                 .has_dma        = 1,
289                 .is_818         = 1,
290         }, {
291                 .name           = "pcl718",
292                 .ns_min         = 16000,
293                 .n_aochan       = 2,
294                 .ai_range_type  = &range_unipolar5,
295                 .has_dma        = 1,
296         }, {
297                 .name           = "pcm3718",
298                 .ns_min         = 10000,
299                 .ai_range_type  = &range_pcl818h_ai,
300                 .has_dma        = 1,
301                 .is_818         = 1,
302         },
303 };
304
305 struct pcl818_private {
306         unsigned int dma;       /*  used DMA, 0=don't use DMA */
307         unsigned int dmapages;
308         unsigned int hwdmasize;
309         unsigned long dmabuf[2];        /*  pointers to begin of DMA buffers */
310         unsigned int hwdmaptr[2];       /*  hardware address of DMA buffers */
311         int next_dma_buf;       /*  which DMA buffer will be used next round */
312         long dma_runs_to_end;   /*  how many we must permorm DMA transfer to end of record */
313         unsigned long last_dma_run;     /*  how many bytes we must transfer on last DMA page */
314         unsigned int ns_min;    /*  manimal allowed delay between samples (in us) for actual card */
315         int i8253_osc_base;     /*  1/frequency of on board oscilator in ns */
316         int ai_act_scan;        /*  how many scans we finished */
317         int ai_act_chan;        /*  actual position in actual scan */
318         unsigned int act_chanlist[16];  /*  MUX setting for actual AI operations */
319         unsigned int act_chanlist_len;  /*  how long is actual MUX list */
320         unsigned int act_chanlist_pos;  /*  actual position in MUX list */
321         unsigned int ai_data_len;       /*  len of data buffer */
322         unsigned int divisor1;
323         unsigned int divisor2;
324         unsigned int usefifo:1;
325         unsigned int ai_cmd_running:1;
326         unsigned int ai_cmd_canceled:1;
327 };
328
329 static void pcl818_start_pacer(struct comedi_device *dev, bool load_counters)
330 {
331         struct pcl818_private *devpriv = dev->private;
332         unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE;
333
334         i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
335         i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
336         udelay(1);
337
338         if (load_counters) {
339                 i8254_write(timer_base, 0, 2, devpriv->divisor2);
340                 i8254_write(timer_base, 0, 1, devpriv->divisor1);
341         }
342 }
343
344 static void pcl818_ai_setup_dma(struct comedi_device *dev,
345                                 struct comedi_subdevice *s)
346 {
347         struct pcl818_private *devpriv = dev->private;
348         struct comedi_cmd *cmd = &s->async->cmd;
349         unsigned int flags;
350         unsigned int bytes;
351
352         disable_dma(devpriv->dma);      /*  disable dma */
353         bytes = devpriv->hwdmasize;
354         if (cmd->stop_src == TRIG_COUNT) {
355                 bytes = cmd->stop_arg * cfc_bytes_per_scan(s);
356                 devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize;
357                 devpriv->last_dma_run = bytes % devpriv->hwdmasize;
358                 devpriv->dma_runs_to_end--;
359                 if (devpriv->dma_runs_to_end >= 0)
360                         bytes = devpriv->hwdmasize;
361         }
362
363         devpriv->next_dma_buf = 0;
364         set_dma_mode(devpriv->dma, DMA_MODE_READ);
365         flags = claim_dma_lock();
366         clear_dma_ff(devpriv->dma);
367         set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
368         set_dma_count(devpriv->dma, bytes);
369         release_dma_lock(flags);
370         enable_dma(devpriv->dma);
371 }
372
373 static void pcl818_ai_setup_next_dma(struct comedi_device *dev,
374                                      struct comedi_subdevice *s)
375 {
376         struct pcl818_private *devpriv = dev->private;
377         struct comedi_cmd *cmd = &s->async->cmd;
378         unsigned long flags;
379
380         disable_dma(devpriv->dma);
381         devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
382         if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) {
383                 /* switch dma bufs */
384                 set_dma_mode(devpriv->dma, DMA_MODE_READ);
385                 flags = claim_dma_lock();
386                 set_dma_addr(devpriv->dma,
387                              devpriv->hwdmaptr[devpriv->next_dma_buf]);
388                 if (devpriv->dma_runs_to_end || cmd->stop_src == TRIG_NONE)
389                         set_dma_count(devpriv->dma, devpriv->hwdmasize);
390                 else
391                         set_dma_count(devpriv->dma, devpriv->last_dma_run);
392                 release_dma_lock(flags);
393                 enable_dma(devpriv->dma);
394         }
395
396         devpriv->dma_runs_to_end--;
397 }
398
399 static void pcl818_ai_set_chan_range(struct comedi_device *dev,
400                                      unsigned int chan,
401                                      unsigned int range)
402 {
403         outb(chan, dev->iobase + PCL818_MUX_REG);
404         outb(range, dev->iobase + PCL818_RANGE_REG);
405 }
406
407 static void pcl818_ai_set_chan_scan(struct comedi_device *dev,
408                                     unsigned int first_chan,
409                                     unsigned int last_chan)
410 {
411         outb(PCL818_MUX_SCAN(first_chan, last_chan),
412              dev->iobase + PCL818_MUX_REG);
413 }
414
415 static void pcl818_ai_setup_chanlist(struct comedi_device *dev,
416                                      unsigned int *chanlist,
417                                      unsigned int seglen)
418 {
419         struct pcl818_private *devpriv = dev->private;
420         unsigned int first_chan = CR_CHAN(chanlist[0]);
421         unsigned int last_chan;
422         unsigned int range;
423         int i;
424
425         devpriv->act_chanlist_len = seglen;
426         devpriv->act_chanlist_pos = 0;
427
428         /* store range list to card */
429         for (i = 0; i < seglen; i++) {
430                 last_chan = CR_CHAN(chanlist[i]);
431                 range = CR_RANGE(chanlist[i]);
432
433                 devpriv->act_chanlist[i] = last_chan;
434
435                 pcl818_ai_set_chan_range(dev, last_chan, range);
436         }
437
438         udelay(1);
439
440         pcl818_ai_set_chan_scan(dev, first_chan, last_chan);
441 }
442
443 static void pcl818_ai_clear_eoc(struct comedi_device *dev)
444 {
445         /* writing any value clears the interrupt request */
446         outb(0, dev->iobase + PCL818_STATUS_REG);
447 }
448
449 static void pcl818_ai_soft_trig(struct comedi_device *dev)
450 {
451         /* writing any value triggers a software conversion */
452         outb(0, dev->iobase + PCL818_AI_LSB_REG);
453 }
454
455 static unsigned int pcl818_ai_get_fifo_sample(struct comedi_device *dev,
456                                               struct comedi_subdevice *s,
457                                               unsigned int *chan)
458 {
459         unsigned int val;
460
461         val = inb(dev->iobase + PCL818_FI_DATALO);
462         val |= (inb(dev->iobase + PCL818_FI_DATAHI) << 8);
463
464         if (chan)
465                 *chan = val & 0xf;
466
467         return (val >> 4) & s->maxdata;
468 }
469
470 static unsigned int pcl818_ai_get_sample(struct comedi_device *dev,
471                                          struct comedi_subdevice *s,
472                                          unsigned int *chan)
473 {
474         unsigned int val;
475
476         val = inb(dev->iobase + PCL818_AI_MSB_REG) << 8;
477         val |= inb(dev->iobase + PCL818_AI_LSB_REG);
478
479         if (chan)
480                 *chan = val & 0xf;
481
482         return (val >> 4) & s->maxdata;
483 }
484
485 static int pcl818_ai_eoc(struct comedi_device *dev,
486                          struct comedi_subdevice *s,
487                          struct comedi_insn *insn,
488                          unsigned long context)
489 {
490         unsigned int status;
491
492         status = inb(dev->iobase + PCL818_STATUS_REG);
493         if (status & PCL818_STATUS_INT)
494                 return 0;
495         return -EBUSY;
496 }
497
498 static bool pcl818_ai_dropout(struct comedi_device *dev,
499                               struct comedi_subdevice *s,
500                               unsigned int chan)
501 {
502         struct pcl818_private *devpriv = dev->private;
503         unsigned int expected_chan;
504
505         expected_chan = devpriv->act_chanlist[devpriv->act_chanlist_pos];
506         if (chan != expected_chan) {
507                 dev_dbg(dev->class_dev,
508                         "A/D mode1/3 %s - channel dropout %d!=%d !\n",
509                         (devpriv->dma) ? "DMA" :
510                         (devpriv->usefifo) ? "FIFO" : "IRQ",
511                         chan, expected_chan);
512                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
513                 return true;
514         }
515         return false;
516 }
517
518 static bool pcl818_ai_next_chan(struct comedi_device *dev,
519                                 struct comedi_subdevice *s)
520 {
521         struct pcl818_private *devpriv = dev->private;
522         struct comedi_cmd *cmd = &s->async->cmd;
523
524         s->async->events |= COMEDI_CB_BLOCK;
525
526         devpriv->act_chanlist_pos++;
527         if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
528                 devpriv->act_chanlist_pos = 0;
529
530         s->async->cur_chan++;
531         if (s->async->cur_chan >= cmd->chanlist_len) {
532                 s->async->cur_chan = 0;
533                 devpriv->ai_act_scan--;
534                 s->async->events |= COMEDI_CB_EOS;
535         }
536
537         if (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan == 0) {
538                 /* all data sampled */
539                 s->async->events |= COMEDI_CB_EOA;
540                 return false;
541         }
542
543         return true;
544 }
545
546 static void pcl818_handle_eoc(struct comedi_device *dev,
547                               struct comedi_subdevice *s)
548 {
549         unsigned int chan;
550         unsigned int val;
551
552         if (pcl818_ai_eoc(dev, s, NULL, 0)) {
553                 dev_err(dev->class_dev, "A/D mode1/3 IRQ without DRDY!\n");
554                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
555                 return;
556         }
557
558         val = pcl818_ai_get_sample(dev, s, &chan);
559
560         if (pcl818_ai_dropout(dev, s, chan))
561                 return;
562
563         comedi_buf_put(s, val);
564
565         pcl818_ai_next_chan(dev, s);
566 }
567
568 static void pcl818_handle_dma(struct comedi_device *dev,
569                               struct comedi_subdevice *s)
570 {
571         struct pcl818_private *devpriv = dev->private;
572         unsigned short *ptr;
573         unsigned int chan;
574         unsigned int val;
575         int i, len, bufptr;
576
577         pcl818_ai_setup_next_dma(dev, s);
578
579         ptr = (unsigned short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
580
581         len = devpriv->hwdmasize >> 1;
582         bufptr = 0;
583
584         for (i = 0; i < len; i++) {
585                 val = ptr[bufptr++];
586                 chan = val & 0xf;
587                 val = (val >> 4) & s->maxdata;
588
589                 if (pcl818_ai_dropout(dev, s, chan))
590                         break;
591
592                 comedi_buf_put(s, val);
593
594                 if (!pcl818_ai_next_chan(dev, s))
595                         break;
596         }
597 }
598
599 static void pcl818_handle_fifo(struct comedi_device *dev,
600                                struct comedi_subdevice *s)
601 {
602         unsigned int status;
603         unsigned int chan;
604         unsigned int val;
605         int i, len;
606
607         status = inb(dev->iobase + PCL818_FI_STATUS);
608
609         if (status & 4) {
610                 dev_err(dev->class_dev, "A/D mode1/3 FIFO overflow!\n");
611                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
612                 return;
613         }
614
615         if (status & 1) {
616                 dev_err(dev->class_dev,
617                         "A/D mode1/3 FIFO interrupt without data!\n");
618                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
619                 return;
620         }
621
622         if (status & 2)
623                 len = 512;
624         else
625                 len = 0;
626
627         for (i = 0; i < len; i++) {
628                 val = pcl818_ai_get_fifo_sample(dev, s, &chan);
629
630                 if (pcl818_ai_dropout(dev, s, chan))
631                         break;
632
633                 comedi_buf_put(s, val);
634
635                 if (!pcl818_ai_next_chan(dev, s))
636                         break;
637         }
638 }
639
640 static irqreturn_t pcl818_interrupt(int irq, void *d)
641 {
642         struct comedi_device *dev = d;
643         struct pcl818_private *devpriv = dev->private;
644         struct comedi_subdevice *s = dev->read_subdev;
645
646         if (!dev->attached || !devpriv->ai_cmd_running) {
647                 pcl818_ai_clear_eoc(dev);
648                 return IRQ_HANDLED;
649         }
650
651         if (devpriv->ai_cmd_canceled) {
652                 /*
653                  * The cleanup from ai_cancel() has been delayed
654                  * until now because the card doesn't seem to like
655                  * being reprogrammed while a DMA transfer is in
656                  * progress.
657                  */
658                 devpriv->ai_act_scan = 0;
659                 s->cancel(dev, s);
660                 return IRQ_HANDLED;
661         }
662
663         if (devpriv->dma)
664                 pcl818_handle_dma(dev, s);
665         else if (devpriv->usefifo)
666                 pcl818_handle_fifo(dev, s);
667         else
668                 pcl818_handle_eoc(dev, s);
669
670         pcl818_ai_clear_eoc(dev);
671
672         cfc_handle_events(dev, s);
673         return IRQ_HANDLED;
674 }
675
676 static int check_channel_list(struct comedi_device *dev,
677                               struct comedi_subdevice *s,
678                               unsigned int *chanlist, unsigned int n_chan)
679 {
680         unsigned int chansegment[16];
681         unsigned int i, nowmustbechan, seglen, segpos;
682
683         /* correct channel and range number check itself comedi/range.c */
684         if (n_chan < 1) {
685                 dev_err(dev->class_dev, "range/channel list is empty!\n");
686                 return 0;
687         }
688
689         if (n_chan > 1) {
690                 /*  first channel is every time ok */
691                 chansegment[0] = chanlist[0];
692                 /*  build part of chanlist */
693                 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
694                         /* we detect loop, this must by finish */
695
696                         if (chanlist[0] == chanlist[i])
697                                 break;
698                         nowmustbechan =
699                             (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
700                         if (nowmustbechan != CR_CHAN(chanlist[i])) {    /*  channel list isn't continuous :-( */
701                                 dev_dbg(dev->class_dev,
702                                         "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
703                                         i, CR_CHAN(chanlist[i]), nowmustbechan,
704                                         CR_CHAN(chanlist[0]));
705                                 return 0;
706                         }
707                         /*  well, this is next correct channel in list */
708                         chansegment[i] = chanlist[i];
709                 }
710
711                 /*  check whole chanlist */
712                 for (i = 0, segpos = 0; i < n_chan; i++) {
713                         if (chanlist[i] != chansegment[i % seglen]) {
714                                 dev_dbg(dev->class_dev,
715                                         "bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
716                                         i, CR_CHAN(chansegment[i]),
717                                         CR_RANGE(chansegment[i]),
718                                         CR_AREF(chansegment[i]),
719                                         CR_CHAN(chanlist[i % seglen]),
720                                         CR_RANGE(chanlist[i % seglen]),
721                                         CR_AREF(chansegment[i % seglen]));
722                                 return 0;       /*  chan/gain list is strange */
723                         }
724                 }
725         } else {
726                 seglen = 1;
727         }
728         return seglen;
729 }
730
731 static int check_single_ended(unsigned int port)
732 {
733         if (inb(port + PCL818_STATUS_REG) & PCL818_STATUS_MUX)
734                 return 1;
735         return 0;
736 }
737
738 static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
739                       struct comedi_cmd *cmd)
740 {
741         const struct pcl818_board *board = dev->board_ptr;
742         struct pcl818_private *devpriv = dev->private;
743         int err = 0;
744         unsigned int arg;
745
746         /* Step 1 : check if triggers are trivially valid */
747
748         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
749         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
750         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
751         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
752         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
753
754         if (err)
755                 return 1;
756
757         /* Step 2a : make sure trigger sources are unique */
758
759         err |= cfc_check_trigger_is_unique(cmd->convert_src);
760         err |= cfc_check_trigger_is_unique(cmd->stop_src);
761
762         /* Step 2b : and mutually compatible */
763
764         if (err)
765                 return 2;
766
767         /* Step 3: check if arguments are trivially valid */
768
769         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
770         err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
771
772         if (cmd->convert_src == TRIG_TIMER)
773                 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
774                                                  board->ns_min);
775         else    /* TRIG_EXT */
776                 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
777
778         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
779
780         if (cmd->stop_src == TRIG_COUNT)
781                 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
782         else    /* TRIG_NONE */
783                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
784
785         if (err)
786                 return 3;
787
788         /* step 4: fix up any arguments */
789
790         if (cmd->convert_src == TRIG_TIMER) {
791                 arg = cmd->convert_arg;
792                 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base,
793                                           &devpriv->divisor1,
794                                           &devpriv->divisor2,
795                                           &arg, cmd->flags);
796                 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
797         }
798
799         if (err)
800                 return 4;
801
802         /* step 5: complain about special chanlist considerations */
803
804         if (cmd->chanlist) {
805                 if (!check_channel_list(dev, s, cmd->chanlist,
806                                         cmd->chanlist_len))
807                         return 5;       /*  incorrect channels list */
808         }
809
810         return 0;
811 }
812
813 static int pcl818_ai_cmd(struct comedi_device *dev,
814                          struct comedi_subdevice *s)
815 {
816         struct pcl818_private *devpriv = dev->private;
817         struct comedi_cmd *cmd = &s->async->cmd;
818         unsigned int ctrl = 0;
819         unsigned int seglen;
820
821         if (devpriv->ai_cmd_running)
822                 return -EBUSY;
823
824         pcl818_start_pacer(dev, false);
825
826         seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len);
827         if (seglen < 1)
828                 return -EINVAL;
829         pcl818_ai_setup_chanlist(dev, cmd->chanlist, seglen);
830
831         devpriv->ai_data_len = s->async->prealloc_bufsz;
832         devpriv->ai_act_scan = cmd->stop_arg;
833         devpriv->ai_act_chan = 0;
834         devpriv->ai_cmd_running = 1;
835         devpriv->ai_cmd_canceled = 0;
836         devpriv->act_chanlist_pos = 0;
837         devpriv->dma_runs_to_end = 0;
838
839         if (cmd->convert_src == TRIG_TIMER)
840                 ctrl |= PCL818_CTRL_PACER_TRIG;
841         else
842                 ctrl |= PCL818_CTRL_EXT_TRIG;
843
844         outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG);
845
846         if (devpriv->dma) {
847                 pcl818_ai_setup_dma(dev, s);
848
849                 ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq) |
850                         PCL818_CTRL_DMAE;
851         } else if (devpriv->usefifo) {
852                 /* enable FIFO */
853                 outb(1, dev->iobase + PCL818_FI_ENABLE);
854         } else {
855                 ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq);
856         }
857         outb(ctrl, dev->iobase + PCL818_CTRL_REG);
858
859         if (cmd->convert_src == TRIG_TIMER)
860                 pcl818_start_pacer(dev, true);
861
862         return 0;
863 }
864
865 static int pcl818_ai_cancel(struct comedi_device *dev,
866                             struct comedi_subdevice *s)
867 {
868         struct pcl818_private *devpriv = dev->private;
869         struct comedi_cmd *cmd = &s->async->cmd;
870
871         if (!devpriv->ai_cmd_running)
872                 return 0;
873
874         if (devpriv->dma) {
875                 if (cmd->stop_src == TRIG_NONE ||
876                     (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan > 0)) {
877                         if (!devpriv->ai_cmd_canceled) {
878                                 /*
879                                 * Wait for running dma transfer to end,
880                                 * do cleanup in interrupt.
881                                 */
882                                 devpriv->ai_cmd_canceled = 1;
883                                 return 0;
884                         }
885                 }
886                 disable_dma(devpriv->dma);
887         }
888
889         outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG);
890         pcl818_start_pacer(dev, false);
891         pcl818_ai_clear_eoc(dev);
892
893         if (devpriv->usefifo) { /*  FIFO shutdown */
894                 outb(0, dev->iobase + PCL818_FI_INTCLR);
895                 outb(0, dev->iobase + PCL818_FI_FLUSH);
896                 outb(0, dev->iobase + PCL818_FI_ENABLE);
897         }
898         devpriv->ai_cmd_running = 0;
899         devpriv->ai_cmd_canceled = 0;
900
901         return 0;
902 }
903
904 static int pcl818_ai_insn_read(struct comedi_device *dev,
905                                struct comedi_subdevice *s,
906                                struct comedi_insn *insn,
907                                unsigned int *data)
908 {
909         unsigned int chan = CR_CHAN(insn->chanspec);
910         unsigned int range = CR_RANGE(insn->chanspec);
911         int ret = 0;
912         int i;
913
914         outb(PCL818_CTRL_SOFT_TRIG, dev->iobase + PCL818_CTRL_REG);
915
916         pcl818_ai_set_chan_range(dev, chan, range);
917         pcl818_ai_set_chan_scan(dev, chan, chan);
918
919         for (i = 0; i < insn->n; i++) {
920                 pcl818_ai_clear_eoc(dev);
921                 pcl818_ai_soft_trig(dev);
922
923                 ret = comedi_timeout(dev, s, insn, pcl818_ai_eoc, 0);
924                 if (ret)
925                         break;
926
927                 data[i] = pcl818_ai_get_sample(dev, s, NULL);
928         }
929         pcl818_ai_clear_eoc(dev);
930
931         return ret ? ret : insn->n;
932 }
933
934 static int pcl818_ao_insn_write(struct comedi_device *dev,
935                                 struct comedi_subdevice *s,
936                                 struct comedi_insn *insn,
937                                 unsigned int *data)
938 {
939         unsigned int chan = CR_CHAN(insn->chanspec);
940         unsigned int val = s->readback[chan];
941         int i;
942
943         for (i = 0; i < insn->n; i++) {
944                 val = data[i];
945                 outb((val & 0x000f) << 4,
946                      dev->iobase + PCL818_AO_LSB_REG(chan));
947                 outb((val & 0x0ff0) >> 4,
948                      dev->iobase + PCL818_AO_MSB_REG(chan));
949         }
950         s->readback[chan] = val;
951
952         return insn->n;
953 }
954
955 static int pcl818_di_insn_bits(struct comedi_device *dev,
956                                struct comedi_subdevice *s,
957                                struct comedi_insn *insn,
958                                unsigned int *data)
959 {
960         data[1] = inb(dev->iobase + PCL818_DO_DI_LSB_REG) |
961                   (inb(dev->iobase + PCL818_DO_DI_MSB_REG) << 8);
962
963         return insn->n;
964 }
965
966 static int pcl818_do_insn_bits(struct comedi_device *dev,
967                                struct comedi_subdevice *s,
968                                struct comedi_insn *insn,
969                                unsigned int *data)
970 {
971         if (comedi_dio_update_state(s, data)) {
972                 outb(s->state & 0xff, dev->iobase + PCL818_DO_DI_LSB_REG);
973                 outb((s->state >> 8), dev->iobase + PCL818_DO_DI_MSB_REG);
974         }
975
976         data[1] = s->state;
977
978         return insn->n;
979 }
980
981 static void pcl818_reset(struct comedi_device *dev)
982 {
983         const struct pcl818_board *board = dev->board_ptr;
984         unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE;
985         unsigned int chan;
986
987         /* flush and disable the FIFO */
988         if (board->has_fifo) {
989                 outb(0, dev->iobase + PCL818_FI_INTCLR);
990                 outb(0, dev->iobase + PCL818_FI_FLUSH);
991                 outb(0, dev->iobase + PCL818_FI_ENABLE);
992         }
993
994         /* disable analog input trigger */
995         outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG);
996         pcl818_ai_clear_eoc(dev);
997
998         pcl818_ai_set_chan_range(dev, 0, 0);
999
1000         /* stop pacer */
1001         outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG);
1002         i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY);
1003         i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY);
1004         i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY);
1005
1006         /* set analog output channels to 0V */
1007         for (chan = 0; chan < board->n_aochan; chan++) {
1008                 outb(0, dev->iobase + PCL818_AO_LSB_REG(chan));
1009                 outb(0, dev->iobase + PCL818_AO_MSB_REG(chan));
1010         }
1011
1012         /* set all digital outputs low */
1013         outb(0, dev->iobase + PCL818_DO_DI_MSB_REG);
1014         outb(0, dev->iobase + PCL818_DO_DI_LSB_REG);
1015 }
1016
1017 static void pcl818_set_ai_range_table(struct comedi_device *dev,
1018                                       struct comedi_subdevice *s,
1019                                       struct comedi_devconfig *it)
1020 {
1021         const struct pcl818_board *board = dev->board_ptr;
1022
1023         /* default to the range table from the boardinfo */
1024         s->range_table = board->ai_range_type;
1025
1026         /* now check the user config option based on the boardtype */
1027         if (board->is_818) {
1028                 if (it->options[4] == 1 || it->options[4] == 10) {
1029                         /* secondary range list jumper selectable */
1030                         s->range_table = &range_pcl818l_h_ai;
1031                 }
1032         } else {
1033                 switch (it->options[4]) {
1034                 case 0:
1035                         s->range_table = &range_bipolar10;
1036                         break;
1037                 case 1:
1038                         s->range_table = &range_bipolar5;
1039                         break;
1040                 case 2:
1041                         s->range_table = &range_bipolar2_5;
1042                         break;
1043                 case 3:
1044                         s->range_table = &range718_bipolar1;
1045                         break;
1046                 case 4:
1047                         s->range_table = &range718_bipolar0_5;
1048                         break;
1049                 case 6:
1050                         s->range_table = &range_unipolar10;
1051                         break;
1052                 case 7:
1053                         s->range_table = &range_unipolar5;
1054                         break;
1055                 case 8:
1056                         s->range_table = &range718_unipolar2;
1057                         break;
1058                 case 9:
1059                         s->range_table = &range718_unipolar1;
1060                         break;
1061                 default:
1062                         s->range_table = &range_unknown;
1063                         break;
1064                 }
1065         }
1066 }
1067
1068 static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1069 {
1070         const struct pcl818_board *board = dev->board_ptr;
1071         struct pcl818_private *devpriv;
1072         struct comedi_subdevice *s;
1073         int ret;
1074         int i;
1075
1076         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1077         if (!devpriv)
1078                 return -ENOMEM;
1079
1080         ret = comedi_request_region(dev, it->options[0],
1081                                     board->has_fifo ? 0x20 : 0x10);
1082         if (ret)
1083                 return ret;
1084
1085         /* we can use IRQ 2-7 for async command support */
1086         if (it->options[1] >= 2 && it->options[1] <= 7) {
1087                 ret = request_irq(it->options[1], pcl818_interrupt, 0,
1088                                   dev->board_name, dev);
1089                 if (ret == 0)
1090                         dev->irq = it->options[1];
1091         }
1092
1093         /* should we use the FIFO? */
1094         if (dev->irq && board->has_fifo && it->options[2] == -1)
1095                 devpriv->usefifo = 1;
1096
1097         /* we need an IRQ to do DMA on channel 3 or 1 */
1098         if (dev->irq && board->has_dma &&
1099             (it->options[2] == 3 || it->options[2] == 1)) {
1100                 ret = request_dma(it->options[2], dev->board_name);
1101                 if (ret) {
1102                         dev_err(dev->class_dev,
1103                                 "unable to request DMA channel %d\n",
1104                                 it->options[2]);
1105                         return -EBUSY;
1106                 }
1107                 devpriv->dma = it->options[2];
1108
1109                 devpriv->dmapages = 2;  /* we need 16KB */
1110                 devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
1111
1112                 for (i = 0; i < 2; i++) {
1113                         unsigned long dmabuf;
1114
1115                         dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
1116                         if (!dmabuf)
1117                                 return -ENOMEM;
1118
1119                         devpriv->dmabuf[i] = dmabuf;
1120                         devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
1121                 }
1122         }
1123
1124         ret = comedi_alloc_subdevices(dev, 4);
1125         if (ret)
1126                 return ret;
1127
1128         s = &dev->subdevices[0];
1129         s->type         = COMEDI_SUBD_AI;
1130         s->subdev_flags = SDF_READABLE;
1131         if (check_single_ended(dev->iobase)) {
1132                 s->n_chan       = 16;
1133                 s->subdev_flags |= SDF_COMMON | SDF_GROUND;
1134         } else {
1135                 s->n_chan       = 8;
1136                 s->subdev_flags |= SDF_DIFF;
1137         }
1138         s->maxdata      = 0x0fff;
1139
1140         pcl818_set_ai_range_table(dev, s, it);
1141
1142         s->insn_read    = pcl818_ai_insn_read;
1143         if (dev->irq) {
1144                 dev->read_subdev = s;
1145                 s->subdev_flags |= SDF_CMD_READ;
1146                 s->len_chanlist = s->n_chan;
1147                 s->do_cmdtest   = ai_cmdtest;
1148                 s->do_cmd       = pcl818_ai_cmd;
1149                 s->cancel       = pcl818_ai_cancel;
1150         }
1151
1152         /* Analog Output subdevice */
1153         s = &dev->subdevices[1];
1154         if (board->n_aochan) {
1155                 s->type         = COMEDI_SUBD_AO;
1156                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1157                 s->n_chan       = board->n_aochan;
1158                 s->maxdata      = 0x0fff;
1159                 s->range_table  = &range_unipolar5;
1160                 if (board->is_818) {
1161                         if ((it->options[4] == 1) || (it->options[4] == 10))
1162                                 s->range_table = &range_unipolar10;
1163                         if (it->options[4] == 2)
1164                                 s->range_table = &range_unknown;
1165                 } else {
1166                         if ((it->options[5] == 1) || (it->options[5] == 10))
1167                                 s->range_table = &range_unipolar10;
1168                         if (it->options[5] == 2)
1169                                 s->range_table = &range_unknown;
1170                 }
1171                 s->insn_write   = pcl818_ao_insn_write;
1172                 s->insn_read    = comedi_readback_insn_read;
1173
1174                 ret = comedi_alloc_subdev_readback(s);
1175                 if (ret)
1176                         return ret;
1177         } else {
1178                 s->type         = COMEDI_SUBD_UNUSED;
1179         }
1180
1181         /* Digital Input subdevice */
1182         s = &dev->subdevices[2];
1183         s->type         = COMEDI_SUBD_DI;
1184         s->subdev_flags = SDF_READABLE;
1185         s->n_chan       = 16;
1186         s->maxdata      = 1;
1187         s->range_table  = &range_digital;
1188         s->insn_bits    = pcl818_di_insn_bits;
1189
1190         /* Digital Output subdevice */
1191         s = &dev->subdevices[3];
1192         s->type         = COMEDI_SUBD_DO;
1193         s->subdev_flags = SDF_WRITABLE;
1194         s->n_chan       = 16;
1195         s->maxdata      = 1;
1196         s->range_table  = &range_digital;
1197         s->insn_bits    = pcl818_do_insn_bits;
1198
1199         /* select 1/10MHz oscilator */
1200         if ((it->options[3] == 0) || (it->options[3] == 10))
1201                 devpriv->i8253_osc_base = I8254_OSC_BASE_10MHZ;
1202         else
1203                 devpriv->i8253_osc_base = I8254_OSC_BASE_1MHZ;
1204
1205         /* max sampling speed */
1206         devpriv->ns_min = board->ns_min;
1207
1208         if (!board->is_818) {
1209                 if ((it->options[6] == 1) || (it->options[6] == 100))
1210                         devpriv->ns_min = 10000;        /* extended PCL718 to 100kHz DAC */
1211         }
1212
1213         pcl818_reset(dev);
1214
1215         return 0;
1216 }
1217
1218 static void pcl818_detach(struct comedi_device *dev)
1219 {
1220         struct pcl818_private *devpriv = dev->private;
1221
1222         if (devpriv) {
1223                 pcl818_ai_cancel(dev, dev->read_subdev);
1224                 pcl818_reset(dev);
1225                 if (devpriv->dma)
1226                         free_dma(devpriv->dma);
1227                 if (devpriv->dmabuf[0])
1228                         free_pages(devpriv->dmabuf[0], devpriv->dmapages);
1229                 if (devpriv->dmabuf[1])
1230                         free_pages(devpriv->dmabuf[1], devpriv->dmapages);
1231         }
1232         comedi_legacy_detach(dev);
1233 }
1234
1235 static struct comedi_driver pcl818_driver = {
1236         .driver_name    = "pcl818",
1237         .module         = THIS_MODULE,
1238         .attach         = pcl818_attach,
1239         .detach         = pcl818_detach,
1240         .board_name     = &boardtypes[0].name,
1241         .num_names      = ARRAY_SIZE(boardtypes),
1242         .offset         = sizeof(struct pcl818_board),
1243 };
1244 module_comedi_driver(pcl818_driver);
1245
1246 MODULE_AUTHOR("Comedi http://www.comedi.org");
1247 MODULE_DESCRIPTION("Comedi low-level driver");
1248 MODULE_LICENSE("GPL");