]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/comedi/drivers/pcl818.c
Merge branch 'next' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[karo-tx-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 /* #define PCL818_MODE13_AO 1 */
114
115 /* boards constants */
116
117 #define boardPCL818L 0
118 #define boardPCL818H 1
119 #define boardPCL818HD 2
120 #define boardPCL818HG 3
121 #define boardPCL818 4
122 #define boardPCL718 5
123
124 /* IO space len */
125 #define PCLx1x_RANGE 16
126 /* IO space len if we use FIFO */
127 #define PCLx1xFIFO_RANGE 32
128
129 /* W: clear INT request */
130 #define PCL818_CLRINT 8
131 /* R: return status byte */
132 #define PCL818_STATUS 8
133 /* R: A/D high byte W: A/D range control */
134 #define PCL818_RANGE 1
135 /* R: next mux scan channel W: mux scan channel & range control pointer */
136 #define PCL818_MUX 2
137 /* R/W: operation control register */
138 #define PCL818_CONTROL 9
139 /* W: counter enable */
140 #define PCL818_CNTENABLE 10
141
142 /* R: low byte of A/D W: soft A/D trigger */
143 #define PCL818_AD_LO 0
144 /* R: high byte of A/D W: A/D range control */
145 #define PCL818_AD_HI 1
146 /* W: D/A low&high byte */
147 #define PCL818_DA_LO 4
148 #define PCL818_DA_HI 5
149 /* R: low&high byte of DI */
150 #define PCL818_DI_LO 3
151 #define PCL818_DI_HI 11
152 /* W: low&high byte of DO */
153 #define PCL818_DO_LO 3
154 #define PCL818_DO_HI 11
155 /* W: PCL718 second D/A */
156 #define PCL718_DA2_LO 6
157 #define PCL718_DA2_HI 7
158 /* counters */
159 #define PCL818_CTR0 12
160 #define PCL818_CTR1 13
161 #define PCL818_CTR2 14
162 /* W: counter control */
163 #define PCL818_CTRCTL 15
164
165 /* W: fifo enable/disable */
166 #define PCL818_FI_ENABLE 6
167 /* W: fifo interrupt clear */
168 #define PCL818_FI_INTCLR 20
169 /* W: fifo interrupt clear */
170 #define PCL818_FI_FLUSH 25
171 /* R: fifo status */
172 #define PCL818_FI_STATUS 25
173 /* R: one record from FIFO */
174 #define PCL818_FI_DATALO 23
175 #define PCL818_FI_DATAHI 23
176
177 /* type of interrupt handler */
178 #define INT_TYPE_AI1_INT 1
179 #define INT_TYPE_AI1_DMA 2
180 #define INT_TYPE_AI1_FIFO 3
181 #define INT_TYPE_AI3_INT 4
182 #define INT_TYPE_AI3_DMA 5
183 #define INT_TYPE_AI3_FIFO 6
184 #ifdef PCL818_MODE13_AO
185 #define INT_TYPE_AO1_INT 7
186 #define INT_TYPE_AO3_INT 8
187 #endif
188
189 #define MAGIC_DMA_WORD 0x5a5a
190
191 static const struct comedi_lrange range_pcl818h_ai = { 9, {
192                                                            BIP_RANGE(5),
193                                                            BIP_RANGE(2.5),
194                                                            BIP_RANGE(1.25),
195                                                            BIP_RANGE(0.625),
196                                                            UNI_RANGE(10),
197                                                            UNI_RANGE(5),
198                                                            UNI_RANGE(2.5),
199                                                            UNI_RANGE(1.25),
200                                                            BIP_RANGE(10),
201                                                            }
202 };
203
204 static const struct comedi_lrange range_pcl818hg_ai = { 10, {
205                                                              BIP_RANGE(5),
206                                                              BIP_RANGE(0.5),
207                                                              BIP_RANGE(0.05),
208                                                              BIP_RANGE(0.005),
209                                                              UNI_RANGE(10),
210                                                              UNI_RANGE(1),
211                                                              UNI_RANGE(0.1),
212                                                              UNI_RANGE(0.01),
213                                                              BIP_RANGE(10),
214                                                              BIP_RANGE(1),
215                                                              BIP_RANGE(0.1),
216                                                              BIP_RANGE(0.01),
217                                                              }
218 };
219
220 static const struct comedi_lrange range_pcl818l_l_ai = { 4, {
221                                                              BIP_RANGE(5),
222                                                              BIP_RANGE(2.5),
223                                                              BIP_RANGE(1.25),
224                                                              BIP_RANGE(0.625),
225                                                              }
226 };
227
228 static const struct comedi_lrange range_pcl818l_h_ai = { 4, {
229                                                              BIP_RANGE(10),
230                                                              BIP_RANGE(5),
231                                                              BIP_RANGE(2.5),
232                                                              BIP_RANGE(1.25),
233                                                              }
234 };
235
236 static const struct comedi_lrange range718_bipolar1 = { 1, {BIP_RANGE(1),} };
237 static const struct comedi_lrange range718_bipolar0_5 = {
238         1, {BIP_RANGE(0.5),} };
239 static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} };
240 static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} };
241
242 struct pcl818_board {
243
244         const char *name;       /*  driver name */
245         int n_ranges;           /*  len of range list */
246         int n_aichan_se;        /*  num of A/D chans in single ended  mode */
247         int n_aichan_diff;      /*  num of A/D chans in diferencial mode */
248         unsigned int ns_min;    /*  minimal allowed delay between samples (in ns) */
249         int n_aochan;           /*  num of D/A chans */
250         int n_dichan;           /*  num of DI chans */
251         int n_dochan;           /*  num of DO chans */
252         const struct comedi_lrange *ai_range_type;      /*  default A/D rangelist */
253         const struct comedi_lrange *ao_range_type;      /*  default D/A rangelist */
254         unsigned int io_range;  /*  len of IO space */
255         unsigned int IRQbits;   /*  allowed interrupts */
256         unsigned int DMAbits;   /*  allowed DMA chans */
257         int ai_maxdata;         /*  maxdata for A/D */
258         int ao_maxdata;         /*  maxdata for D/A */
259         unsigned char fifo;     /*  1=board has FIFO */
260         int is_818;
261 };
262
263 struct pcl818_private {
264
265         unsigned int dma;       /*  used DMA, 0=don't use DMA */
266         unsigned int io_range;
267         unsigned long dmabuf[2];        /*  pointers to begin of DMA buffers */
268         unsigned int dmapages[2];       /*  len of DMA buffers in PAGE_SIZEs */
269         unsigned int hwdmaptr[2];       /*  hardware address of DMA buffers */
270         unsigned int hwdmasize[2];      /*  len of DMA buffers in Bytes */
271         int next_dma_buf;       /*  which DMA buffer will be used next round */
272         long dma_runs_to_end;   /*  how many we must permorm DMA transfer to end of record */
273         unsigned long last_dma_run;     /*  how many bytes we must transfer on last DMA page */
274         unsigned char neverending_ai;   /*  if=1, then we do neverending record (you must use cancel()) */
275         unsigned int ns_min;    /*  manimal allowed delay between samples (in us) for actual card */
276         int i8253_osc_base;     /*  1/frequency of on board oscilator in ns */
277         int irq_free;           /*  1=have allocated IRQ */
278         int irq_blocked;        /*  1=IRQ now uses any subdev */
279         int irq_was_now_closed; /*  when IRQ finish, there's stored int818_mode for last interrupt */
280         int ai_mode;            /*  who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
281         struct comedi_subdevice *last_int_sub;  /*  ptr to subdevice which now finish */
282         int ai_act_scan;        /*  how many scans we finished */
283         int ai_act_chan;        /*  actual position in actual scan */
284         unsigned int act_chanlist[16];  /*  MUX setting for actual AI operations */
285         unsigned int act_chanlist_len;  /*  how long is actual MUX list */
286         unsigned int act_chanlist_pos;  /*  actual position in MUX list */
287         unsigned int ai_scans;  /*  len of scanlist */
288         unsigned int ai_n_chan; /*  how many channels is measured */
289         unsigned int *ai_chanlist;      /*  actaul chanlist */
290         unsigned int ai_flags;  /*  flaglist */
291         unsigned int ai_data_len;       /*  len of data buffer */
292         short *ai_data;         /*  data buffer */
293         unsigned int ai_timer1; /*  timers */
294         unsigned int ai_timer2;
295         struct comedi_subdevice *sub_ai;        /*  ptr to AI subdevice */
296         unsigned char usefifo;  /*  1=use fifo */
297         unsigned int ao_readback[2];
298 };
299
300 static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,      /*  used for gain list programming */
301         0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
302 };
303
304 /*
305 ==============================================================================
306 */
307 static void setup_channel_list(struct comedi_device *dev,
308                                struct comedi_subdevice *s,
309                                unsigned int *chanlist, unsigned int n_chan,
310                                unsigned int seglen);
311 static int check_channel_list(struct comedi_device *dev,
312                               struct comedi_subdevice *s,
313                               unsigned int *chanlist, unsigned int n_chan);
314
315 static int pcl818_ai_cancel(struct comedi_device *dev,
316                             struct comedi_subdevice *s);
317 static void start_pacer(struct comedi_device *dev, int mode,
318                         unsigned int divisor1, unsigned int divisor2);
319
320 /*
321 ==============================================================================
322    ANALOG INPUT MODE0, 818 cards, slow version
323 */
324 static int pcl818_ai_insn_read(struct comedi_device *dev,
325                                struct comedi_subdevice *s,
326                                struct comedi_insn *insn, unsigned int *data)
327 {
328         int n;
329         int timeout;
330
331         /* software trigger, DMA and INT off */
332         outb(0, dev->iobase + PCL818_CONTROL);
333
334         /* select channel */
335         outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX);
336
337         /* select gain */
338         outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE);
339
340         for (n = 0; n < insn->n; n++) {
341
342                 /* clear INT (conversion end) flag */
343                 outb(0, dev->iobase + PCL818_CLRINT);
344
345                 /* start conversion */
346                 outb(0, dev->iobase + PCL818_AD_LO);
347
348                 timeout = 100;
349                 while (timeout--) {
350                         if (inb(dev->iobase + PCL818_STATUS) & 0x10)
351                                 goto conv_finish;
352                         udelay(1);
353                 }
354                 comedi_error(dev, "A/D insn timeout");
355                 /* clear INT (conversion end) flag */
356                 outb(0, dev->iobase + PCL818_CLRINT);
357                 return -EIO;
358
359 conv_finish:
360                 data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |
361                            (inb(dev->iobase + PCL818_AD_LO) >> 4));
362         }
363
364         return n;
365 }
366
367 /*
368 ==============================================================================
369    ANALOG OUTPUT MODE0, 818 cards
370    only one sample per call is supported
371 */
372 static int pcl818_ao_insn_read(struct comedi_device *dev,
373                                struct comedi_subdevice *s,
374                                struct comedi_insn *insn, unsigned int *data)
375 {
376         struct pcl818_private *devpriv = dev->private;
377         int n;
378         int chan = CR_CHAN(insn->chanspec);
379
380         for (n = 0; n < insn->n; n++)
381                 data[n] = devpriv->ao_readback[chan];
382
383         return n;
384 }
385
386 static int pcl818_ao_insn_write(struct comedi_device *dev,
387                                 struct comedi_subdevice *s,
388                                 struct comedi_insn *insn, unsigned int *data)
389 {
390         struct pcl818_private *devpriv = dev->private;
391         int n;
392         int chan = CR_CHAN(insn->chanspec);
393
394         for (n = 0; n < insn->n; n++) {
395                 devpriv->ao_readback[chan] = data[n];
396                 outb((data[n] & 0x000f) << 4, dev->iobase +
397                      (chan ? PCL718_DA2_LO : PCL818_DA_LO));
398                 outb((data[n] & 0x0ff0) >> 4, dev->iobase +
399                      (chan ? PCL718_DA2_HI : PCL818_DA_HI));
400         }
401
402         return n;
403 }
404
405 /*
406 ==============================================================================
407    DIGITAL INPUT MODE0, 818 cards
408
409    only one sample per call is supported
410 */
411 static int pcl818_di_insn_bits(struct comedi_device *dev,
412                                struct comedi_subdevice *s,
413                                struct comedi_insn *insn, unsigned int *data)
414 {
415         data[1] = inb(dev->iobase + PCL818_DI_LO) |
416             (inb(dev->iobase + PCL818_DI_HI) << 8);
417
418         return insn->n;
419 }
420
421 /*
422 ==============================================================================
423    DIGITAL OUTPUT MODE0, 818 cards
424
425    only one sample per call is supported
426 */
427 static int pcl818_do_insn_bits(struct comedi_device *dev,
428                                struct comedi_subdevice *s,
429                                struct comedi_insn *insn, unsigned int *data)
430 {
431         s->state &= ~data[0];
432         s->state |= (data[0] & data[1]);
433
434         outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
435         outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
436
437         data[1] = s->state;
438
439         return insn->n;
440 }
441
442 /*
443 ==============================================================================
444    analog input interrupt mode 1 & 3, 818 cards
445    one sample per interrupt version
446 */
447 static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
448 {
449         struct comedi_device *dev = d;
450         struct pcl818_private *devpriv = dev->private;
451         struct comedi_subdevice *s = &dev->subdevices[0];
452         int low;
453         int timeout = 50;       /* wait max 50us */
454
455         while (timeout--) {
456                 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
457                         goto conv_finish;
458                 udelay(1);
459         }
460         outb(0, dev->iobase + PCL818_STATUS);   /* clear INT request */
461         comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
462         pcl818_ai_cancel(dev, s);
463         s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
464         comedi_event(dev, s);
465         return IRQ_HANDLED;
466
467 conv_finish:
468         low = inb(dev->iobase + PCL818_AD_LO);
469         comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4)));        /*  get one sample */
470         outb(0, dev->iobase + PCL818_CLRINT);   /* clear INT request */
471
472         if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) {  /*  dropout! */
473                 printk
474                     ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
475                      (low & 0xf),
476                      devpriv->act_chanlist[devpriv->act_chanlist_pos]);
477                 pcl818_ai_cancel(dev, s);
478                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
479                 comedi_event(dev, s);
480                 return IRQ_HANDLED;
481         }
482         devpriv->act_chanlist_pos++;
483         if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
484                 devpriv->act_chanlist_pos = 0;
485
486         s->async->cur_chan++;
487         if (s->async->cur_chan >= devpriv->ai_n_chan) {
488                 /*  printk("E"); */
489                 s->async->cur_chan = 0;
490                 devpriv->ai_act_scan--;
491         }
492
493         if (!devpriv->neverending_ai) {
494                 if (devpriv->ai_act_scan == 0) {        /* all data sampled */
495                         pcl818_ai_cancel(dev, s);
496                         s->async->events |= COMEDI_CB_EOA;
497                 }
498         }
499         comedi_event(dev, s);
500         return IRQ_HANDLED;
501 }
502
503 /*
504 ==============================================================================
505    analog input dma mode 1 & 3, 818 cards
506 */
507 static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
508 {
509         struct comedi_device *dev = d;
510         struct pcl818_private *devpriv = dev->private;
511         struct comedi_subdevice *s = &dev->subdevices[0];
512         int i, len, bufptr;
513         unsigned long flags;
514         short *ptr;
515
516         disable_dma(devpriv->dma);
517         devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
518         if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) {       /*  switch dma bufs */
519                 set_dma_mode(devpriv->dma, DMA_MODE_READ);
520                 flags = claim_dma_lock();
521                 set_dma_addr(devpriv->dma,
522                              devpriv->hwdmaptr[devpriv->next_dma_buf]);
523                 if (devpriv->dma_runs_to_end || devpriv->neverending_ai) {
524                         set_dma_count(devpriv->dma,
525                                       devpriv->hwdmasize[devpriv->
526                                                          next_dma_buf]);
527                 } else {
528                         set_dma_count(devpriv->dma, devpriv->last_dma_run);
529                 }
530                 release_dma_lock(flags);
531                 enable_dma(devpriv->dma);
532         }
533         printk("comedi: A/D mode1/3 IRQ \n");
534
535         devpriv->dma_runs_to_end--;
536         outb(0, dev->iobase + PCL818_CLRINT);   /* clear INT request */
537         ptr = (short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
538
539         len = devpriv->hwdmasize[0] >> 1;
540         bufptr = 0;
541
542         for (i = 0; i < len; i++) {
543                 if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) {  /*  dropout! */
544                         printk
545                             ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
546                              (ptr[bufptr] & 0xf),
547                              devpriv->act_chanlist[devpriv->act_chanlist_pos],
548                              devpriv->act_chanlist_pos);
549                         pcl818_ai_cancel(dev, s);
550                         s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
551                         comedi_event(dev, s);
552                         return IRQ_HANDLED;
553                 }
554
555                 comedi_buf_put(s->async, ptr[bufptr++] >> 4);   /*  get one sample */
556
557                 devpriv->act_chanlist_pos++;
558                 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
559                         devpriv->act_chanlist_pos = 0;
560
561                 s->async->cur_chan++;
562                 if (s->async->cur_chan >= devpriv->ai_n_chan) {
563                         s->async->cur_chan = 0;
564                         devpriv->ai_act_scan--;
565                 }
566
567                 if (!devpriv->neverending_ai)
568                         if (devpriv->ai_act_scan == 0) {        /* all data sampled */
569                                 pcl818_ai_cancel(dev, s);
570                                 s->async->events |= COMEDI_CB_EOA;
571                                 comedi_event(dev, s);
572                                 /*  printk("done int ai13 dma\n"); */
573                                 return IRQ_HANDLED;
574                         }
575         }
576
577         if (len > 0)
578                 comedi_event(dev, s);
579         return IRQ_HANDLED;
580 }
581
582 /*
583 ==============================================================================
584    analog input interrupt mode 1 & 3, 818HD/HG cards
585 */
586 static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
587 {
588         struct comedi_device *dev = d;
589         struct pcl818_private *devpriv = dev->private;
590         struct comedi_subdevice *s = &dev->subdevices[0];
591         int i, len, lo;
592
593         outb(0, dev->iobase + PCL818_FI_INTCLR);        /*  clear fifo int request */
594
595         lo = inb(dev->iobase + PCL818_FI_STATUS);
596
597         if (lo & 4) {
598                 comedi_error(dev, "A/D mode1/3 FIFO overflow!");
599                 pcl818_ai_cancel(dev, s);
600                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
601                 comedi_event(dev, s);
602                 return IRQ_HANDLED;
603         }
604
605         if (lo & 1) {
606                 comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!");
607                 pcl818_ai_cancel(dev, s);
608                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
609                 comedi_event(dev, s);
610                 return IRQ_HANDLED;
611         }
612
613         if (lo & 2)
614                 len = 512;
615         else
616                 len = 0;
617
618         for (i = 0; i < len; i++) {
619                 lo = inb(dev->iobase + PCL818_FI_DATALO);
620                 if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) {   /*  dropout! */
621                         printk
622                             ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
623                              (lo & 0xf),
624                              devpriv->act_chanlist[devpriv->act_chanlist_pos]);
625                         pcl818_ai_cancel(dev, s);
626                         s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
627                         comedi_event(dev, s);
628                         return IRQ_HANDLED;
629                 }
630
631                 comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4));       /*  get one sample */
632
633                 devpriv->act_chanlist_pos++;
634                 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
635                         devpriv->act_chanlist_pos = 0;
636
637                 s->async->cur_chan++;
638                 if (s->async->cur_chan >= devpriv->ai_n_chan) {
639                         s->async->cur_chan = 0;
640                         devpriv->ai_act_scan--;
641                 }
642
643                 if (!devpriv->neverending_ai)
644                         if (devpriv->ai_act_scan == 0) {        /* all data sampled */
645                                 pcl818_ai_cancel(dev, s);
646                                 s->async->events |= COMEDI_CB_EOA;
647                                 comedi_event(dev, s);
648                                 return IRQ_HANDLED;
649                         }
650         }
651
652         if (len > 0)
653                 comedi_event(dev, s);
654         return IRQ_HANDLED;
655 }
656
657 /*
658 ==============================================================================
659     INT procedure
660 */
661 static irqreturn_t interrupt_pcl818(int irq, void *d)
662 {
663         struct comedi_device *dev = d;
664         struct pcl818_private *devpriv = dev->private;
665
666         if (!dev->attached) {
667                 comedi_error(dev, "premature interrupt");
668                 return IRQ_HANDLED;
669         }
670         /* printk("I\n"); */
671
672         if (devpriv->irq_blocked && devpriv->irq_was_now_closed) {
673                 if ((devpriv->neverending_ai || (!devpriv->neverending_ai &&
674                                                  devpriv->ai_act_scan > 0)) &&
675                     (devpriv->ai_mode == INT_TYPE_AI1_DMA ||
676                      devpriv->ai_mode == INT_TYPE_AI3_DMA)) {
677                         /* The cleanup from ai_cancel() has been delayed
678                            until now because the card doesn't seem to like
679                            being reprogrammed while a DMA transfer is in
680                            progress.
681                          */
682                         struct comedi_subdevice *s = &dev->subdevices[0];
683                         devpriv->ai_act_scan = 0;
684                         devpriv->neverending_ai = 0;
685                         pcl818_ai_cancel(dev, s);
686                 }
687
688                 outb(0, dev->iobase + PCL818_CLRINT);   /* clear INT request */
689
690                 return IRQ_HANDLED;
691         }
692
693         switch (devpriv->ai_mode) {
694         case INT_TYPE_AI1_DMA:
695         case INT_TYPE_AI3_DMA:
696                 return interrupt_pcl818_ai_mode13_dma(irq, d);
697         case INT_TYPE_AI1_INT:
698         case INT_TYPE_AI3_INT:
699                 return interrupt_pcl818_ai_mode13_int(irq, d);
700         case INT_TYPE_AI1_FIFO:
701         case INT_TYPE_AI3_FIFO:
702                 return interrupt_pcl818_ai_mode13_fifo(irq, d);
703 #ifdef PCL818_MODE13_AO
704         case INT_TYPE_AO1_INT:
705         case INT_TYPE_AO3_INT:
706                 return interrupt_pcl818_ao_mode13_int(irq, d);
707 #endif
708         default:
709                 break;
710         }
711
712         outb(0, dev->iobase + PCL818_CLRINT);   /* clear INT request */
713
714         if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked)
715             || (!devpriv->ai_mode)) {
716                 comedi_error(dev, "bad IRQ!");
717                 return IRQ_NONE;
718         }
719
720         comedi_error(dev, "IRQ from unknown source!");
721         return IRQ_NONE;
722 }
723
724 /*
725 ==============================================================================
726    ANALOG INPUT MODE 1 or 3 DMA , 818 cards
727 */
728 static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev,
729                                     struct comedi_subdevice *s)
730 {
731         struct pcl818_private *devpriv = dev->private;
732         unsigned int flags;
733         unsigned int bytes;
734
735         printk("mode13dma_int, mode: %d\n", mode);
736         disable_dma(devpriv->dma);      /*  disable dma */
737         bytes = devpriv->hwdmasize[0];
738         if (!devpriv->neverending_ai) {
739                 bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /*  how many */
740                 devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0];       /*  how many DMA pages we must fiil */
741                 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0];  /* on last dma transfer must be moved */
742                 devpriv->dma_runs_to_end--;
743                 if (devpriv->dma_runs_to_end >= 0)
744                         bytes = devpriv->hwdmasize[0];
745         }
746
747         devpriv->next_dma_buf = 0;
748         set_dma_mode(devpriv->dma, DMA_MODE_READ);
749         flags = claim_dma_lock();
750         clear_dma_ff(devpriv->dma);
751         set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
752         set_dma_count(devpriv->dma, bytes);
753         release_dma_lock(flags);
754         enable_dma(devpriv->dma);
755
756         if (mode == 1) {
757                 devpriv->ai_mode = INT_TYPE_AI1_DMA;
758                 outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);     /* Pacer+IRQ+DMA */
759         } else {
760                 devpriv->ai_mode = INT_TYPE_AI3_DMA;
761                 outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);     /* Ext trig+IRQ+DMA */
762         };
763 }
764
765 /*
766 ==============================================================================
767    ANALOG INPUT MODE 1 or 3, 818 cards
768 */
769 static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
770                               struct comedi_subdevice *s)
771 {
772         struct pcl818_private *devpriv = dev->private;
773         struct comedi_cmd *cmd = &s->async->cmd;
774         int divisor1 = 0, divisor2 = 0;
775         unsigned int seglen;
776
777         dev_dbg(dev->class_dev, "pcl818_ai_cmd_mode()\n");
778         if (!dev->irq) {
779                 comedi_error(dev, "IRQ not defined!");
780                 return -EINVAL;
781         }
782
783         if (devpriv->irq_blocked)
784                 return -EBUSY;
785
786         start_pacer(dev, -1, 0, 0);     /*  stop pacer */
787
788         seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
789                                     devpriv->ai_n_chan);
790         if (seglen < 1)
791                 return -EINVAL;
792         setup_channel_list(dev, s, devpriv->ai_chanlist,
793                            devpriv->ai_n_chan, seglen);
794
795         udelay(1);
796
797         devpriv->ai_act_scan = devpriv->ai_scans;
798         devpriv->ai_act_chan = 0;
799         devpriv->irq_blocked = 1;
800         devpriv->irq_was_now_closed = 0;
801         devpriv->neverending_ai = 0;
802         devpriv->act_chanlist_pos = 0;
803         devpriv->dma_runs_to_end = 0;
804
805         if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
806                 devpriv->neverending_ai = 1;    /* well, user want neverending */
807
808         if (mode == 1) {
809                 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
810                                           &divisor2, &cmd->convert_arg,
811                                           TRIG_ROUND_NEAREST);
812                 if (divisor1 == 1) {    /* PCL718/818 crash if any divisor is set to 1 */
813                         divisor1 = 2;
814                         divisor2 /= 2;
815                 }
816                 if (divisor2 == 1) {
817                         divisor2 = 2;
818                         divisor1 /= 2;
819                 }
820         }
821
822         outb(0, dev->iobase + PCL818_CNTENABLE);        /* enable pacer */
823
824         switch (devpriv->dma) {
825         case 1:         /*  DMA */
826         case 3:
827                 pcl818_ai_mode13dma_int(mode, dev, s);
828                 break;
829         case 0:
830                 if (!devpriv->usefifo) {
831                         /* IRQ */
832                         /* printk("IRQ\n"); */
833                         if (mode == 1) {
834                                 devpriv->ai_mode = INT_TYPE_AI1_INT;
835                                 /* Pacer+IRQ */
836                                 outb(0x83 | (dev->irq << 4),
837                                      dev->iobase + PCL818_CONTROL);
838                         } else {
839                                 devpriv->ai_mode = INT_TYPE_AI3_INT;
840                                 /* Ext trig+IRQ */
841                                 outb(0x82 | (dev->irq << 4),
842                                      dev->iobase + PCL818_CONTROL);
843                         }
844                 } else {
845                         /* FIFO */
846                         /* enable FIFO */
847                         outb(1, dev->iobase + PCL818_FI_ENABLE);
848                         if (mode == 1) {
849                                 devpriv->ai_mode = INT_TYPE_AI1_FIFO;
850                                 /* Pacer */
851                                 outb(0x03, dev->iobase + PCL818_CONTROL);
852                         } else {
853                                 devpriv->ai_mode = INT_TYPE_AI3_FIFO;
854                                 outb(0x02, dev->iobase + PCL818_CONTROL);
855                         }
856                 }
857         }
858
859         start_pacer(dev, mode, divisor1, divisor2);
860
861         dev_dbg(dev->class_dev, "pcl818_ai_cmd_mode() end\n");
862         return 0;
863 }
864
865 /*
866 ==============================================================================
867  Start/stop pacer onboard pacer
868 */
869 static void start_pacer(struct comedi_device *dev, int mode,
870                         unsigned int divisor1, unsigned int divisor2)
871 {
872         outb(0xb4, dev->iobase + PCL818_CTRCTL);
873         outb(0x74, dev->iobase + PCL818_CTRCTL);
874         udelay(1);
875
876         if (mode == 1) {
877                 outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
878                 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
879                 outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
880                 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
881         }
882 }
883
884 /*
885 ==============================================================================
886  Check if channel list from user is builded correctly
887  If it's ok, then program scan/gain logic
888 */
889 static int check_channel_list(struct comedi_device *dev,
890                               struct comedi_subdevice *s,
891                               unsigned int *chanlist, unsigned int n_chan)
892 {
893         unsigned int chansegment[16];
894         unsigned int i, nowmustbechan, seglen, segpos;
895
896         /* correct channel and range number check itself comedi/range.c */
897         if (n_chan < 1) {
898                 comedi_error(dev, "range/channel list is empty!");
899                 return 0;
900         }
901
902         if (n_chan > 1) {
903                 /*  first channel is every time ok */
904                 chansegment[0] = chanlist[0];
905                 /*  build part of chanlist */
906                 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
907
908                         /* printk("%d. %d * %d\n",i,
909                          * CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));*/
910
911                         /* we detect loop, this must by finish */
912
913                         if (chanlist[0] == chanlist[i])
914                                 break;
915                         nowmustbechan =
916                             (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
917                         if (nowmustbechan != CR_CHAN(chanlist[i])) {    /*  channel list isn't continuous :-( */
918                                 printk
919                                     ("comedi%d: pcl818: channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
920                                      dev->minor, i, CR_CHAN(chanlist[i]),
921                                      nowmustbechan, CR_CHAN(chanlist[0]));
922                                 return 0;
923                         }
924                         /*  well, this is next correct channel in list */
925                         chansegment[i] = chanlist[i];
926                 }
927
928                 /*  check whole chanlist */
929                 for (i = 0, segpos = 0; i < n_chan; i++) {
930                         /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i])); */
931                         if (chanlist[i] != chansegment[i % seglen]) {
932                                 printk
933                                     ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
934                                      dev->minor, i, CR_CHAN(chansegment[i]),
935                                      CR_RANGE(chansegment[i]),
936                                      CR_AREF(chansegment[i]),
937                                      CR_CHAN(chanlist[i % seglen]),
938                                      CR_RANGE(chanlist[i % seglen]),
939                                      CR_AREF(chansegment[i % seglen]));
940                                 return 0;       /*  chan/gain list is strange */
941                         }
942                 }
943         } else {
944                 seglen = 1;
945         }
946         printk("check_channel_list: seglen %d\n", seglen);
947         return seglen;
948 }
949
950 static void setup_channel_list(struct comedi_device *dev,
951                                struct comedi_subdevice *s,
952                                unsigned int *chanlist, unsigned int n_chan,
953                                unsigned int seglen)
954 {
955         struct pcl818_private *devpriv = dev->private;
956         int i;
957
958         devpriv->act_chanlist_len = seglen;
959         devpriv->act_chanlist_pos = 0;
960
961         for (i = 0; i < seglen; i++) {  /*  store range list to card */
962                 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
963                 outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX);       /* select channel */
964                 outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE);        /* select gain */
965         }
966
967         udelay(1);
968
969         /* select channel interval to scan */
970         outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen -
971                                                                1] << 4),
972              dev->iobase + PCL818_MUX);
973 }
974
975 /*
976 ==============================================================================
977  Check if board is switched to SE (1) or DIFF(0) mode
978 */
979 static int check_single_ended(unsigned int port)
980 {
981         if (inb(port + PCL818_STATUS) & 0x20)
982                 return 1;
983         return 0;
984 }
985
986 /*
987 ==============================================================================
988 */
989 static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
990                       struct comedi_cmd *cmd)
991 {
992         const struct pcl818_board *board = comedi_board(dev);
993         struct pcl818_private *devpriv = dev->private;
994         int err = 0;
995         int tmp, divisor1 = 0, divisor2 = 0;
996
997         /* Step 1 : check if triggers are trivially valid */
998
999         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
1000         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
1001         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
1002         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1003         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
1004
1005         if (err)
1006                 return 1;
1007
1008         /* Step 2a : make sure trigger sources are unique */
1009
1010         err |= cfc_check_trigger_is_unique(cmd->convert_src);
1011         err |= cfc_check_trigger_is_unique(cmd->stop_src);
1012
1013         /* Step 2b : and mutually compatible */
1014
1015         if (err)
1016                 return 2;
1017
1018         /* Step 3: check if arguments are trivially valid */
1019
1020         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
1021         err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
1022
1023         if (cmd->convert_src == TRIG_TIMER)
1024                 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
1025                                                  board->ns_min);
1026         else    /* TRIG_EXT */
1027                 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
1028
1029         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1030
1031         if (cmd->stop_src == TRIG_COUNT)
1032                 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
1033         else    /* TRIG_NONE */
1034                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
1035
1036         if (err)
1037                 return 3;
1038
1039         /* step 4: fix up any arguments */
1040
1041         if (cmd->convert_src == TRIG_TIMER) {
1042                 tmp = cmd->convert_arg;
1043                 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1044                                           &divisor2, &cmd->convert_arg,
1045                                           cmd->flags & TRIG_ROUND_MASK);
1046                 if (cmd->convert_arg < board->ns_min)
1047                         cmd->convert_arg = board->ns_min;
1048                 if (tmp != cmd->convert_arg)
1049                         err++;
1050         }
1051
1052         if (err)
1053                 return 4;
1054
1055         /* step 5: complain about special chanlist considerations */
1056
1057         if (cmd->chanlist) {
1058                 if (!check_channel_list(dev, s, cmd->chanlist,
1059                                         cmd->chanlist_len))
1060                         return 5;       /*  incorrect channels list */
1061         }
1062
1063         return 0;
1064 }
1065
1066 /*
1067 ==============================================================================
1068 */
1069 static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1070 {
1071         struct pcl818_private *devpriv = dev->private;
1072         struct comedi_cmd *cmd = &s->async->cmd;
1073         int retval;
1074
1075         dev_dbg(dev->class_dev, "pcl818_ai_cmd()\n");
1076         devpriv->ai_n_chan = cmd->chanlist_len;
1077         devpriv->ai_chanlist = cmd->chanlist;
1078         devpriv->ai_flags = cmd->flags;
1079         devpriv->ai_data_len = s->async->prealloc_bufsz;
1080         devpriv->ai_data = s->async->prealloc_buf;
1081         devpriv->ai_timer1 = 0;
1082         devpriv->ai_timer2 = 0;
1083
1084         if (cmd->stop_src == TRIG_COUNT)
1085                 devpriv->ai_scans = cmd->stop_arg;
1086         else
1087                 devpriv->ai_scans = 0;
1088
1089         if (cmd->scan_begin_src == TRIG_FOLLOW) {       /*  mode 1, 3 */
1090                 if (cmd->convert_src == TRIG_TIMER) {   /*  mode 1 */
1091                         devpriv->ai_timer1 = cmd->convert_arg;
1092                         retval = pcl818_ai_cmd_mode(1, dev, s);
1093                         dev_dbg(dev->class_dev, "pcl818_ai_cmd() end\n");
1094                         return retval;
1095                 }
1096                 if (cmd->convert_src == TRIG_EXT) {     /*  mode 3 */
1097                         return pcl818_ai_cmd_mode(3, dev, s);
1098                 }
1099         }
1100
1101         return -1;
1102 }
1103
1104 /*
1105 ==============================================================================
1106  cancel any mode 1-4 AI
1107 */
1108 static int pcl818_ai_cancel(struct comedi_device *dev,
1109                             struct comedi_subdevice *s)
1110 {
1111         struct pcl818_private *devpriv = dev->private;
1112
1113         if (devpriv->irq_blocked > 0) {
1114                 dev_dbg(dev->class_dev, "pcl818_ai_cancel()\n");
1115                 devpriv->irq_was_now_closed = 1;
1116
1117                 switch (devpriv->ai_mode) {
1118                 case INT_TYPE_AI1_DMA:
1119                 case INT_TYPE_AI3_DMA:
1120                         if (devpriv->neverending_ai ||
1121                             (!devpriv->neverending_ai &&
1122                              devpriv->ai_act_scan > 0)) {
1123                                 /* wait for running dma transfer to end, do cleanup in interrupt */
1124                                 goto end;
1125                         }
1126                         disable_dma(devpriv->dma);
1127                 case INT_TYPE_AI1_INT:
1128                 case INT_TYPE_AI3_INT:
1129                 case INT_TYPE_AI1_FIFO:
1130                 case INT_TYPE_AI3_FIFO:
1131 #ifdef PCL818_MODE13_AO
1132                 case INT_TYPE_AO1_INT:
1133                 case INT_TYPE_AO3_INT:
1134 #endif
1135                         outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL);   /* Stop A/D */
1136                         udelay(1);
1137                         start_pacer(dev, -1, 0, 0);
1138                         outb(0, dev->iobase + PCL818_AD_LO);
1139                         inb(dev->iobase + PCL818_AD_LO);
1140                         inb(dev->iobase + PCL818_AD_HI);
1141                         outb(0, dev->iobase + PCL818_CLRINT);   /* clear INT request */
1142                         outb(0, dev->iobase + PCL818_CONTROL);  /* Stop A/D */
1143                         if (devpriv->usefifo) { /*  FIFO shutdown */
1144                                 outb(0, dev->iobase + PCL818_FI_INTCLR);
1145                                 outb(0, dev->iobase + PCL818_FI_FLUSH);
1146                                 outb(0, dev->iobase + PCL818_FI_ENABLE);
1147                         }
1148                         devpriv->irq_blocked = 0;
1149                         devpriv->last_int_sub = s;
1150                         devpriv->neverending_ai = 0;
1151                         devpriv->ai_mode = 0;
1152                         devpriv->irq_was_now_closed = 0;
1153                         break;
1154                 }
1155         }
1156
1157 end:
1158         dev_dbg(dev->class_dev, "pcl818_ai_cancel() end\n");
1159         return 0;
1160 }
1161
1162 /*
1163 ==============================================================================
1164  chech for PCL818
1165 */
1166 static int pcl818_check(unsigned long iobase)
1167 {
1168         outb(0x00, iobase + PCL818_MUX);
1169         udelay(1);
1170         if (inb(iobase + PCL818_MUX) != 0x00)
1171                 return 1;       /* there isn't card */
1172         outb(0x55, iobase + PCL818_MUX);
1173         udelay(1);
1174         if (inb(iobase + PCL818_MUX) != 0x55)
1175                 return 1;       /* there isn't card */
1176         outb(0x00, iobase + PCL818_MUX);
1177         udelay(1);
1178         outb(0x18, iobase + PCL818_CONTROL);
1179         udelay(1);
1180         if (inb(iobase + PCL818_CONTROL) != 0x18)
1181                 return 1;       /* there isn't card */
1182         return 0;               /*  ok, card exist */
1183 }
1184
1185 /*
1186 ==============================================================================
1187  reset whole PCL-818 cards
1188 */
1189 static void pcl818_reset(struct comedi_device *dev)
1190 {
1191         const struct pcl818_board *board = comedi_board(dev);
1192         struct pcl818_private *devpriv = dev->private;
1193
1194         if (devpriv->usefifo) { /*  FIFO shutdown */
1195                 outb(0, dev->iobase + PCL818_FI_INTCLR);
1196                 outb(0, dev->iobase + PCL818_FI_FLUSH);
1197                 outb(0, dev->iobase + PCL818_FI_ENABLE);
1198         }
1199         outb(0, dev->iobase + PCL818_DA_LO);    /*  DAC=0V */
1200         outb(0, dev->iobase + PCL818_DA_HI);
1201         udelay(1);
1202         outb(0, dev->iobase + PCL818_DO_HI);    /*  DO=$0000 */
1203         outb(0, dev->iobase + PCL818_DO_LO);
1204         udelay(1);
1205         outb(0, dev->iobase + PCL818_CONTROL);
1206         outb(0, dev->iobase + PCL818_CNTENABLE);
1207         outb(0, dev->iobase + PCL818_MUX);
1208         outb(0, dev->iobase + PCL818_CLRINT);
1209         outb(0xb0, dev->iobase + PCL818_CTRCTL);        /* Stop pacer */
1210         outb(0x70, dev->iobase + PCL818_CTRCTL);
1211         outb(0x30, dev->iobase + PCL818_CTRCTL);
1212         if (board->is_818) {
1213                 outb(0, dev->iobase + PCL818_RANGE);
1214         } else {
1215                 outb(0, dev->iobase + PCL718_DA2_LO);
1216                 outb(0, dev->iobase + PCL718_DA2_HI);
1217         }
1218 }
1219
1220 static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1221 {
1222         const struct pcl818_board *board = comedi_board(dev);
1223         struct pcl818_private *devpriv;
1224         int ret;
1225         unsigned int irq;
1226         int dma;
1227         unsigned long pages;
1228         struct comedi_subdevice *s;
1229
1230         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1231         if (!devpriv)
1232                 return -ENOMEM;
1233
1234         devpriv->io_range = board->io_range;
1235         if ((board->fifo) && (it->options[2] == -1)) {
1236                 /*  we've board with FIFO and we want to use FIFO */
1237                 devpriv->io_range = PCLx1xFIFO_RANGE;
1238                 devpriv->usefifo = 1;
1239         }
1240         ret = comedi_request_region(dev, it->options[0], devpriv->io_range);
1241         if (ret)
1242                 return ret;
1243
1244         if (pcl818_check(dev->iobase)) {
1245                 comedi_error(dev, "I can't detect board. FAIL!\n");
1246                 return -EIO;
1247         }
1248
1249         /* grab our IRQ */
1250         irq = 0;
1251         if (board->IRQbits != 0) {      /* board support IRQ */
1252                 irq = it->options[1];
1253                 if (irq) {      /* we want to use IRQ */
1254                         if (((1 << irq) & board->IRQbits) == 0) {
1255                                 printk
1256                                     (", IRQ %u is out of allowed range, DISABLING IT",
1257                                      irq);
1258                                 irq = 0;        /* Bad IRQ */
1259                         } else {
1260                                 if (request_irq(irq, interrupt_pcl818, 0,
1261                                                 dev->board_name, dev)) {
1262                                         printk
1263                                             (", unable to allocate IRQ %u, DISABLING IT",
1264                                              irq);
1265                                         irq = 0;        /* Can't use IRQ */
1266                                 } else {
1267                                         printk(KERN_DEBUG "irq=%u", irq);
1268                                 }
1269                         }
1270                 }
1271         }
1272
1273         dev->irq = irq;
1274         if (irq)
1275                 devpriv->irq_free = 1;   /* 1=we have allocated irq */
1276         else
1277                 devpriv->irq_free = 0;
1278
1279         devpriv->irq_blocked = 0;       /* number of subdevice which use IRQ */
1280         devpriv->ai_mode = 0;   /* mode of irq */
1281
1282         /* grab our DMA */
1283         dma = 0;
1284         devpriv->dma = dma;
1285         if (!devpriv->irq_free)
1286                 goto no_dma;    /* if we haven't IRQ, we can't use DMA */
1287         if (board->DMAbits != 0) {      /* board support DMA */
1288                 dma = it->options[2];
1289                 if (dma < 1)
1290                         goto no_dma;    /* DMA disabled */
1291                 if (((1 << dma) & board->DMAbits) == 0) {
1292                         printk(KERN_ERR "DMA is out of allowed range, FAIL!\n");
1293                         return -EINVAL; /* Bad DMA */
1294                 }
1295                 ret = request_dma(dma, dev->board_name);
1296                 if (ret)
1297                         return -EBUSY;  /* DMA isn't free */
1298                 devpriv->dma = dma;
1299                 pages = 2;      /* we need 16KB */
1300                 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1301                 if (!devpriv->dmabuf[0])
1302                         /* maybe experiment with try_to_free_pages() will help .... */
1303                         return -EBUSY;  /* no buffer :-( */
1304                 devpriv->dmapages[0] = pages;
1305                 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1306                 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
1307                 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
1308                 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1309                 if (!devpriv->dmabuf[1])
1310                         return -EBUSY;
1311                 devpriv->dmapages[1] = pages;
1312                 devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
1313                 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1314         }
1315
1316 no_dma:
1317
1318         ret = comedi_alloc_subdevices(dev, 4);
1319         if (ret)
1320                 return ret;
1321
1322         s = &dev->subdevices[0];
1323         if (!board->n_aichan_se) {
1324                 s->type = COMEDI_SUBD_UNUSED;
1325         } else {
1326                 s->type = COMEDI_SUBD_AI;
1327                 devpriv->sub_ai = s;
1328                 s->subdev_flags = SDF_READABLE;
1329                 if (check_single_ended(dev->iobase)) {
1330                         s->n_chan = board->n_aichan_se;
1331                         s->subdev_flags |= SDF_COMMON | SDF_GROUND;
1332                         printk(", %dchans S.E. DAC", s->n_chan);
1333                 } else {
1334                         s->n_chan = board->n_aichan_diff;
1335                         s->subdev_flags |= SDF_DIFF;
1336                         printk(", %dchans DIFF DAC", s->n_chan);
1337                 }
1338                 s->maxdata = board->ai_maxdata;
1339                 s->len_chanlist = s->n_chan;
1340                 s->range_table = board->ai_range_type;
1341                 s->cancel = pcl818_ai_cancel;
1342                 s->insn_read = pcl818_ai_insn_read;
1343                 if (irq) {
1344                         dev->read_subdev = s;
1345                         s->subdev_flags |= SDF_CMD_READ;
1346                         s->do_cmdtest = ai_cmdtest;
1347                         s->do_cmd = ai_cmd;
1348                 }
1349                 if (board->is_818) {
1350                         if ((it->options[4] == 1) || (it->options[4] == 10))
1351                                 s->range_table = &range_pcl818l_h_ai;   /*  secondary range list jumper selectable */
1352                 } else {
1353                         switch (it->options[4]) {
1354                         case 0:
1355                                 s->range_table = &range_bipolar10;
1356                                 break;
1357                         case 1:
1358                                 s->range_table = &range_bipolar5;
1359                                 break;
1360                         case 2:
1361                                 s->range_table = &range_bipolar2_5;
1362                                 break;
1363                         case 3:
1364                                 s->range_table = &range718_bipolar1;
1365                                 break;
1366                         case 4:
1367                                 s->range_table = &range718_bipolar0_5;
1368                                 break;
1369                         case 6:
1370                                 s->range_table = &range_unipolar10;
1371                                 break;
1372                         case 7:
1373                                 s->range_table = &range_unipolar5;
1374                                 break;
1375                         case 8:
1376                                 s->range_table = &range718_unipolar2;
1377                                 break;
1378                         case 9:
1379                                 s->range_table = &range718_unipolar1;
1380                                 break;
1381                         default:
1382                                 s->range_table = &range_unknown;
1383                                 break;
1384                         }
1385                 }
1386         }
1387
1388         s = &dev->subdevices[1];
1389         if (!board->n_aochan) {
1390                 s->type = COMEDI_SUBD_UNUSED;
1391         } else {
1392                 s->type = COMEDI_SUBD_AO;
1393                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1394                 s->n_chan = board->n_aochan;
1395                 s->maxdata = board->ao_maxdata;
1396                 s->len_chanlist = board->n_aochan;
1397                 s->range_table = board->ao_range_type;
1398                 s->insn_read = pcl818_ao_insn_read;
1399                 s->insn_write = pcl818_ao_insn_write;
1400                 if (board->is_818) {
1401                         if ((it->options[4] == 1) || (it->options[4] == 10))
1402                                 s->range_table = &range_unipolar10;
1403                         if (it->options[4] == 2)
1404                                 s->range_table = &range_unknown;
1405                 } else {
1406                         if ((it->options[5] == 1) || (it->options[5] == 10))
1407                                 s->range_table = &range_unipolar10;
1408                         if (it->options[5] == 2)
1409                                 s->range_table = &range_unknown;
1410                 }
1411         }
1412
1413         s = &dev->subdevices[2];
1414         if (!board->n_dichan) {
1415                 s->type = COMEDI_SUBD_UNUSED;
1416         } else {
1417                 s->type = COMEDI_SUBD_DI;
1418                 s->subdev_flags = SDF_READABLE;
1419                 s->n_chan = board->n_dichan;
1420                 s->maxdata = 1;
1421                 s->len_chanlist = board->n_dichan;
1422                 s->range_table = &range_digital;
1423                 s->insn_bits = pcl818_di_insn_bits;
1424         }
1425
1426         s = &dev->subdevices[3];
1427         if (!board->n_dochan) {
1428                 s->type = COMEDI_SUBD_UNUSED;
1429         } else {
1430                 s->type = COMEDI_SUBD_DO;
1431                 s->subdev_flags = SDF_WRITABLE;
1432                 s->n_chan = board->n_dochan;
1433                 s->maxdata = 1;
1434                 s->len_chanlist = board->n_dochan;
1435                 s->range_table = &range_digital;
1436                 s->insn_bits = pcl818_do_insn_bits;
1437         }
1438
1439         /* select 1/10MHz oscilator */
1440         if ((it->options[3] == 0) || (it->options[3] == 10))
1441                 devpriv->i8253_osc_base = 100;
1442         else
1443                 devpriv->i8253_osc_base = 1000;
1444
1445         /* max sampling speed */
1446         devpriv->ns_min = board->ns_min;
1447
1448         if (!board->is_818) {
1449                 if ((it->options[6] == 1) || (it->options[6] == 100))
1450                         devpriv->ns_min = 10000;        /* extended PCL718 to 100kHz DAC */
1451         }
1452
1453         pcl818_reset(dev);
1454
1455         printk("\n");
1456
1457         return 0;
1458 }
1459
1460 static void pcl818_detach(struct comedi_device *dev)
1461 {
1462         struct pcl818_private *devpriv = dev->private;
1463
1464         if (devpriv) {
1465                 pcl818_ai_cancel(dev, devpriv->sub_ai);
1466                 pcl818_reset(dev);
1467                 if (devpriv->dma)
1468                         free_dma(devpriv->dma);
1469                 if (devpriv->dmabuf[0])
1470                         free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1471                 if (devpriv->dmabuf[1])
1472                         free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1473         }
1474         comedi_legacy_detach(dev);
1475 }
1476
1477 static const struct pcl818_board boardtypes[] = {
1478         {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
1479          &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1480          0x0a, 0xfff, 0xfff, 0, 1},
1481         {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
1482          &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1483          0x0a, 0xfff, 0xfff, 0, 1},
1484         {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
1485          &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1486          0x0a, 0xfff, 0xfff, 1, 1},
1487         {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
1488          &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1489          0x0a, 0xfff, 0xfff, 1, 1},
1490         {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
1491          &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1492          0x0a, 0xfff, 0xfff, 0, 1},
1493         {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
1494          &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1495          0x0a, 0xfff, 0xfff, 0, 0},
1496         /* pcm3718 */
1497         {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
1498          &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1499          0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
1500 };
1501
1502 static struct comedi_driver pcl818_driver = {
1503         .driver_name    = "pcl818",
1504         .module         = THIS_MODULE,
1505         .attach         = pcl818_attach,
1506         .detach         = pcl818_detach,
1507         .board_name     = &boardtypes[0].name,
1508         .num_names      = ARRAY_SIZE(boardtypes),
1509         .offset         = sizeof(struct pcl818_board),
1510 };
1511 module_comedi_driver(pcl818_driver);
1512
1513 MODULE_AUTHOR("Comedi http://www.comedi.org");
1514 MODULE_DESCRIPTION("Comedi low-level driver");
1515 MODULE_LICENSE("GPL");