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