c7f6130ff6a11d95b2f5ed7c47a3f4a0aee97408
[cascardo/linux.git] / drivers / staging / comedi / drivers / addi-data / hwdrv_apci3120.c
1 /**
2 @verbatim
3
4 Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
5
6         ADDI-DATA GmbH
7         Dieselstrasse 3
8         D-77833 Ottersweier
9         Tel: +19(0)7223/9493-0
10         Fax: +49(0)7223/9493-92
11         http://www.addi-data.com
12         info@addi-data.com
13
14 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17
18 @endverbatim
19 */
20 /*
21   +-----------------------------------------------------------------------+
22   | (C) ADDI-DATA GmbH          Dieselstrasse 3      D-77833 Ottersweier  |
23   +-----------------------------------------------------------------------+
24   | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
25   | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
26   +-----------------------------------------------------------------------+
27   | Project     : APCI-3120       | Compiler   : GCC                      |
28   | Module name : hwdrv_apci3120.c| Version    : 2.96                     |
29   +-------------------------------+---------------------------------------+
30   | Project manager: Eric Stolz   | Date       :  02/12/2002              |
31   +-----------------------------------------------------------------------+
32   | Description :APCI3120 Module.  Hardware abstraction Layer for APCI3120|
33   +-----------------------------------------------------------------------+
34   |                             UPDATE'S                                  |
35   +-----------------------------------------------------------------------+
36   |   Date   |   Author  |          Description of updates                |
37   +----------+-----------+------------------------------------------------+
38   |          |           |                                                |
39   |          |           |                                                |
40   +----------+-----------+------------------------------------------------+
41 */
42
43 /*
44  * ADDON RELATED ADDITIONS
45  */
46 /* Constant */
47 #define APCI3120_ENABLE_TRANSFER_ADD_ON_LOW             0x00
48 #define APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH            0x1200
49 #define APCI3120_A2P_FIFO_MANAGEMENT                    0x04000400L
50 #define APCI3120_AMWEN_ENABLE                           0x02
51 #define APCI3120_A2P_FIFO_WRITE_ENABLE                  0x01
52 #define APCI3120_FIFO_ADVANCE_ON_BYTE_2                 0x20000000L
53 #define APCI3120_ENABLE_WRITE_TC_INT                    0x00004000L
54 #define APCI3120_CLEAR_WRITE_TC_INT                     0x00040000L
55 #define APCI3120_DISABLE_AMWEN_AND_A2P_FIFO_WRITE       0x0
56 #define APCI3120_DISABLE_BUS_MASTER_ADD_ON              0x0
57 #define APCI3120_DISABLE_BUS_MASTER_PCI                 0x0
58
59 /* ADD_ON ::: this needed since apci supports 16 bit interface to add on */
60 #define APCI3120_ADD_ON_AGCSTS_LOW      0x3C
61 #define APCI3120_ADD_ON_AGCSTS_HIGH     (APCI3120_ADD_ON_AGCSTS_LOW + 2)
62 #define APCI3120_ADD_ON_MWAR_LOW        0x24
63 #define APCI3120_ADD_ON_MWAR_HIGH       (APCI3120_ADD_ON_MWAR_LOW + 2)
64 #define APCI3120_ADD_ON_MWTC_LOW        0x058
65 #define APCI3120_ADD_ON_MWTC_HIGH       (APCI3120_ADD_ON_MWTC_LOW + 2)
66
67 /* AMCC */
68 #define APCI3120_AMCC_OP_MCSR           0x3C
69 #define APCI3120_AMCC_OP_REG_INTCSR     0x38
70
71 /* for transfer count enable bit */
72 #define AGCSTS_TC_ENABLE        0x10000000
73
74 #define APCI3120_START                  1
75 #define APCI3120_STOP                   0
76
77 #define APCI3120_EOC_MODE               1
78 #define APCI3120_EOS_MODE               2
79 #define APCI3120_DMA_MODE               3
80
81 #define APCI3120_RD_FIFO                0x00
82
83 /* software trigger dummy register */
84 #define APCI3120_START_CONVERSION       0x02
85
86 /* TIMER DEFINE */
87 #define APCI3120_QUARTZ_A               70
88 #define APCI3120_QUARTZ_B               50
89 #define APCI3120_TIMER                  1
90 #define APCI3120_WATCHDOG               2
91 #define APCI3120_TIMER_DISABLE          0
92 #define APCI3120_TIMER_ENABLE           1
93
94 #define APCI3120_COUNTER                3
95
96 static int apci3120_reset(struct comedi_device *dev)
97 {
98         struct apci3120_private *devpriv = dev->private;
99
100         devpriv->b_InterruptMode = APCI3120_EOC_MODE;
101
102         /*  variables used in timer subdevice */
103         devpriv->b_Timer2Mode = 0;
104         devpriv->b_Timer2Interrupt = 0;
105         devpriv->b_ExttrigEnable = 0;   /*  Disable ext trigger */
106
107         /* Disable all interrupts, watchdog for the anolog output */
108         devpriv->mode = 0;
109         outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
110
111         /* disable all counters, ext trigger, and reset scan */
112         devpriv->ctrl = 0;
113         outw(devpriv->ctrl, dev->iobase + APCI3120_CTRL_REG);
114
115         inw(dev->iobase + APCI3120_STATUS_REG);
116
117         return 0;
118 }
119
120 static int apci3120_cancel(struct comedi_device *dev,
121                            struct comedi_subdevice *s)
122 {
123         struct apci3120_private *devpriv = dev->private;
124
125         /*  Disable A2P Fifo write and AMWEN signal */
126         outw(0, devpriv->addon + 4);
127
128         /* Disable Bus Master ADD ON */
129         outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->addon + 0);
130         outw(0, devpriv->addon + 2);
131         outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->addon + 0);
132         outw(0, devpriv->addon + 2);
133
134         /* Disable BUS Master PCI */
135         outl(0, devpriv->amcc + AMCC_OP_REG_MCSR);
136
137         /* disable all counters, ext trigger, and reset scan */
138         devpriv->ctrl = 0;
139         outw(devpriv->ctrl, dev->iobase + APCI3120_CTRL_REG);
140
141         /* DISABLE_ALL_INTERRUPT */
142         devpriv->mode = 0;
143         outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
144
145         inw(dev->iobase + APCI3120_STATUS_REG);
146         devpriv->ui_DmaActualBuffer = 0;
147
148         devpriv->b_InterruptMode = APCI3120_EOC_MODE;
149
150         return 0;
151 }
152
153 static int apci3120_ai_cmdtest(struct comedi_device *dev,
154                                struct comedi_subdevice *s,
155                                struct comedi_cmd *cmd)
156 {
157         int err = 0;
158
159         /* Step 1 : check if triggers are trivially valid */
160
161         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
162         err |= cfc_check_trigger_src(&cmd->scan_begin_src,
163                                         TRIG_TIMER | TRIG_FOLLOW);
164         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
165         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
166         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
167
168         if (err)
169                 return 1;
170
171         /* Step 2a : make sure trigger sources are unique */
172
173         err |= cfc_check_trigger_is_unique(cmd->start_src);
174         err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
175         err |= cfc_check_trigger_is_unique(cmd->stop_src);
176
177         /* Step 2b : and mutually compatible */
178
179         if (err)
180                 return 2;
181
182         /* Step 3: check if arguments are trivially valid */
183
184         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
185
186         if (cmd->scan_begin_src == TRIG_TIMER)  /* Test Delay timing */
187                 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 100000);
188
189         if (cmd->scan_begin_src == TRIG_TIMER) {
190                 if (cmd->convert_arg)
191                         err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
192                                                          10000);
193         } else {
194                 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
195         }
196
197         err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
198         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
199
200         if (cmd->stop_src == TRIG_COUNT)
201                 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
202         else    /*  TRIG_NONE */
203                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
204
205         if (err)
206                 return 3;
207
208         /*  step 4: fix up any arguments */
209
210         if (cmd->scan_begin_src == TRIG_TIMER &&
211             cmd->scan_begin_arg < cmd->convert_arg * cmd->scan_end_arg) {
212                 cmd->scan_begin_arg = cmd->convert_arg * cmd->scan_end_arg;
213                 err |= -EINVAL;
214         }
215
216         if (err)
217                 return 4;
218
219         return 0;
220 }
221
222 static void apci3120_setup_dma(struct comedi_device *dev,
223                                struct comedi_subdevice *s)
224 {
225         struct apci3120_private *devpriv = dev->private;
226         struct comedi_cmd *cmd = &s->async->cmd;
227         struct apci3120_dmabuf *dmabuf0 = &devpriv->dmabuf[0];
228         struct apci3120_dmabuf *dmabuf1 = &devpriv->dmabuf[1];
229         unsigned int dmalen0 = dmabuf0->size;
230         unsigned int dmalen1 = dmabuf1->size;
231         unsigned int scan_bytes;
232
233         scan_bytes = comedi_samples_to_bytes(s, cmd->scan_end_arg);
234
235         if (cmd->stop_src == TRIG_COUNT) {
236                 /*
237                  * Must we fill full first buffer? And must we fill
238                  * full second buffer when first is once filled?
239                  */
240                 if (dmalen0 > (cmd->stop_arg * scan_bytes))
241                         dmalen0 = cmd->stop_arg * scan_bytes;
242                 else if (dmalen1 > (cmd->stop_arg * scan_bytes - dmalen0))
243                         dmalen1 = cmd->stop_arg * scan_bytes - dmalen0;
244         }
245
246         if (cmd->flags & CMDF_WAKE_EOS) {
247                 /* don't we want wake up every scan? */
248                 if (dmalen0 > scan_bytes) {
249                         dmalen0 = scan_bytes;
250                         if (cmd->scan_end_arg & 1)
251                                 dmalen0 += 2;
252                 }
253                 if (dmalen1 > scan_bytes) {
254                         dmalen1 = scan_bytes;
255                         if (cmd->scan_end_arg & 1)
256                                 dmalen1 -= 2;
257                         if (dmalen1 < 4)
258                                 dmalen1 = 4;
259                 }
260         } else {
261                 /* isn't output buff smaller that our DMA buff? */
262                 if (dmalen0 > s->async->prealloc_bufsz)
263                         dmalen0 = s->async->prealloc_bufsz;
264                 if (dmalen1 > s->async->prealloc_bufsz)
265                         dmalen1 = s->async->prealloc_bufsz;
266         }
267         dmabuf0->use_size = dmalen0;
268         dmabuf1->use_size = dmalen1;
269
270         /* Initialize DMA */
271
272         /*
273          * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS
274          * register 1
275          */
276         outl(AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO,
277              devpriv->amcc + AMCC_OP_REG_AGCSTS);
278
279         /* changed  since 16 bit interface for add on */
280         /* ENABLE BUS MASTER */
281         outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->addon + 0);
282         outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, devpriv->addon + 2);
283
284         outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->addon + 0);
285         outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->addon + 2);
286
287         /*
288          * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux
289          * driver
290          */
291         outw(0x1000, devpriv->addon + 2);
292         /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
293
294         /* 2 No change */
295         /* A2P FIFO MANAGEMENT */
296         /* A2P fifo reset & transfer control enable */
297         outl(APCI3120_A2P_FIFO_MANAGEMENT,
298              devpriv->amcc + APCI3120_AMCC_OP_MCSR);
299
300         /*
301          * 3
302          * beginning address of dma buf The 32 bit address of dma buffer
303          * is converted into two 16 bit addresses Can done by using _attach
304          * and put into into an array array used may be for differnet pages
305          */
306
307         /* DMA Start Address Low */
308         outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->addon + 0);
309         outw(dmabuf0->hw & 0xffff, devpriv->addon + 2);
310
311         /* DMA Start Address High */
312         outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->addon + 0);
313         outw((dmabuf0->hw >> 16) & 0xffff, devpriv->addon + 2);
314
315         /*
316          * 4
317          * amount of bytes to be transferred set transfer count used ADDON
318          * MWTC register commented testing
319          */
320
321         /* Nbr of acquisition LOW */
322         outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->addon + 0);
323         outw(dmabuf0->use_size & 0xffff, devpriv->addon + 2);
324
325         /* Nbr of acquisition HIGH */
326         outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->addon + 0);
327         outw((dmabuf0->use_size >> 16) & 0xffff, devpriv->addon + 2);
328
329         /*
330          * 5
331          * To configure A2P FIFO testing outl(
332          * FIFO_ADVANCE_ON_BYTE_2, devpriv->amcc + AMCC_OP_REG_INTCSR);
333          */
334
335         /* A2P FIFO RESET */
336         /*
337          * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux
338          * driver
339          */
340         outl(0x04000000UL, devpriv->amcc + AMCC_OP_REG_MCSR);
341         /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
342
343         /*
344          * 6
345          * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE |
346          * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
347          */
348
349         /*
350          * 7
351          * initialise end of dma interrupt AINT_WRITE_COMPL =
352          * ENABLE_WRITE_TC_INT(ADDI)
353          */
354         /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */
355         outl(APCI3120_FIFO_ADVANCE_ON_BYTE_2 | APCI3120_ENABLE_WRITE_TC_INT,
356              devpriv->amcc + AMCC_OP_REG_INTCSR);
357
358         /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
359         /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
360         outw(3, devpriv->addon + 4);
361         /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
362
363         /* A2P FIFO RESET */
364         /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
365         outl(0x04000000UL, devpriv->amcc + APCI3120_AMCC_OP_MCSR);
366         /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
367 }
368
369 static int apci3120_ai_cmd(struct comedi_device *dev,
370                            struct comedi_subdevice *s)
371 {
372         struct apci3120_private *devpriv = dev->private;
373         struct comedi_cmd *cmd = &s->async->cmd;
374         unsigned int divisor;
375
376         /* set default mode bits */
377         devpriv->mode = APCI3120_MODE_TIMER2_CLK_OSC |
378                         APCI3120_MODE_TIMER2_AS_TIMER;
379
380         /* Clear Timer Write TC int */
381         outl(APCI3120_CLEAR_WRITE_TC_INT,
382              devpriv->amcc + APCI3120_AMCC_OP_REG_INTCSR);
383
384         devpriv->ui_DmaActualBuffer = 0;
385
386         /* load chanlist for command scan */
387         apci3120_set_chanlist(dev, s, cmd->chanlist_len, cmd->chanlist);
388
389         if (cmd->start_src == TRIG_EXT) {
390                 devpriv->b_ExttrigEnable = 1;
391                 apci3120_exttrig_enable(dev, true);
392         } else {
393                 devpriv->b_ExttrigEnable = 0;
394         }
395
396         if (cmd->scan_begin_src == TRIG_TIMER) {
397                 /*
398                  * Timer 1 is used in MODE2 (rate generator) to set the
399                  * start time for each scan.
400                  */
401                 divisor = apci3120_ns_to_timer(dev, 1, cmd->scan_begin_arg,
402                                                cmd->flags);
403                 apci3120_timer_set_mode(dev, 1, APCI3120_TIMER_MODE2);
404                 apci3120_timer_write(dev, 1, divisor);
405         }
406
407         /*
408          * Timer 0 is used in MODE2 (rate generator) to set the conversion
409          * time for each acquisition.
410          */
411         divisor = apci3120_ns_to_timer(dev, 0, cmd->convert_arg, cmd->flags);
412         apci3120_timer_set_mode(dev, 0, APCI3120_TIMER_MODE2);
413         apci3120_timer_write(dev, 0, divisor);
414
415         if (devpriv->us_UseDma) {
416                 devpriv->b_InterruptMode = APCI3120_DMA_MODE;
417                 apci3120_setup_dma(dev, s);
418         } else {
419                 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
420
421                 devpriv->mode |= APCI3120_MODE_EOS_IRQ_ENA;
422
423                 if (cmd->stop_src == TRIG_COUNT) {
424                         /*
425                          * Timer 2 is used in MODE0 (hardware retriggerable
426                          * one-shot) to count the number of scans.
427                          *
428                          * NOTE: not sure about the -2 value
429                          */
430                         apci3120_timer_set_mode(dev, 2, APCI3120_TIMER_MODE0);
431                         apci3120_timer_write(dev, 2, cmd->stop_arg - 2);
432
433                         apci3120_clr_timer2_interrupt(dev);
434
435                         apci3120_timer_enable(dev, 2, true);
436
437                         /* configure Timer 2 For counting EOS */
438                         devpriv->mode |= APCI3120_MODE_TIMER2_AS_COUNTER |
439                                          APCI3120_MODE_TIMER2_CLK_EOS |
440                                          APCI3120_MODE_TIMER2_IRQ_ENA;
441
442                         devpriv->b_Timer2Mode = APCI3120_COUNTER;
443                         devpriv->b_Timer2Interrupt = 1;
444                 }
445         }
446
447         /* set mode to enable acquisition */
448         outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
449
450         if (cmd->scan_begin_src == TRIG_TIMER)
451                 apci3120_timer_enable(dev, 1, true);
452         apci3120_timer_enable(dev, 0, true);
453
454         return 0;
455 }
456
457 /*
458  * This is a handler for the DMA interrupt.
459  * This function copies the data to Comedi Buffer.
460  * For continuous DMA it reinitializes the DMA operation.
461  * For single mode DMA it stop the acquisition.
462  */
463 static void apci3120_interrupt_dma(int irq, void *d)
464 {
465         struct comedi_device *dev = d;
466         struct apci3120_private *devpriv = dev->private;
467         struct comedi_subdevice *s = dev->read_subdev;
468         struct comedi_cmd *cmd = &s->async->cmd;
469         struct apci3120_dmabuf *dmabuf;
470         unsigned int samplesinbuf;
471         unsigned int ui_Tmp;
472
473         dmabuf = &devpriv->dmabuf[devpriv->ui_DmaActualBuffer];
474
475         samplesinbuf = dmabuf->use_size - inl(devpriv->amcc + AMCC_OP_REG_MWTC);
476
477         if (samplesinbuf < dmabuf->use_size)
478                 dev_err(dev->class_dev, "Interrupted DMA transfer!\n");
479         if (samplesinbuf & 1) {
480                 dev_err(dev->class_dev, "Odd count of bytes in DMA ring!\n");
481                 apci3120_cancel(dev, s);
482                 return;
483         }
484         samplesinbuf = samplesinbuf >> 1;       /*  number of received samples */
485         if (devpriv->b_DmaDoubleBuffer) {
486                 /*  switch DMA buffers if is used double buffering */
487                 struct apci3120_dmabuf *next_dmabuf;
488
489                 next_dmabuf = &devpriv->dmabuf[1 - devpriv->ui_DmaActualBuffer];
490
491                 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
492                 outl(ui_Tmp, devpriv->amcc + AMCC_OP_REG_AGCSTS);
493
494                 /*  changed  since 16 bit interface for add on */
495                 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->addon + 0);
496                 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, devpriv->addon + 2);
497                 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->addon + 0);
498                 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->addon + 2); /*  0x1000 is out putted in windows driver */
499
500                 /* DMA Start Address Low */
501                 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->addon + 0);
502                 outw(next_dmabuf->hw & 0xffff, devpriv->addon + 2);
503
504                 /* DMA Start Address High */
505                 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->addon + 0);
506                 outw((next_dmabuf->hw >> 16) & 0xffff, devpriv->addon + 2);
507
508                 /* Nbr of acquisition LOW */
509                 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->addon + 0);
510                 outw(next_dmabuf->use_size & 0xffff, devpriv->addon + 2);
511
512                 /* Nbr of acquisition HIGH */
513                 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->addon + 0);
514                 outw((next_dmabuf->use_size > 16) & 0xffff, devpriv->addon + 2);
515
516                 /*
517                  * To configure A2P FIFO
518                  * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
519                  * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
520                  */
521                 outw(3, devpriv->addon + 4);
522                 /* initialise end of dma interrupt  AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
523                 outl(APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
524                      APCI3120_ENABLE_WRITE_TC_INT,
525                      devpriv->amcc + AMCC_OP_REG_INTCSR);
526
527         }
528         if (samplesinbuf) {
529                 comedi_buf_write_samples(s, dmabuf->virt, samplesinbuf);
530
531                 if (!(cmd->flags & CMDF_WAKE_EOS))
532                         s->async->events |= COMEDI_CB_EOS;
533         }
534         if (cmd->stop_src == TRIG_COUNT &&
535             s->async->scans_done >= cmd->stop_arg) {
536                 s->async->events |= COMEDI_CB_EOA;
537                 return;
538         }
539
540         if (devpriv->b_DmaDoubleBuffer) {       /*  switch dma buffers */
541                 devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
542         } else {
543                 /*
544                  * restart DMA if is not used double buffering
545                  * ADDED REINITIALISE THE DMA
546                  */
547                 outl(AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO,
548                      devpriv->amcc + AMCC_OP_REG_AGCSTS);
549
550                 /*  changed  since 16 bit interface for add on */
551                 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->addon + 0);
552                 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, devpriv->addon + 2);
553                 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->addon + 0);
554                 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->addon + 2);
555                 /*
556                  * A2P FIFO MANAGEMENT
557                  * A2P fifo reset & transfer control enable
558                  */
559                 outl(APCI3120_A2P_FIFO_MANAGEMENT,
560                      devpriv->amcc + AMCC_OP_REG_MCSR);
561
562                 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->addon + 0);
563                 outw(dmabuf->hw & 0xffff, devpriv->addon + 2);
564                 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->addon + 0);
565                 outw((dmabuf->hw >> 16) & 0xffff, devpriv->addon + 2);
566
567                 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->addon + 0);
568                 outw(dmabuf->use_size & 0xffff, devpriv->addon + 2);
569                 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->addon + 0);
570                 outw((dmabuf->use_size >> 16) & 0xffff, devpriv->addon + 2);
571
572                 /*
573                  * To configure A2P FIFO
574                  * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
575                  * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
576                  */
577                 outw(3, devpriv->addon + 4);
578                 /* initialise end of dma interrupt  AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
579                 outl(APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
580                      APCI3120_ENABLE_WRITE_TC_INT,
581                      devpriv->amcc + AMCC_OP_REG_INTCSR);
582         }
583 }
584
585 static irqreturn_t apci3120_interrupt(int irq, void *d)
586 {
587         struct comedi_device *dev = d;
588         struct apci3120_private *devpriv = dev->private;
589         struct comedi_subdevice *s = dev->read_subdev;
590         struct comedi_cmd *cmd = &s->async->cmd;
591         unsigned int status;
592         unsigned int int_amcc;
593
594         status = inw(dev->iobase + APCI3120_STATUS_REG);
595         int_amcc = inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
596
597         if (!(status & APCI3120_STATUS_INT_MASK) &&
598             !(int_amcc & ANY_S593X_INT)) {
599                 dev_err(dev->class_dev, "IRQ from unknown source\n");
600                 return IRQ_NONE;
601         }
602
603         outl(int_amcc | 0x00ff0000, devpriv->amcc + AMCC_OP_REG_INTCSR);
604
605         if (devpriv->b_ExttrigEnable) {
606                 apci3120_exttrig_enable(dev, false);
607                 devpriv->b_ExttrigEnable = 0;
608         }
609
610         apci3120_clr_timer2_interrupt(dev);
611
612         if (int_amcc & MASTER_ABORT_INT)
613                 dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n");
614         if (int_amcc & TARGET_ABORT_INT)
615                 dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n");
616
617         if ((status & APCI3120_STATUS_EOC_INT) == 0 &&
618             devpriv->b_InterruptMode == APCI3120_EOC_MODE) {
619                 /* nothing to do... EOC mode is not currently used */
620         }
621
622         if ((status & APCI3120_STATUS_EOS_INT) &&
623             devpriv->b_InterruptMode == APCI3120_EOS_MODE) {
624                 unsigned short val;
625                 int i;
626
627                 for (i = 0; i < cmd->chanlist_len; i++) {
628                         val = inw(dev->iobase + 0);
629                         comedi_buf_write_samples(s, &val, 1);
630                 }
631
632                 devpriv->mode |= APCI3120_MODE_EOS_IRQ_ENA;
633                 outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
634         }
635
636         if (status & APCI3120_STATUS_TIMER2_INT) {
637                 switch (devpriv->b_Timer2Mode) {
638                 case APCI3120_COUNTER:
639                         devpriv->mode &= ~APCI3120_MODE_EOS_IRQ_ENA;
640                         outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
641
642                         s->async->events |= COMEDI_CB_EOA;
643                         break;
644
645                 case APCI3120_TIMER:
646
647                         /* Send a signal to from kernel to user space */
648                         send_sig(SIGIO, devpriv->tsk_Current, 0);
649                         break;
650
651                 case APCI3120_WATCHDOG:
652
653                         /* Send a signal to from kernel to user space */
654                         send_sig(SIGIO, devpriv->tsk_Current, 0);
655                         break;
656
657                 default:
658                         /*  disable Timer Interrupt */
659                         devpriv->mode &= ~APCI3120_MODE_TIMER2_IRQ_ENA;
660                         outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
661                 }
662
663                 apci3120_clr_timer2_interrupt(dev);
664         }
665
666         if ((status & APCI3120_STATUS_AMCC_INT) &&
667             devpriv->b_InterruptMode == APCI3120_DMA_MODE) {
668                 /* Clear Timer Write TC int */
669                 outl(APCI3120_CLEAR_WRITE_TC_INT,
670                         devpriv->amcc + APCI3120_AMCC_OP_REG_INTCSR);
671
672                 apci3120_clr_timer2_interrupt(dev);
673
674                 /* do some data transfer */
675                 apci3120_interrupt_dma(irq, d);
676         }
677         comedi_handle_events(dev, s);
678
679         return IRQ_HANDLED;
680 }
681
682 /*
683  * Configure Timer 2
684  *
685  * data[0] = TIMER configure as timer
686  *         = WATCHDOG configure as watchdog
687  * data[1] = Timer constant
688  * data[2] = Timer2 interrupt (1)enable or(0) disable
689  */
690 static int apci3120_config_insn_timer(struct comedi_device *dev,
691                                       struct comedi_subdevice *s,
692                                       struct comedi_insn *insn,
693                                       unsigned int *data)
694 {
695         struct apci3120_private *devpriv = dev->private;
696         unsigned int divisor;
697
698         if (!data[1])
699                 dev_err(dev->class_dev, "No timer constant!\n");
700
701         devpriv->b_Timer2Interrupt = (unsigned char) data[2];   /*  save info whether to enable or disable interrupt */
702
703         divisor = apci3120_ns_to_timer(dev, 2, data[1], CMDF_ROUND_DOWN);
704
705         apci3120_timer_enable(dev, 2, false);
706
707         /* disable timer 2 interrupt and reset operation mode (timer) */
708         devpriv->mode &= ~APCI3120_MODE_TIMER2_IRQ_ENA &
709                          ~APCI3120_MODE_TIMER2_AS_MASK;
710
711         /*  Disable Eoc and Eos Interrupts */
712         devpriv->mode &= ~APCI3120_MODE_EOC_IRQ_ENA &
713                          ~APCI3120_MODE_EOS_IRQ_ENA;
714         outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
715
716         if (data[0] == APCI3120_TIMER) {        /* initialize timer */
717                 /* Set the Timer 2 in mode 2(Timer) */
718                 apci3120_timer_set_mode(dev, 2, APCI3120_TIMER_MODE2);
719
720                 /* Set timer 2 delay */
721                 apci3120_timer_write(dev, 2, divisor);
722
723                 /*  timer2 in Timer mode enabled */
724                 devpriv->b_Timer2Mode = APCI3120_TIMER;
725         } else {                        /*  Initialize Watch dog */
726                 /* Set the Timer 2 in mode 5(Watchdog) */
727                 apci3120_timer_set_mode(dev, 2, APCI3120_TIMER_MODE5);
728
729                 /* Set timer 2 delay */
730                 apci3120_timer_write(dev, 2, divisor);
731
732                 /* watchdog enabled */
733                 devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
734
735         }
736
737         return insn->n;
738
739 }
740
741 /*
742  * To start and stop the timer
743  *
744  * data[0] = 1 (start)
745  *         = 0 (stop)
746  *         = 2 (write new value)
747  * data[1] = new value
748  *
749  * devpriv->b_Timer2Mode = 0 DISABLE
750  *                       = 1 Timer
751  *                       = 2 Watch dog
752  */
753 static int apci3120_write_insn_timer(struct comedi_device *dev,
754                                      struct comedi_subdevice *s,
755                                      struct comedi_insn *insn,
756                                      unsigned int *data)
757 {
758         struct apci3120_private *devpriv = dev->private;
759         unsigned int divisor;
760
761         if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
762                 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
763                 dev_err(dev->class_dev, "timer2 not configured\n");
764                 return -EINVAL;
765         }
766
767         if (data[0] == 2) {     /*  write new value */
768                 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
769                         dev_err(dev->class_dev,
770                                 "timer2 not configured in TIMER MODE\n");
771                         return -EINVAL;
772                 }
773         }
774
775         switch (data[0]) {
776         case APCI3120_START:
777                 apci3120_clr_timer2_interrupt(dev);
778
779                 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {  /* start timer */
780                         /* Enable Timer */
781                         devpriv->mode &= 0x0b;
782                         devpriv->mode |= APCI3120_MODE_TIMER2_AS_TIMER;
783                 } else {                /* start watch dog */
784                         /* Enable WatchDog */
785                         devpriv->mode &= 0x0b;
786                         devpriv->mode |= APCI3120_MODE_TIMER2_AS_WDOG;
787                 }
788
789                 /* enable disable interrupt */
790                 if (devpriv->b_Timer2Interrupt) {
791                         devpriv->mode |= APCI3120_MODE_TIMER2_IRQ_ENA;
792
793                         /*  save the task structure to pass info to user */
794                         devpriv->tsk_Current = current;
795                 } else {
796                         devpriv->mode &= ~APCI3120_MODE_TIMER2_IRQ_ENA;
797                 }
798                 outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
799
800                 /* start timer */
801                 if (devpriv->b_Timer2Mode == APCI3120_TIMER)
802                         apci3120_timer_enable(dev, 2, true);
803                 break;
804
805         case APCI3120_STOP:
806                 /* disable timer 2 interrupt and reset operation mode (timer) */
807                 devpriv->mode &= ~APCI3120_MODE_TIMER2_IRQ_ENA &
808                                  ~APCI3120_MODE_TIMER2_AS_MASK;
809                 outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
810
811                 apci3120_timer_enable(dev, 2, false);
812
813                 apci3120_clr_timer2_interrupt(dev);
814                 break;
815
816         case 2:         /* write new value to Timer */
817                 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
818                         dev_err(dev->class_dev,
819                                 "timer2 not configured in TIMER MODE\n");
820                         return -EINVAL;
821                 }
822
823                 divisor = apci3120_ns_to_timer(dev, 2, data[1],
824                                                CMDF_ROUND_DOWN);
825
826                 /* Set timer 2 delay */
827                 apci3120_timer_write(dev, 2, divisor);
828                 break;
829         default:
830                 return -EINVAL; /*  Not a valid input */
831         }
832
833         return insn->n;
834 }
835
836 /*
837  * Read the Timer value
838  *
839  * for Timer: data[0]= Timer constant
840  *
841  * for watchdog: data[0] = 0 (still running)
842  *                       = 1 (run down)
843  */
844 static int apci3120_read_insn_timer(struct comedi_device *dev,
845                                     struct comedi_subdevice *s,
846                                     struct comedi_insn *insn,
847                                     unsigned int *data)
848 {
849         struct apci3120_private *devpriv = dev->private;
850         unsigned int status;
851
852         if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
853                 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
854                 dev_err(dev->class_dev, "timer2 not configured\n");
855         }
856         if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
857                 data[0] = apci3120_timer_read(dev, 2);
858         } else {
859                 /* Read watch dog status */
860                 status = inw(dev->iobase + APCI3120_STATUS_REG);
861                 if (status & APCI3120_STATUS_TIMER2_INT) {
862                         apci3120_clr_timer2_interrupt(dev);
863                         data[0] = 1;
864                 } else {
865                         data[0] = 0;
866                 }
867         }
868         return insn->n;
869 }