]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
Merge branch 'omap-pool'
[linux-2.6-omap-h63xx.git] / drivers / staging / comedi / drivers / addi-data / hwdrv_apci3120.c
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
new file mode 100644 (file)
index 0000000..68eb8df
--- /dev/null
@@ -0,0 +1,2697 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstrasse 3      D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-----------------------------------------------------------------------+
+  | Project     : APCI-3120       | Compiler   : GCC                      |
+  | Module name : hwdrv_apci3120.c| Version    : 2.96                     |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date       :  02/12/2002              |
+  +-----------------------------------------------------------------------+
+  | Description :APCI3120 Module.  Hardware abstraction Layer for APCI3120|
+  +-----------------------------------------------------------------------+
+  |                             UPDATE'S                                  |
+  +-----------------------------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |          |                  |                                                |
+  |          |           |                                               |
+  +----------+-----------+------------------------------------------------+
+*/
+
+#include "hwdrv_apci3120.h"
+static UINT ui_Temp = 0;
+
+// FUNCTION DEFINITIONS
+
+/*
++----------------------------------------------------------------------------+
+|                           ANALOG INPUT SUBDEVICE                              |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev,|
+|  struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)                                      |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Task              : Calls card specific function                                          |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev                                                                         |
+|                     struct comedi_subdevice *s                                                                        |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data                                                                |
++----------------------------------------------------------------------------+
+| Return Value      :                                                                           |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnConfigAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s,
+       struct comedi_insn * insn, unsigned int * data)
+{
+       UINT i;
+
+       if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE))
+               return -1;
+
+       // Check for Conversion time to be added ??
+       devpriv->ui_EocEosConversionTime = data[2];
+
+       if (data[0] == APCI3120_EOS_MODE) {
+
+               //Test the number of the channel
+               for (i = 0; i < data[3]; i++) {
+
+                       if (CR_CHAN(data[4 + i]) >= this_board->i_NbrAiChannel) {
+                               printk("bad channel list\n");
+                               return -2;
+                       }
+               }
+
+               devpriv->b_InterruptMode = APCI3120_EOS_MODE;
+
+               if (data[1]) {
+                       devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
+               } else
+                       devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
+               // Copy channel list and Range List to devpriv
+
+               devpriv->ui_AiNbrofChannels = data[3];
+               for (i = 0; i < devpriv->ui_AiNbrofChannels; i++) {
+                       devpriv->ui_AiChannelList[i] = data[4 + i];
+               }
+
+       } else                  // EOC
+       {
+               devpriv->b_InterruptMode = APCI3120_EOC_MODE;
+               if (data[1]) {
+                       devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
+               } else {
+                       devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
+               }
+       }
+
+       return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev,  |
+|                      struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data)         |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Task              :  card specific function                                                           |
+|                              Reads analog input in synchronous mode               |
+|                        EOC and EOS is selected as per configured              |
+|                     if no conversion time is set uses default conversion   |
+|                        time 10 microsec.                                                                      |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev                                                                         |
+|                     struct comedi_subdevice *s                                                                        |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data                                                                        |
++----------------------------------------------------------------------------+
+| Return Value      :                                                                           |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnReadAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s,
+       struct comedi_insn * insn, unsigned int * data)
+{
+       USHORT us_ConvertTiming, us_TmpValue, i;
+       BYTE b_Tmp;
+
+       // fix convertion time to 10 us
+       if (!devpriv->ui_EocEosConversionTime) {
+               printk("No timer0 Value using 10 us\n");
+               us_ConvertTiming = 10;
+       } else
+               us_ConvertTiming = (USHORT) (devpriv->ui_EocEosConversionTime / 1000);  // nano to useconds
+
+       // this_board->i_hwdrv_InsnReadAnalogInput(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]);
+
+       // Clear software registers
+       devpriv->b_TimerSelectMode = 0;
+       devpriv->b_ModeSelectRegister = 0;
+       devpriv->us_OutputRegister = 0;
+//        devpriv->b_DigitalOutputRegister=0;
+
+       if (insn->unused[0] == 222)     // second insn read
+       {
+
+               for (i = 0; i < insn->n; i++) {
+                       data[i] = devpriv->ui_AiReadData[i];
+               }
+
+       } else {
+               devpriv->tsk_Current = current; // Save the current process task structure
+               //Testing if board have the new Quartz and calculate the time value
+               //to set in the timer
+
+               us_TmpValue =
+                       (USHORT) inw(devpriv->iobase + APCI3120_RD_STATUS);
+
+               //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
+               if ((us_TmpValue & 0x00B0) == 0x00B0
+                       || !strcmp(this_board->pc_DriverName, "apci3001")) {
+                       us_ConvertTiming = (us_ConvertTiming * 2) - 2;
+               } else {
+                       us_ConvertTiming =
+                               ((us_ConvertTiming * 12926) / 10000) - 1;
+               }
+
+               us_TmpValue = (USHORT) devpriv->b_InterruptMode;
+
+               switch (us_TmpValue) {
+
+               case APCI3120_EOC_MODE:
+
+                       // Testing the interrupt flag and set the EOC bit
+                       // Clears the FIFO
+                       inw(devpriv->iobase + APCI3120_RESET_FIFO);
+
+                       // Initialize the sequence array
+
+                       //if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0))  return -EINVAL;
+
+                       if (!i_APCI3120_SetupChannelList(dev, s, 1,
+                                       &insn->chanspec, 0))
+                               return -EINVAL;
+
+                       //Initialize Timer 0 mode 4
+                       devpriv->b_TimerSelectMode =
+                               (devpriv->
+                               b_TimerSelectMode & 0xFC) |
+                               APCI3120_TIMER_0_MODE_4;
+                       outb(devpriv->b_TimerSelectMode,
+                               devpriv->iobase + APCI3120_TIMER_CRT1);
+
+                       // Reset the scan bit and Disables the  EOS, DMA, EOC interrupt
+                       devpriv->b_ModeSelectRegister =
+                               devpriv->
+                               b_ModeSelectRegister & APCI3120_DISABLE_SCAN;
+
+                       if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
+
+                               //Disables the EOS,DMA and enables the EOC interrupt
+                               devpriv->b_ModeSelectRegister =
+                                       (devpriv->
+                                       b_ModeSelectRegister &
+                                       APCI3120_DISABLE_EOS_INT) |
+                                       APCI3120_ENABLE_EOC_INT;
+                               inw(devpriv->iobase);
+
+                       } else {
+                               devpriv->b_ModeSelectRegister =
+                                       devpriv->
+                                       b_ModeSelectRegister &
+                                       APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
+                       }
+
+                       outb(devpriv->b_ModeSelectRegister,
+                               devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
+
+                       // Sets gate 0
+                       devpriv->us_OutputRegister =
+                               (devpriv->
+                               us_OutputRegister & APCI3120_CLEAR_PA_PR) |
+                               APCI3120_ENABLE_TIMER0;
+                       outw(devpriv->us_OutputRegister,
+                               devpriv->iobase + APCI3120_WR_ADDRESS);
+
+                       // Select Timer 0
+                       b_Tmp = ((devpriv->
+                                       b_DigitalOutputRegister) & 0xF0) |
+                               APCI3120_SELECT_TIMER_0_WORD;
+                       outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+
+                       //Set the convertion time
+                       outw(us_ConvertTiming,
+                               devpriv->iobase + APCI3120_TIMER_VALUE);
+
+                       us_TmpValue =
+                               (USHORT) inw(dev->iobase + APCI3120_RD_STATUS);
+
+                       if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
+
+                               do {
+                                       // Waiting for the end of conversion
+                                       us_TmpValue =
+                                               inw(devpriv->iobase +
+                                               APCI3120_RD_STATUS);
+                               } while ((us_TmpValue & APCI3120_EOC) ==
+                                       APCI3120_EOC);
+
+                               //Read the result in FIFO  and put it in insn data pointer
+                               us_TmpValue = inw(devpriv->iobase + 0);
+                               *data = us_TmpValue;
+
+                               inw(devpriv->iobase + APCI3120_RESET_FIFO);
+                       }
+
+                       break;
+
+               case APCI3120_EOS_MODE:
+
+                       inw(devpriv->iobase);
+                       // Clears the FIFO
+                       inw(devpriv->iobase + APCI3120_RESET_FIFO);
+                       // clear PA PR  and disable timer 0
+
+                       devpriv->us_OutputRegister =
+                               (devpriv->
+                               us_OutputRegister & APCI3120_CLEAR_PA_PR) |
+                               APCI3120_DISABLE_TIMER0;
+
+                       outw(devpriv->us_OutputRegister,
+                               devpriv->iobase + APCI3120_WR_ADDRESS);
+
+                       if (!i_APCI3120_SetupChannelList(dev, s,
+                                       devpriv->ui_AiNbrofChannels,
+                                       devpriv->ui_AiChannelList, 0))
+                               return -EINVAL;
+
+                       //Initialize Timer 0 mode 2
+                       devpriv->b_TimerSelectMode =
+                               (devpriv->
+                               b_TimerSelectMode & 0xFC) |
+                               APCI3120_TIMER_0_MODE_2;
+                       outb(devpriv->b_TimerSelectMode,
+                               devpriv->iobase + APCI3120_TIMER_CRT1);
+
+                       //Select Timer 0
+                       b_Tmp = ((devpriv->
+                                       b_DigitalOutputRegister) & 0xF0) |
+                               APCI3120_SELECT_TIMER_0_WORD;
+                       outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+
+                       //Set the convertion time
+                       outw(us_ConvertTiming,
+                               devpriv->iobase + APCI3120_TIMER_VALUE);
+
+                       //Set the scan bit
+                       devpriv->b_ModeSelectRegister =
+                               devpriv->
+                               b_ModeSelectRegister | APCI3120_ENABLE_SCAN;
+                       outb(devpriv->b_ModeSelectRegister,
+                               devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
+
+                       //If Interrupt function is loaded
+                       if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
+                               //Disables the EOC,DMA and enables the EOS interrupt
+                               devpriv->b_ModeSelectRegister =
+                                       (devpriv->
+                                       b_ModeSelectRegister &
+                                       APCI3120_DISABLE_EOC_INT) |
+                                       APCI3120_ENABLE_EOS_INT;
+                               inw(devpriv->iobase);
+
+                       } else
+                               devpriv->b_ModeSelectRegister =
+                                       devpriv->
+                                       b_ModeSelectRegister &
+                                       APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
+
+                       outb(devpriv->b_ModeSelectRegister,
+                               devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
+
+                       inw(devpriv->iobase + APCI3120_RD_STATUS);
+
+                       //Sets gate 0
+
+                       devpriv->us_OutputRegister =
+                               devpriv->
+                               us_OutputRegister | APCI3120_ENABLE_TIMER0;
+                       outw(devpriv->us_OutputRegister,
+                               devpriv->iobase + APCI3120_WR_ADDRESS);
+
+                       //Start conversion
+                       outw(0, devpriv->iobase + APCI3120_START_CONVERSION);
+
+                       //Waiting of end of convertion if interrupt is not installed
+                       if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
+                               //Waiting the end of convertion
+                               do {
+                                       us_TmpValue =
+                                               inw(devpriv->iobase +
+                                               APCI3120_RD_STATUS);
+                               }
+                               while ((us_TmpValue & APCI3120_EOS) !=
+                                       APCI3120_EOS);
+
+                               for (i = 0; i < devpriv->ui_AiNbrofChannels;
+                                       i++) {
+                                       //Read the result in FIFO and write them in shared memory
+                                       us_TmpValue = inw(devpriv->iobase);
+                                       data[i] = (UINT) us_TmpValue;
+                               }
+
+                               devpriv->b_InterruptMode = APCI3120_EOC_MODE;   // Restore defaults.
+                       }
+                       break;
+
+               default:
+                       printk("inputs wrong\n");
+
+               }
+               devpriv->ui_EocEosConversionTime = 0;   // re initializing the variable;
+       }
+
+       return insn->n;
+
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,|
+|                                                                                           struct comedi_subdevice *s)|
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Task              : Stops Cyclic acquisition                                                      |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev                                                                         |
+|                     struct comedi_subdevice *s                                                                        |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Return Value      :0                                                                      |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_StopCyclicAcquisition(struct comedi_device * dev, struct comedi_subdevice * s)
+{
+       // Disable A2P Fifo write and AMWEN signal
+       outw(0, devpriv->i_IobaseAddon + 4);
+
+       //Disable Bus Master ADD ON
+       outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
+       outw(0, devpriv->i_IobaseAddon + 2);
+       outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
+       outw(0, devpriv->i_IobaseAddon + 2);
+
+       //Disable BUS Master PCI
+       outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
+
+       //outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL), devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);    // stop amcc irqs
+       //outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS), devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); // stop DMA
+
+       //Disable ext trigger
+       i_APCI3120_ExttrigDisable(dev);
+
+       devpriv->us_OutputRegister = 0;
+       //stop  counters
+       outw(devpriv->
+               us_OutputRegister & APCI3120_DISABLE_TIMER0 &
+               APCI3120_DISABLE_TIMER1, dev->iobase + APCI3120_WR_ADDRESS);
+
+       outw(APCI3120_DISABLE_ALL_TIMER, dev->iobase + APCI3120_WR_ADDRESS);
+
+       //DISABLE_ALL_INTERRUPT
+       outb(APCI3120_DISABLE_ALL_INTERRUPT,
+               dev->iobase + APCI3120_WRITE_MODE_SELECT);
+       //Flush FIFO
+       inb(dev->iobase + APCI3120_RESET_FIFO);
+       inw(dev->iobase + APCI3120_RD_STATUS);
+       devpriv->ui_AiActualScan = 0;
+       devpriv->ui_AiActualScanPosition = 0;
+       s->async->cur_chan = 0;
+       devpriv->ui_AiBufferPtr = 0;
+       devpriv->b_AiContinuous = 0;
+       devpriv->ui_DmaActualBuffer = 0;
+
+       devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
+       devpriv->b_InterruptMode = APCI3120_EOC_MODE;
+       devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
+       i_APCI3120_Reset(dev);
+       return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev|
+|                      ,struct comedi_subdevice *s,struct comedi_cmd *cmd)                                      |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Task              : Test validity for a command for cyclic anlog input     |
+|                       acquisition                                                                     |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev                                                                         |
+|                     struct comedi_subdevice *s                                                                        |
+|                     struct comedi_cmd *cmd                                                            |
++----------------------------------------------------------------------------+
+| Return Value      :0                                                                      |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s,
+       struct comedi_cmd * cmd)
+{
+       int err = 0;
+       int tmp;                // divisor1,divisor2;
+
+       // step 1: make sure trigger sources are trivially valid
+
+       tmp = cmd->start_src;
+       cmd->start_src &= TRIG_NOW | TRIG_EXT;
+       if (!cmd->start_src || tmp != cmd->start_src)
+               err++;
+
+       tmp = cmd->scan_begin_src;
+       cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW;
+       if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
+               err++;
+
+       tmp = cmd->convert_src;
+       cmd->convert_src &= TRIG_TIMER;
+       if (!cmd->convert_src || tmp != cmd->convert_src)
+               err++;
+
+       tmp = cmd->scan_end_src;
+       cmd->scan_end_src &= TRIG_COUNT;
+       if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
+               err++;
+
+       tmp = cmd->stop_src;
+       cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
+       if (!cmd->stop_src || tmp != cmd->stop_src)
+               err++;
+
+       if (err)
+               return 1;
+
+       //step 2: make sure trigger sources are unique and mutually compatible
+
+       if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
+               err++;
+       }
+
+       if (cmd->scan_begin_src != TRIG_TIMER &&
+               cmd->scan_begin_src != TRIG_FOLLOW)
+               err++;
+
+       if (cmd->convert_src != TRIG_TIMER)
+               err++;
+
+       if (cmd->scan_end_src != TRIG_COUNT) {
+               cmd->scan_end_src = TRIG_COUNT;
+               err++;
+       }
+
+       if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
+               err++;
+
+       if (err)
+               return 2;
+
+       // step 3: make sure arguments are trivially compatible
+
+       if (cmd->start_arg != 0) {
+               cmd->start_arg = 0;
+               err++;
+       }
+
+       if (cmd->scan_begin_src == TRIG_TIMER)  // Test Delay timing
+       {
+               if (cmd->scan_begin_arg < this_board->ui_MinDelaytimeNs) {
+                       cmd->scan_begin_arg = this_board->ui_MinDelaytimeNs;
+                       err++;
+               }
+       }
+
+       if (cmd->convert_src == TRIG_TIMER)     // Test Acquisition timing
+       {
+               if (cmd->scan_begin_src == TRIG_TIMER) {
+                       if ((cmd->convert_arg)
+                               && (cmd->convert_arg <
+                                       this_board->ui_MinAcquisitiontimeNs)) {
+                               cmd->convert_arg =
+                                       this_board->ui_MinAcquisitiontimeNs;
+                               err++;
+                       }
+               } else {
+                       if (cmd->convert_arg <
+                               this_board->ui_MinAcquisitiontimeNs) {
+                               cmd->convert_arg =
+                                       this_board->ui_MinAcquisitiontimeNs;
+                               err++;
+
+                       }
+               }
+       }
+
+       if (!cmd->chanlist_len) {
+               cmd->chanlist_len = 1;
+               err++;
+       }
+       if (cmd->chanlist_len > this_board->i_AiChannelList) {
+               cmd->chanlist_len = this_board->i_AiChannelList;
+               err++;
+       }
+       if (cmd->stop_src == TRIG_COUNT) {
+               if (!cmd->stop_arg) {
+                       cmd->stop_arg = 1;
+                       err++;
+               }
+       } else {                // TRIG_NONE
+               if (cmd->stop_arg != 0) {
+                       cmd->stop_arg = 0;
+                       err++;
+               }
+       }
+
+       if (err)
+               return 3;
+
+       // step 4: fix up any arguments
+
+       if (cmd->convert_src == TRIG_TIMER) {
+
+               if (cmd->scan_begin_src == TRIG_TIMER &&
+                       cmd->scan_begin_arg <
+                       cmd->convert_arg * cmd->scan_end_arg) {
+                       cmd->scan_begin_arg =
+                               cmd->convert_arg * cmd->scan_end_arg;
+                       err++;
+               }
+       }
+
+       if (err)
+               return 4;
+
+       return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     : int i_APCI3120_CommandAnalogInput(struct comedi_device *dev,  |
+|                                                                                              struct comedi_subdevice *s) |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Task              : Does asynchronous acquisition                          |
+|                     Determines the mode 1 or 2.                                                   |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev                                                                         |
+|                     struct comedi_subdevice *s                                                                        |
+|                                                                                                                               |
++----------------------------------------------------------------------------+
+| Return Value      :                                                                           |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_CommandAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s)
+{
+       struct comedi_cmd *cmd = &s->async->cmd;
+
+       //loading private structure with cmd structure inputs
+       devpriv->ui_AiFlags = cmd->flags;
+       devpriv->ui_AiNbrofChannels = cmd->chanlist_len;
+       devpriv->ui_AiScanLength = cmd->scan_end_arg;
+       devpriv->pui_AiChannelList = cmd->chanlist;
+
+       //UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data;
+       devpriv->AiData = s->async->prealloc_buf;
+       //UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len;
+       devpriv->ui_AiDataLength = s->async->prealloc_bufsz;
+
+       if (cmd->stop_src == TRIG_COUNT) {
+               devpriv->ui_AiNbrofScans = cmd->stop_arg;
+       } else {
+               devpriv->ui_AiNbrofScans = 0;
+       }
+
+       devpriv->ui_AiTimer0 = 0;       // variables changed to timer0,timer1
+       devpriv->ui_AiTimer1 = 0;
+       if ((devpriv->ui_AiNbrofScans == 0) || (devpriv->ui_AiNbrofScans == -1))
+               devpriv->b_AiContinuous = 1;    // user want neverending analog acquisition
+       // stopped using cancel
+
+       if (cmd->start_src == TRIG_EXT)
+               devpriv->b_ExttrigEnable = APCI3120_ENABLE;
+       else
+               devpriv->b_ExttrigEnable = APCI3120_DISABLE;
+
+       if (cmd->scan_begin_src == TRIG_FOLLOW) {
+               // mode 1 or 3
+               if (cmd->convert_src == TRIG_TIMER) {
+                       // mode 1
+
+                       devpriv->ui_AiTimer0 = cmd->convert_arg;        // timer constant in nano seconds
+                       //return this_board->i_hwdrv_CommandAnalogInput(1,dev,s);
+                       return i_APCI3120_CyclicAnalogInput(1, dev, s);
+               }
+
+       }
+       if ((cmd->scan_begin_src == TRIG_TIMER)
+               && (cmd->convert_src == TRIG_TIMER)) {
+               // mode 2
+               devpriv->ui_AiTimer1 = cmd->scan_begin_arg;
+               devpriv->ui_AiTimer0 = cmd->convert_arg;        // variable changed timer2 to timer0
+               //return this_board->i_hwdrv_CommandAnalogInput(2,dev,s);
+               return i_APCI3120_CyclicAnalogInput(2, dev, s);
+       }
+       return -1;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :  int i_APCI3120_CyclicAnalogInput(int mode,            |
+|                         struct comedi_device * dev,struct comedi_subdevice * s)                       |
++----------------------------------------------------------------------------+
+| Task              : This is used for analog input cyclic acquisition       |
+|                        Performs the command operations.                       |
+|                        If DMA is configured does DMA initialization           |
+|                        otherwise does the acquisition with EOS interrupt.     |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  :                                                                                                           |
+|                                                                                                                               |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Return Value      :                                                                           |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev,
+       struct comedi_subdevice * s)
+{
+       BYTE b_Tmp;
+       UINT ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 =
+               0, dmalen1 = 0, ui_TimerValue2 =
+               0, ui_TimerValue0, ui_ConvertTiming;
+       USHORT us_TmpValue;
+
+       //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+       //devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE;
+       //END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+       /*******************/
+       /* Resets the FIFO */
+       /*******************/
+       inb(dev->iobase + APCI3120_RESET_FIFO);
+
+       //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+       //inw(dev->iobase+APCI3120_RD_STATUS);
+       //END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+       /***************************/
+       /* Acquisition initialized */
+       /***************************/
+       //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+       devpriv->b_AiCyclicAcquisition = APCI3120_ENABLE;
+       //END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+       // clear software  registers
+       devpriv->b_TimerSelectMode = 0;
+       devpriv->us_OutputRegister = 0;
+       devpriv->b_ModeSelectRegister = 0;
+       //devpriv->b_DigitalOutputRegister=0;
+
+       //COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition
+
+   /****************************/
+       /* Clear Timer Write TC INT */
+   /****************************/
+       outl(APCI3120_CLEAR_WRITE_TC_INT,
+               devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR);
+
+   /************************************/
+       /* Clears the timer status register */
+   /************************************/
+       //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+       //inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER);
+       inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
+       //END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+   /**************************/
+       /* Disables All Timer     */
+       /* Sets PR and PA to 0    */
+   /**************************/
+       devpriv->us_OutputRegister = devpriv->us_OutputRegister &
+               APCI3120_DISABLE_TIMER0 &
+               APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR;
+
+       outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
+
+   /*******************/
+       /* Resets the FIFO */
+   /*******************/
+       //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+       inb(devpriv->iobase + APCI3120_RESET_FIFO);
+       //END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+       devpriv->ui_AiActualScan = 0;
+       devpriv->ui_AiActualScanPosition = 0;
+       s->async->cur_chan = 0;
+       devpriv->ui_AiBufferPtr = 0;
+       devpriv->ui_DmaActualBuffer = 0;
+
+       // value for timer2  minus -2 has to be done .....dunno y??
+       ui_TimerValue2 = devpriv->ui_AiNbrofScans - 2;
+       ui_ConvertTiming = devpriv->ui_AiTimer0;
+
+       if (mode == 2)
+               ui_DelayTiming = devpriv->ui_AiTimer1;
+
+   /**********************************/
+       /* Initializes the sequence array */
+   /**********************************/
+       if (!i_APCI3120_SetupChannelList(dev, s, devpriv->ui_AiNbrofChannels,
+                       devpriv->pui_AiChannelList, 0))
+               return -EINVAL;
+
+       us_TmpValue = (USHORT) inw(dev->iobase + APCI3120_RD_STATUS);
+/*** EL241003 : add this section in comment because floats must not be used
+        if((us_TmpValue & 0x00B0)==0x00B0)
+        {
+           f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2);
+               ui_TimerValue0=(UINT)f_ConvertValue;
+               if (mode==2)
+               {
+                       f_DelayValue     = (((float)ui_DelayTiming * 0.00002) - 2);
+                       ui_TimerValue1  =   (UINT) f_DelayValue;
+               }
+        }
+        else
+        {
+               f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1);
+               ui_TimerValue0=(UINT)f_ConvertValue;
+               if (mode == 2)
+               {
+                    f_DelayValue     = (((float)ui_DelayTiming * 0.000012926) - 1);
+                    ui_TimerValue1  =   (UINT) f_DelayValue;
+               }
+       }
+***********************************************************************************************/
+/*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/
+       //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
+       if ((us_TmpValue & 0x00B0) == 0x00B0
+               || !strcmp(this_board->pc_DriverName, "apci3001")) {
+               ui_TimerValue0 = ui_ConvertTiming * 2 - 2000;
+               ui_TimerValue0 = ui_TimerValue0 / 1000;
+
+               if (mode == 2) {
+                       ui_DelayTiming = ui_DelayTiming / 1000;
+                       ui_TimerValue1 = ui_DelayTiming * 2 - 200;
+                       ui_TimerValue1 = ui_TimerValue1 / 100;
+               }
+       } else {
+               ui_ConvertTiming = ui_ConvertTiming / 1000;
+               ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000;
+               ui_TimerValue0 = ui_TimerValue0 / 10000;
+
+               if (mode == 2) {
+                       ui_DelayTiming = ui_DelayTiming / 1000;
+                       ui_TimerValue1 = ui_DelayTiming * 12926 - 1;
+                       ui_TimerValue1 = ui_TimerValue1 / 1000000;
+               }
+       }
+/*** EL241003 End ******************************************************************************/
+
+       if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
+               i_APCI3120_ExttrigEnable(dev);  // activate EXT trigger
+       }
+       switch (mode) {
+       case 1:
+               // init timer0 in mode 2
+               devpriv->b_TimerSelectMode =
+                       (devpriv->
+                       b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
+               outb(devpriv->b_TimerSelectMode,
+                       dev->iobase + APCI3120_TIMER_CRT1);
+
+               //Select Timer 0
+               b_Tmp = ((devpriv->
+                               b_DigitalOutputRegister) & 0xF0) |
+                       APCI3120_SELECT_TIMER_0_WORD;
+               outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
+               //Set the convertion time
+               outw(((USHORT) ui_TimerValue0),
+                       dev->iobase + APCI3120_TIMER_VALUE);
+               break;
+
+       case 2:
+               // init timer1 in mode 2
+               devpriv->b_TimerSelectMode =
+                       (devpriv->
+                       b_TimerSelectMode & 0xF3) | APCI3120_TIMER_1_MODE_2;
+               outb(devpriv->b_TimerSelectMode,
+                       dev->iobase + APCI3120_TIMER_CRT1);
+
+               //Select Timer 1
+               b_Tmp = ((devpriv->
+                               b_DigitalOutputRegister) & 0xF0) |
+                       APCI3120_SELECT_TIMER_1_WORD;
+               outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
+               //Set the convertion time
+               outw(((USHORT) ui_TimerValue1),
+                       dev->iobase + APCI3120_TIMER_VALUE);
+
+               // init timer0 in mode 2
+               devpriv->b_TimerSelectMode =
+                       (devpriv->
+                       b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
+               outb(devpriv->b_TimerSelectMode,
+                       dev->iobase + APCI3120_TIMER_CRT1);
+
+               //Select Timer 0
+               b_Tmp = ((devpriv->
+                               b_DigitalOutputRegister) & 0xF0) |
+                       APCI3120_SELECT_TIMER_0_WORD;
+               outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
+
+               //Set the convertion time
+               outw(((USHORT) ui_TimerValue0),
+                       dev->iobase + APCI3120_TIMER_VALUE);
+               break;
+
+       }
+       //   ##########common for all modes#################
+
+       /***********************/
+       /* Clears the SCAN bit */
+       /***********************/
+       //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+       //devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN;
+       devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
+               APCI3120_DISABLE_SCAN;
+       //END JK 07.05.04: Comparison between WIN32 and Linux driver
+       outb(devpriv->b_ModeSelectRegister,
+               dev->iobase + APCI3120_WRITE_MODE_SELECT);
+
+       // If DMA is disabled
+       if (devpriv->us_UseDma == APCI3120_DISABLE) {
+               // disable EOC and enable EOS
+               devpriv->b_InterruptMode = APCI3120_EOS_MODE;
+               devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
+
+               devpriv->b_ModeSelectRegister =
+                       (devpriv->
+                       b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT) |
+                       APCI3120_ENABLE_EOS_INT;
+               outb(devpriv->b_ModeSelectRegister,
+                       dev->iobase + APCI3120_WRITE_MODE_SELECT);
+
+               if (!devpriv->b_AiContinuous) {
+                       // configure Timer2 For counting  EOS
+                       //Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0)
+                       devpriv->us_OutputRegister =
+                               devpriv->
+                               us_OutputRegister & APCI3120_DISABLE_TIMER2;
+                       outw(devpriv->us_OutputRegister,
+                               dev->iobase + APCI3120_WR_ADDRESS);
+
+                       // DISABLE TIMER INTERRUPT
+                       devpriv->b_ModeSelectRegister =
+                               devpriv->
+                               b_ModeSelectRegister &
+                               APCI3120_DISABLE_TIMER_INT & 0xEF;
+                       outb(devpriv->b_ModeSelectRegister,
+                               dev->iobase + APCI3120_WRITE_MODE_SELECT);
+
+                       //(1) Init timer 2 in mode 0 and write timer value
+                       devpriv->b_TimerSelectMode =
+                               (devpriv->
+                               b_TimerSelectMode & 0x0F) |
+                               APCI3120_TIMER_2_MODE_0;
+                       outb(devpriv->b_TimerSelectMode,
+                               dev->iobase + APCI3120_TIMER_CRT1);
+
+                       //Writing LOW WORD
+                       b_Tmp = ((devpriv->
+                                       b_DigitalOutputRegister) & 0xF0) |
+                               APCI3120_SELECT_TIMER_2_LOW_WORD;
+                       outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
+                       outw(LOWORD(ui_TimerValue2),
+                               dev->iobase + APCI3120_TIMER_VALUE);
+
+                       //Writing HIGH WORD
+                       b_Tmp = ((devpriv->
+                                       b_DigitalOutputRegister) & 0xF0) |
+                               APCI3120_SELECT_TIMER_2_HIGH_WORD;
+                       outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
+                       outw(HIWORD(ui_TimerValue2),
+                               dev->iobase + APCI3120_TIMER_VALUE);
+
+                       //(2) Reset FC_TIMER BIT  Clearing timer status register
+                       inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
+                       // enable timer counter and disable watch dog
+                       devpriv->b_ModeSelectRegister =
+                               (devpriv->
+                               b_ModeSelectRegister |
+                               APCI3120_ENABLE_TIMER_COUNTER) &
+                               APCI3120_DISABLE_WATCHDOG;
+                       // select EOS clock input for timer 2
+                       devpriv->b_ModeSelectRegister =
+                               devpriv->
+                               b_ModeSelectRegister |
+                               APCI3120_TIMER2_SELECT_EOS;
+                       // Enable timer2  interrupt
+                       devpriv->b_ModeSelectRegister =
+                               devpriv->
+                               b_ModeSelectRegister |
+                               APCI3120_ENABLE_TIMER_INT;
+                       outb(devpriv->b_ModeSelectRegister,
+                               dev->iobase + APCI3120_WRITE_MODE_SELECT);
+                       devpriv->b_Timer2Mode = APCI3120_COUNTER;
+                       devpriv->b_Timer2Interrupt = APCI3120_ENABLE;
+               }
+       } else {
+               // If DMA Enabled
+               //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+               //inw(dev->iobase+0);// reset EOC bit
+               //END JK 07.05.04: Comparison between WIN32 and Linux driver
+               devpriv->b_InterruptMode = APCI3120_DMA_MODE;
+
+      /************************************/
+               /* Disables the EOC, EOS interrupt  */
+         /************************************/
+               devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
+                       APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT;
+
+               outb(devpriv->b_ModeSelectRegister,
+                       dev->iobase + APCI3120_WRITE_MODE_SELECT);
+
+               dmalen0 = devpriv->ui_DmaBufferSize[0];
+               dmalen1 = devpriv->ui_DmaBufferSize[1];
+
+               if (!devpriv->b_AiContinuous) {
+
+                       if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) {      // must we fill full first buffer?
+                               dmalen0 =
+                                       devpriv->ui_AiNbrofScans *
+                                       devpriv->ui_AiScanLength * 2;
+                       } else if (dmalen1 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0))       // and must we fill full second buffer when first is once filled?
+                               dmalen1 =
+                                       devpriv->ui_AiNbrofScans *
+                                       devpriv->ui_AiScanLength * 2 - dmalen0;
+               }
+
+               if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) {
+                       // don't we want wake up every scan?
+                       if (dmalen0 > (devpriv->ui_AiScanLength * 2)) {
+                               dmalen0 = devpriv->ui_AiScanLength * 2;
+                               if (devpriv->ui_AiScanLength & 1)
+                                       dmalen0 += 2;
+                       }
+                       if (dmalen1 > (devpriv->ui_AiScanLength * 2)) {
+                               dmalen1 = devpriv->ui_AiScanLength * 2;
+                               if (devpriv->ui_AiScanLength & 1)
+                                       dmalen1 -= 2;
+                               if (dmalen1 < 4)
+                                       dmalen1 = 4;
+                       }
+               } else {        // isn't output buff smaller that our DMA buff?
+                       if (dmalen0 > (devpriv->ui_AiDataLength)) {
+                               dmalen0 = devpriv->ui_AiDataLength;
+                       }
+                       if (dmalen1 > (devpriv->ui_AiDataLength)) {
+                               dmalen1 = devpriv->ui_AiDataLength;
+                       }
+               }
+               devpriv->ui_DmaBufferUsesize[0] = dmalen0;
+               devpriv->ui_DmaBufferUsesize[1] = dmalen1;
+
+               //Initialize DMA
+
+               // Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS register
+               //1
+               ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
+               outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS);
+
+               // changed  since 16 bit interface for add on
+               /*********************/
+               /* ENABLE BUS MASTER */
+               /*********************/
+               outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
+               outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
+                       devpriv->i_IobaseAddon + 2);
+
+               outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
+               outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH,
+                       devpriv->i_IobaseAddon + 2);
+
+               // TO VERIFIED
+               //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+               outw(0x1000, devpriv->i_IobaseAddon + 2);
+               //END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+               //2  No change
+               // A2P FIFO MANAGEMENT
+               // A2P fifo reset  & transfer control enable
+                /***********************/
+               /* A2P FIFO MANAGEMENT */
+                /***********************/
+               outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc +
+                       APCI3120_AMCC_OP_MCSR);
+
+               //3
+               //beginning address of dma buf
+               //The 32 bit address of dma buffer is converted into two 16 bit addresses
+               // Can done by using _attach and put into into an array
+               // array used may be for differnet pages
+
+               // DMA Start Adress Low
+               outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
+               outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF),
+                       devpriv->i_IobaseAddon + 2);
+
+                /*************************/
+               /* DMA Start Adress High */
+                /*************************/
+               outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
+               outw((devpriv->ul_DmaBufferHw[0] / 65536),
+                       devpriv->i_IobaseAddon + 2);
+
+               //4
+               // amount of bytes to be transfered  set transfer count
+               // used ADDON MWTC register
+               //commented testing             outl(devpriv->ui_DmaBufferUsesize[0], devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC);
+
+                /**************************/
+               /* Nbr of acquisition LOW */
+                /**************************/
+               outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
+               outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF),
+                       devpriv->i_IobaseAddon + 2);
+
+                /***************************/
+               /* Nbr of acquisition HIGH */
+                /***************************/
+               outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
+               outw((devpriv->ui_DmaBufferUsesize[0] / 65536),
+                       devpriv->i_IobaseAddon + 2);
+
+               //5
+               // To configure A2P FIFO
+               // testing outl( FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
+
+               /******************/
+               /* A2P FIFO RESET */
+               /******************/
+               // TO VERIFY
+               //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+               outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
+               //END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+               //6
+               //ENABLE A2P FIFO WRITE AND ENABLE AMWEN
+               // AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
+               //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+               //outw(3,devpriv->i_IobaseAddon + 4);
+               //END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+               //7
+               //initialise end of dma interrupt  AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI)
+               /***************************************************/
+               /* A2P FIFO CONFIGURATE, END OF DMA INTERRUPT INIT */
+               /***************************************************/
+               outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
+                               APCI3120_ENABLE_WRITE_TC_INT),
+                       devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
+
+               //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+               /******************************************/
+               /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
+               /******************************************/
+               outw(3, devpriv->i_IobaseAddon + 4);
+               //END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+               /******************/
+               /* A2P FIFO RESET */
+               /******************/
+               //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+               outl(0x04000000UL,
+                       devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR);
+               //END JK 07.05.04: Comparison between WIN32 and Linux driver
+       }
+
+       if ((devpriv->us_UseDma == APCI3120_DISABLE)
+               && !devpriv->b_AiContinuous) {
+               // set gate 2   to start conversion
+               devpriv->us_OutputRegister =
+                       devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2;
+               outw(devpriv->us_OutputRegister,
+                       dev->iobase + APCI3120_WR_ADDRESS);
+       }
+
+       switch (mode) {
+       case 1:
+               // set gate 0   to start conversion
+               devpriv->us_OutputRegister =
+                       devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
+               outw(devpriv->us_OutputRegister,
+                       dev->iobase + APCI3120_WR_ADDRESS);
+               break;
+       case 2:
+               // set  gate 0 and gate 1
+               devpriv->us_OutputRegister =
+                       devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER1;
+               devpriv->us_OutputRegister =
+                       devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
+               outw(devpriv->us_OutputRegister,
+                       dev->iobase + APCI3120_WR_ADDRESS);
+               break;
+
+       }
+
+       return 0;
+
+}
+
+/*
++----------------------------------------------------------------------------+
+|                      INTERNAL FUNCTIONS                                                               |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function name     : int i_APCI3120_Reset(struct comedi_device *dev)               |
+|                                                                                                               |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Task              : Hardware reset function                                                       |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  :  struct comedi_device *dev                                                                        |
+|                                                                                                                               |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Return Value      :                                                                           |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_Reset(struct comedi_device * dev)
+{
+       unsigned int i;
+       unsigned short us_TmpValue;
+
+       devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
+       devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
+       devpriv->b_InterruptMode = APCI3120_EOC_MODE;
+       devpriv->ui_EocEosConversionTime = 0;   // set eoc eos conv time to 0
+       devpriv->b_OutputMemoryStatus = 0;
+
+       // variables used in timer subdevice
+       devpriv->b_Timer2Mode = 0;
+       devpriv->b_Timer2Interrupt = 0;
+       devpriv->b_ExttrigEnable = 0;   // Disable ext trigger
+
+       /* Disable all interrupts, watchdog for the anolog output */
+       devpriv->b_ModeSelectRegister = 0;
+       outb(devpriv->b_ModeSelectRegister,
+               dev->iobase + APCI3120_WRITE_MODE_SELECT);
+
+       // Disables all counters, ext trigger and clears PA, PR
+       devpriv->us_OutputRegister = 0;
+       outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
+
+       //Code to set the all anolog o/p channel to 0v
+       //8191 is decimal value for zero(0 v)volt in bipolar mode(default)
+       outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1);      //channel 1
+       outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1);      //channel 2
+       outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1);      //channel 3
+       outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1);      //channel 4
+
+       outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2);      //channel 5
+       outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2);      //channel 6
+       outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2);      //channel 7
+       outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2);      //channel 8
+
+       //  Reset digital output to L0W
+
+//ES05  outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT);
+       udelay(10);
+
+       inw(dev->iobase + 0);   //make a dummy read
+       inb(dev->iobase + APCI3120_RESET_FIFO); // flush FIFO
+       inw(dev->iobase + APCI3120_RD_STATUS);  // flush A/D status register
+
+       //code to reset the RAM sequence
+       for (i = 0; i < 16; i++) {
+               us_TmpValue = i << 8;   //select the location
+               outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
+       }
+       return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     : int i_APCI3120_SetupChannelList(struct comedi_device * dev,   |
+|                     struct comedi_subdevice * s, int n_chan,unsigned int *chanlist|
+|                        ,char check)                                                                                   |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Task              :This function will first check channel list is ok or not|
+|and then initialize the sequence RAM with the polarity, Gain,Channel number |
+|If the last argument of function "check"is 1 then it only checks the channel|
+|list is ok or not.                                                                                                             |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device * dev                                                                        |
+|                     struct comedi_subdevice * s                                                                       |
+|                     int n_chan                                                                |
+                         unsigned int *chanlist
+                         char check
++----------------------------------------------------------------------------+
+| Return Value      :                                                                           |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_SetupChannelList(struct comedi_device * dev, struct comedi_subdevice * s,
+       int n_chan, unsigned int *chanlist, char check)
+{
+       unsigned int i;         //, differencial=0, bipolar=0;
+       unsigned int gain;
+       unsigned short us_TmpValue;
+
+       /* correct channel and range number check itself comedi/range.c */
+       if (n_chan < 1) {
+               if (!check)
+                       comedi_error(dev, "range/channel list is empty!");
+               return 0;
+       }
+       // All is ok, so we can setup channel/range list
+       if (check)
+               return 1;
+
+       //Code  to set the PA and PR...Here it set PA to 0..
+       devpriv->us_OutputRegister =
+               devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR;
+       devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8;
+       outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
+
+       for (i = 0; i < n_chan; i++) {
+               // store range list to card
+               us_TmpValue = CR_CHAN(chanlist[i]);     // get channel number;
+
+               if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES) {
+                       us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff);   // set bipolar
+               } else {
+                       us_TmpValue |= APCI3120_UNIPOLAR;       // enable unipolar......
+               }
+
+               gain = CR_RANGE(chanlist[i]);   // get gain number
+               us_TmpValue |= ((gain & 0x03) << 4);    //<<4 for G0 and G1 bit in RAM
+               us_TmpValue |= i << 8;  //To select the RAM LOCATION....
+               outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
+
+               printk("\n Gain = %i",
+                       (((unsigned char)CR_RANGE(chanlist[i]) & 0x03) << 2));
+               printk("\n Channel = %i", CR_CHAN(chanlist[i]));
+               printk("\n Polarity = %i", us_TmpValue & APCI3120_UNIPOLAR);
+       }
+       return 1;               // we can serve this with scan logic
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :  int i_APCI3120_ExttrigEnable(struct comedi_device * dev)    |
+|                                                                                                               |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Task              :  Enable the external trigger                                                  |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  :  struct comedi_device * dev                                                                       |
+|                                                                                                                               |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Return Value      :      0                                                                    |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_ExttrigEnable(struct comedi_device * dev)
+{
+
+       devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER;
+       outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
+       return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :  int i_APCI3120_ExttrigDisable(struct comedi_device * dev)   |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Task              :  Disables the external trigger                                        |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  :  struct comedi_device * dev                                                                       |
+|                                                                                                                               |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Return Value      :    0                                                                      |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_ExttrigDisable(struct comedi_device * dev)
+{
+       devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER;
+       outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
+       return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+|                    INTERRUPT FUNCTIONS                                                |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function name     : void v_APCI3120_Interrupt(int irq, void *d)                                                               |
+|                                                                                                               |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Task              :Interrupt handler for APCI3120                             |
+|                       When interrupt occurs this gets called.                 |
+|                       First it finds which interrupt has been generated and   |
+|                       handles  corresponding interrupt                        |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  :  int irq                                                                                          |
+|                        void *d                                                                                        |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Return Value      : void                                                                      |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+void v_APCI3120_Interrupt(int irq, void *d)
+{
+       struct comedi_device *dev = d;
+       USHORT int_daq;
+
+       unsigned int int_amcc, ui_Check, i;
+       USHORT us_TmpValue;
+       BYTE b_DummyRead;
+
+       struct comedi_subdevice *s = dev->subdevices + 0;
+       ui_Check = 1;
+
+       int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000;       // get IRQ reasons
+       int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);     // get AMCC INT register
+
+       if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) {
+               comedi_error(dev, "IRQ from unknow source");
+               return;
+       }
+
+       outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);        // shutdown IRQ reasons in AMCC
+
+       int_daq = (int_daq >> 12) & 0xF;
+
+       if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
+               //Disable ext trigger
+               i_APCI3120_ExttrigDisable(dev);
+               devpriv->b_ExttrigEnable = APCI3120_DISABLE;
+       }
+       //clear the timer 2 interrupt
+       inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER);
+
+       if (int_amcc & MASTER_ABORT_INT)
+               comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!");
+       if (int_amcc & TARGET_ABORT_INT)
+               comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!");
+
+       // Ckeck if EOC interrupt
+       if (((int_daq & 0x8) == 0)
+               && (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) {
+               if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
+
+                       // Read the AI Value
+
+                       devpriv->ui_AiReadData[0] =
+                               (UINT) inw(devpriv->iobase + 0);
+                       devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
+                       send_sig(SIGIO, devpriv->tsk_Current, 0);       // send signal to the sample
+               } else {
+                       //Disable EOC Interrupt
+                       devpriv->b_ModeSelectRegister =
+                               devpriv->
+                               b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT;
+                       outb(devpriv->b_ModeSelectRegister,
+                               devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
+
+               }
+       }
+
+       // Check If EOS interrupt
+       if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) {
+
+               if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE)      // enable this in without DMA ???
+               {
+
+                       if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
+                               ui_Check = 0;
+                               i_APCI3120_InterruptHandleEos(dev);
+                               devpriv->ui_AiActualScan++;
+                               devpriv->b_ModeSelectRegister =
+                                       devpriv->
+                                       b_ModeSelectRegister |
+                                       APCI3120_ENABLE_EOS_INT;
+                               outb(devpriv->b_ModeSelectRegister,
+                                       dev->iobase +
+                                       APCI3120_WRITE_MODE_SELECT);
+                       } else {
+                               ui_Check = 0;
+                               for (i = 0; i < devpriv->ui_AiNbrofChannels;
+                                       i++) {
+                                       us_TmpValue = inw(devpriv->iobase + 0);
+                                       devpriv->ui_AiReadData[i] =
+                                               (UINT) us_TmpValue;
+                               }
+                               devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
+                               devpriv->b_InterruptMode = APCI3120_EOC_MODE;
+
+                               send_sig(SIGIO, devpriv->tsk_Current, 0);       // send signal to the sample
+
+                       }
+
+               } else {
+                       devpriv->b_ModeSelectRegister =
+                               devpriv->
+                               b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
+                       outb(devpriv->b_ModeSelectRegister,
+                               dev->iobase + APCI3120_WRITE_MODE_SELECT);
+                       devpriv->b_EocEosInterrupt = APCI3120_DISABLE;  //Default settings
+                       devpriv->b_InterruptMode = APCI3120_EOC_MODE;
+               }
+
+       }
+       //Timer2 interrupt
+       if (int_daq & 0x1) {
+
+               switch (devpriv->b_Timer2Mode) {
+               case APCI3120_COUNTER:
+
+                       devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
+                       devpriv->b_ModeSelectRegister =
+                               devpriv->
+                               b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
+                       outb(devpriv->b_ModeSelectRegister,
+                               dev->iobase + APCI3120_WRITE_MODE_SELECT);
+
+                       // stop timer 2
+                       devpriv->us_OutputRegister =
+                               devpriv->
+                               us_OutputRegister & APCI3120_DISABLE_ALL_TIMER;
+                       outw(devpriv->us_OutputRegister,
+                               dev->iobase + APCI3120_WR_ADDRESS);
+
+                       //stop timer 0 and timer 1
+                       i_APCI3120_StopCyclicAcquisition(dev, s);
+                       devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
+
+                       //UPDATE-0.7.57->0.7.68comedi_done(dev,s);
+                       s->async->events |= COMEDI_CB_EOA;
+                       comedi_event(dev, s);
+
+                       break;
+
+               case APCI3120_TIMER:
+
+                       //Send a signal to from kernel to user space
+                       send_sig(SIGIO, devpriv->tsk_Current, 0);
+                       break;
+
+               case APCI3120_WATCHDOG:
+
+                       //Send a signal to from kernel to user space
+                       send_sig(SIGIO, devpriv->tsk_Current, 0);
+                       break;
+
+               default:
+
+                       // disable Timer Interrupt
+
+                       devpriv->b_ModeSelectRegister =
+                               devpriv->
+                               b_ModeSelectRegister &
+                               APCI3120_DISABLE_TIMER_INT;
+
+                       outb(devpriv->b_ModeSelectRegister,
+                               dev->iobase + APCI3120_WRITE_MODE_SELECT);
+
+               }
+
+               b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
+
+       }
+
+       if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
+               if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
+
+                       /****************************/
+                       /* Clear Timer Write TC INT */
+                       /****************************/
+
+                       outl(APCI3120_CLEAR_WRITE_TC_INT,
+                               devpriv->i_IobaseAmcc +
+                               APCI3120_AMCC_OP_REG_INTCSR);
+
+                       /************************************/
+                       /* Clears the timer status register */
+                       /************************************/
+                       inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
+                       v_APCI3120_InterruptDma(irq, d);        // do some data transfer
+               } else {
+                       /* Stops the Timer */
+                       outw(devpriv->
+                               us_OutputRegister & APCI3120_DISABLE_TIMER0 &
+                               APCI3120_DISABLE_TIMER1,
+                               dev->iobase + APCI3120_WR_ADDRESS);
+               }
+
+       }
+
+       return;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)   |
+|                                                                                                               |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Task              : This function handles EOS interrupt.                   |
+|                     This function copies the acquired data(from FIFO)      |
+|                              to Comedi buffer.                                                                        |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev                                                                         |
+|                                                                                                                               |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Return Value      : 0                                                                         |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+/*
+ * int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)
+{
+       int n_chan,i;
+       short *data;
+       struct comedi_subdevice *s=dev->subdevices+0;
+       struct comedi_async *async = s->async;
+       data=async->data+async->buf_int_ptr;
+        n_chan=devpriv->ui_AiNbrofChannels;
+
+       for(i=0;i<n_chan;i++)
+         {
+           data[i]=inw(dev->iobase+0);
+         }
+       async->buf_int_count+=n_chan*sizeof(short);
+       async->buf_int_ptr+=n_chan*sizeof(short);
+       comedi_eos(dev,s);
+       if (s->async->buf_int_ptr>=s->async->data_len) //  for buffer rool over
+                        {
+*//* buffer rollover */
+/*             s->async->buf_int_ptr=0;
+               comedi_eobuf(dev,s);
+         }
+       return 0;
+}*/
+int i_APCI3120_InterruptHandleEos(struct comedi_device * dev)
+{
+       int n_chan, i;
+       struct comedi_subdevice *s = dev->subdevices + 0;
+       int err = 1;
+
+       n_chan = devpriv->ui_AiNbrofChannels;
+
+       s->async->events = 0;
+
+       for (i = 0; i < n_chan; i++)
+               err &= comedi_buf_put(s->async, inw(dev->iobase + 0));
+
+       s->async->events |= COMEDI_CB_EOS;
+
+       if (err == 0)
+               s->async->events |= COMEDI_CB_OVERFLOW;
+
+       comedi_event(dev, s);
+
+       return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     : void v_APCI3120_InterruptDma(int irq, void *d)                                                                    |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Task              : This is a handler for the DMA interrupt                |
+|                        This function copies the data to Comedi Buffer.        |
+|                        For continuous DMA it reinitializes the DMA operation. |
+|                        For single mode DMA it stop the acquisition.           |
+|                                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : int irq, void *d                          |
+|                                                                                                                               |
++----------------------------------------------------------------------------+
+| Return Value      :  void                                                                     |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+void v_APCI3120_InterruptDma(int irq, void *d)
+{
+       struct comedi_device *dev = d;
+       struct comedi_subdevice *s = dev->subdevices + 0;
+       unsigned int next_dma_buf, samplesinbuf;
+       unsigned long low_word, high_word, var;
+
+       UINT ui_Tmp;
+       samplesinbuf =
+               devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] -
+               inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC);
+
+       if (samplesinbuf <
+               devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) {
+               comedi_error(dev, "Interrupted DMA transfer!");
+       }
+       if (samplesinbuf & 1) {
+               comedi_error(dev, "Odd count of bytes in DMA ring!");
+               i_APCI3120_StopCyclicAcquisition(dev, s);
+               devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
+
+               return;
+       }
+       samplesinbuf = samplesinbuf >> 1;       // number of received samples
+       if (devpriv->b_DmaDoubleBuffer) {
+               // switch DMA buffers if is used double buffering
+               next_dma_buf = 1 - devpriv->ui_DmaActualBuffer;
+
+               ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
+               outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
+
+               // changed  since 16 bit interface for add on
+               outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
+               outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
+                       devpriv->i_IobaseAddon + 2);
+               outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
+               outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); // 0x1000 is out putted in windows driver
+
+               var = devpriv->ul_DmaBufferHw[next_dma_buf];
+               low_word = var & 0xffff;
+               var = devpriv->ul_DmaBufferHw[next_dma_buf];
+               high_word = var / 65536;
+
+               /* DMA Start Adress Low */
+               outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
+               outw(low_word, devpriv->i_IobaseAddon + 2);
+
+               /* DMA Start Adress High */
+               outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
+               outw(high_word, devpriv->i_IobaseAddon + 2);
+
+               var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
+               low_word = var & 0xffff;
+               var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
+               high_word = var / 65536;
+
+               /* Nbr of acquisition LOW */
+               outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
+               outw(low_word, devpriv->i_IobaseAddon + 2);
+
+               /* Nbr of acquisition HIGH */
+               outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
+               outw(high_word, devpriv->i_IobaseAddon + 2);
+
+               // To configure A2P FIFO
+               // ENABLE A2P FIFO WRITE AND ENABLE AMWEN
+               // AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
+               outw(3, devpriv->i_IobaseAddon + 4);
+               //initialise end of dma interrupt  AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI)
+               outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
+                               APCI3120_ENABLE_WRITE_TC_INT),
+                       devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
+
+       }
+/*UPDATE-0.7.57->0.7.68
+       ptr=(short *)devpriv->ul_DmaBufferVirtual[devpriv->ui_DmaActualBuffer];
+
+
+       // if there is not enough space left in the buffer to copy all data contained in the DMABufferVirtual
+       if(s->async->buf_int_ptr+samplesinbuf*sizeof(short)>=devpriv->ui_AiDataLength)
+       {
+               m=(devpriv->ui_AiDataLength-s->async->buf_int_ptr)/sizeof(short);
+               v_APCI3120_InterruptDmaMoveBlock16bit(dev,s,(void *)ptr,((void *)(devpriv->AiData))+s->async->buf_int_ptr,m);
+               s->async->buf_int_count+=m*sizeof(short);
+               ptr+=m*sizeof(short);
+                samplesinbuf-=m;
+               s->async->buf_int_ptr=0;
+               comedi_eobuf(dev,s);
+       }
+
+       if (samplesinbuf)
+       {
+               v_APCI3120_InterruptDmaMoveBlock16bit(dev,s,(void *)ptr,((void *)(devpriv->AiData))+s->async->buf_int_ptr,samplesinbuf);
+
+               s->async->buf_int_count+=samplesinbuf*sizeof(short);
+               s->async->buf_int_ptr+=samplesinbuf*sizeof(short);
+               if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS))
+               {
+                       comedi_bufcheck(dev,s);
+                }
+       }
+       if (!devpriv->b_AiContinuous)
+       if ( devpriv->ui_AiActualScan>=devpriv->ui_AiNbrofScans )
+       {
+           // all data sampled
+           i_APCI3120_StopCyclicAcquisition(dev,s);
+            devpriv->b_AiCyclicAcquisition=APCI3120_DISABLE;
+           //DPRINTK("\n Single DMA completed..\n");
+               comedi_done(dev,s);
+               return;
+       }
+*/
+       if (samplesinbuf) {
+               v_APCI3120_InterruptDmaMoveBlock16bit(dev, s,
+                       devpriv->ul_DmaBufferVirtual[devpriv->
+                               ui_DmaActualBuffer], samplesinbuf);
+
+               if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) {
+                       s->async->events |= COMEDI_CB_EOS;
+                       comedi_event(dev, s);
+               }
+       }
+       if (!devpriv->b_AiContinuous)
+               if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) {
+                       // all data sampled
+                       i_APCI3120_StopCyclicAcquisition(dev, s);
+                       devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
+                       s->async->events |= COMEDI_CB_EOA;
+                       comedi_event(dev, s);
+                       return;
+               }
+
+       if (devpriv->b_DmaDoubleBuffer) {       // switch dma buffers
+               devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
+       } else {
+               // restart DMA if is not used double buffering
+               //ADDED REINITIALISE THE DMA
+               ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
+               outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
+
+               // changed  since 16 bit interface for add on
+               outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
+               outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
+                       devpriv->i_IobaseAddon + 2);
+               outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
+               outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); //
+               // A2P FIFO MANAGEMENT
+               // A2P fifo reset  & transfer control enable
+               outl(APCI3120_A2P_FIFO_MANAGEMENT,
+                       devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
+
+               var = devpriv->ul_DmaBufferHw[0];
+               low_word = var & 0xffff;
+               var = devpriv->ul_DmaBufferHw[0];
+               high_word = var / 65536;
+               outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
+               outw(low_word, devpriv->i_IobaseAddon + 2);
+               outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
+               outw(high_word, devpriv->i_IobaseAddon + 2);
+
+               var = devpriv->ui_DmaBufferUsesize[0];
+               low_word = var & 0xffff;        //changed
+               var = devpriv->ui_DmaBufferUsesize[0];
+               high_word = var / 65536;
+               outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
+               outw(low_word, devpriv->i_IobaseAddon + 2);
+               outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
+               outw(high_word, devpriv->i_IobaseAddon + 2);
+
+               // To configure A2P FIFO
+               //ENABLE A2P FIFO WRITE AND ENABLE AMWEN
+               // AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
+               outw(3, devpriv->i_IobaseAddon + 4);
+               //initialise end of dma interrupt  AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI)
+               outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
+                               APCI3120_ENABLE_WRITE_TC_INT),
+                       devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
+       }
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device|
+|*dev,struct comedi_subdevice *s,short *dma,short *data,int n)                              |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Task              : This function copies the data from DMA buffer to the   |
+|                               Comedi buffer                                                                           |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev                                                                         |
+|                     struct comedi_subdevice *s                                                                        |
+|                     short *dma                                                                                        |
+|                     short *data,int n                                                         |
++----------------------------------------------------------------------------+
+| Return Value      : void                                                                      |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+/*void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,struct comedi_subdevice *s,short *dma,short *data,int n)
+{
+       int i,j,m;
+
+       j=s->async->cur_chan;
+       m=devpriv->ui_AiActualScanPosition;
+        for(i=0;i<n;i++)
+       {
+               *data=*dma;
+               data++; dma++;
+               j++;
+               if(j>=devpriv->ui_AiNbrofChannels)
+               {
+                       m+=j;
+                       j=0;
+                       if(m>=devpriv->ui_AiScanLength)
+                       {
+                               m=0;
+                               devpriv->ui_AiActualScan++;
+                               if (devpriv->ui_AiFlags & TRIG_WAKE_EOS)
+;//UPDATE-0.7.57->0.7.68                                       comedi_eos(dev,s);
+                       }
+               }
+       }
+        devpriv->ui_AiActualScanPosition=m;
+       s->async->cur_chan=j;
+
+}
+*/
+void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device * dev,
+       struct comedi_subdevice * s, short * dma_buffer, unsigned int num_samples)
+{
+       devpriv->ui_AiActualScan +=
+               (s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength;
+       s->async->cur_chan += num_samples;
+       s->async->cur_chan %= devpriv->ui_AiScanLength;
+
+       cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short));
+}
+
+/*
++----------------------------------------------------------------------------+
+|                           TIMER SUBDEVICE                                     |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnConfigTimer(struct comedi_device *dev,          |
+|      struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)                              |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Task              :Configure Timer 2                                                                      |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev                                                                         |
+|                     struct comedi_subdevice *s                                                                        |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data                                                                                |
+|                                                                                                                               |
+|                      data[0]= TIMER  configure as timer                    |
+|                                               = WATCHDOG configure as watchdog                                |
+|                                data[1] = Timer constant                                                       |
+|                                data[2] = Timer2 interrupt (1)enable or(0) disable |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Return Value      :                                                                           |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnConfigTimer(struct comedi_device * dev, struct comedi_subdevice * s,
+       struct comedi_insn * insn, unsigned int * data)
+{
+
+       UINT ui_Timervalue2;
+       USHORT us_TmpValue;
+       BYTE b_Tmp;
+
+       if (!data[1])
+               comedi_error(dev, "config:No timer constant !");
+
+       devpriv->b_Timer2Interrupt = (BYTE) data[2];    // save info whether to enable or disable interrupt
+
+       ui_Timervalue2 = data[1] / 1000;        // convert nano seconds  to u seconds
+
+       //this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(BYTE)data[0]);
+       us_TmpValue = (USHORT) inw(devpriv->iobase + APCI3120_RD_STATUS);
+
+       //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
+       // and calculate the time value to set in the timer
+       if ((us_TmpValue & 0x00B0) == 0x00B0
+               || !strcmp(this_board->pc_DriverName, "apci3001")) {
+               //Calculate the time value to set in the timer
+               ui_Timervalue2 = ui_Timervalue2 / 50;
+       } else {
+               //Calculate the time value to set in the timer
+               ui_Timervalue2 = ui_Timervalue2 / 70;
+       }
+
+       //Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0)
+       devpriv->us_OutputRegister =
+               devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2;
+       outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS);
+
+       // Disable TIMER Interrupt
+       devpriv->b_ModeSelectRegister =
+               devpriv->
+               b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF;
+
+       // Disable Eoc and Eos Interrupts
+       devpriv->b_ModeSelectRegister =
+               devpriv->
+               b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT &
+               APCI3120_DISABLE_EOS_INT;
+       outb(devpriv->b_ModeSelectRegister,
+               devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
+       if (data[0] == APCI3120_TIMER)  //initialize timer
+       {
+
+               //devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister| APCI3120_ENABLE_TIMER_INT ;
+               //outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT);
+
+               //Set the Timer 2 in mode 2(Timer)
+               devpriv->b_TimerSelectMode =
+                       (devpriv->
+                       b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2;
+               outb(devpriv->b_TimerSelectMode,
+                       devpriv->iobase + APCI3120_TIMER_CRT1);
+
+               //Configure the timer 2 for writing the LOW WORD of timer is Delay value
+               //You must make a b_tmp variable with DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
+               //you can set the digital output and configure the timer 2,and if you don't make this, digital output
+               //are erase (Set to 0)
+
+               //Writing LOW WORD
+               b_Tmp = ((devpriv->
+                               b_DigitalOutputRegister) & 0xF0) |
+                       APCI3120_SELECT_TIMER_2_LOW_WORD;
+               outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+               outw(LOWORD(ui_Timervalue2),
+                       devpriv->iobase + APCI3120_TIMER_VALUE);
+
+               //Writing HIGH WORD
+               b_Tmp = ((devpriv->
+                               b_DigitalOutputRegister) & 0xF0) |
+                       APCI3120_SELECT_TIMER_2_HIGH_WORD;
+               outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+               outw(HIWORD(ui_Timervalue2),
+                       devpriv->iobase + APCI3120_TIMER_VALUE);
+               // timer2 in Timer mode enabled
+               devpriv->b_Timer2Mode = APCI3120_TIMER;
+
+       } else                  // Initialize Watch dog
+       {
+
+               //Set the Timer 2 in mode 5(Watchdog)
+
+               devpriv->b_TimerSelectMode =
+                       (devpriv->
+                       b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5;
+               outb(devpriv->b_TimerSelectMode,
+                       devpriv->iobase + APCI3120_TIMER_CRT1);
+
+               //Configure the timer 2 for writing the LOW WORD of timer is Delay value
+               //You must make a b_tmp variable with DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
+               //you can set the digital output and configure the timer 2,and if you don't make this, digital output
+               //are erase (Set to 0)
+
+               //Writing LOW WORD
+               b_Tmp = ((devpriv->
+                               b_DigitalOutputRegister) & 0xF0) |
+                       APCI3120_SELECT_TIMER_2_LOW_WORD;
+               outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+               outw(LOWORD(ui_Timervalue2),
+                       devpriv->iobase + APCI3120_TIMER_VALUE);
+
+               //Writing HIGH WORD
+               b_Tmp = ((devpriv->
+                               b_DigitalOutputRegister) & 0xF0) |
+                       APCI3120_SELECT_TIMER_2_HIGH_WORD;
+               outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+
+               outw(HIWORD(ui_Timervalue2),
+                       devpriv->iobase + APCI3120_TIMER_VALUE);
+               //watchdog enabled
+               devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
+
+       }
+
+       return insn->n;
+
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnWriteTimer(struct comedi_device *dev,           |
+|                    struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)  |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Task              :    To start and stop the timer                            |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev                                                                         |
+|                     struct comedi_subdevice *s                                                                        |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data                                         |
+|                                                                            |
+|                              data[0] = 1 (start)                                  |
+|                              data[0] = 0 (stop )                                  |
+|                              data[0] = 2  (write new value)                       |
+|                              data[1]= new value                                   |
+|                                                                            |
+|                              devpriv->b_Timer2Mode =  0 DISABLE                   |
+|                                                               1 Timer                     |
+|                                                                               2 Watch dog                         |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Return Value      :                                                                           |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnWriteTimer(struct comedi_device * dev, struct comedi_subdevice * s,
+       struct comedi_insn * insn, unsigned int * data)
+{
+
+       UINT ui_Timervalue2 = 0;
+       USHORT us_TmpValue;
+       BYTE b_Tmp;
+
+       if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
+               && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
+               comedi_error(dev, "\nwrite:timer2  not configured ");
+               return -EINVAL;
+       }
+
+       if (data[0] == 2)       // write new value
+       {
+               if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
+                       comedi_error(dev,
+                               "write :timer2  not configured  in TIMER MODE");
+                       return -EINVAL;
+               }
+
+               if (data[1])
+                       ui_Timervalue2 = data[1];
+               else
+                       ui_Timervalue2 = 0;
+       }
+
+       //this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2);
+
+       switch (data[0]) {
+       case APCI3120_START:
+
+               // Reset FC_TIMER BIT
+               inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
+               if (devpriv->b_Timer2Mode == APCI3120_TIMER)    //start timer
+               {
+                       //Enable Timer
+                       devpriv->b_ModeSelectRegister =
+                               devpriv->b_ModeSelectRegister & 0x0B;
+               } else          //start watch dog
+               {
+                       //Enable WatchDog
+                       devpriv->b_ModeSelectRegister =
+                               (devpriv->
+                               b_ModeSelectRegister & 0x0B) |
+                               APCI3120_ENABLE_WATCHDOG;
+               }
+
+               //enable disable interrupt
+               if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) {
+
+                       devpriv->b_ModeSelectRegister =
+                               devpriv->
+                               b_ModeSelectRegister |
+                               APCI3120_ENABLE_TIMER_INT;
+                       // save the task structure to pass info to user
+                       devpriv->tsk_Current = current;
+               } else {
+
+                       devpriv->b_ModeSelectRegister =
+                               devpriv->
+                               b_ModeSelectRegister &
+                               APCI3120_DISABLE_TIMER_INT;
+               }
+               outb(devpriv->b_ModeSelectRegister,
+                       devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
+
+               if (devpriv->b_Timer2Mode == APCI3120_TIMER)    //start timer
+               {
+                       //For Timer mode is  Gate2 must be activated   **timer started
+                       devpriv->us_OutputRegister =
+                               devpriv->
+                               us_OutputRegister | APCI3120_ENABLE_TIMER2;
+                       outw(devpriv->us_OutputRegister,
+                               devpriv->iobase + APCI3120_WR_ADDRESS);
+               }
+
+               break;
+
+       case APCI3120_STOP:
+               if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
+                       //Disable timer
+                       devpriv->b_ModeSelectRegister =
+                               devpriv->
+                               b_ModeSelectRegister &
+                               APCI3120_DISABLE_TIMER_COUNTER;
+               } else {
+                       //Disable WatchDog
+                       devpriv->b_ModeSelectRegister =
+                               devpriv->
+                               b_ModeSelectRegister &
+                               APCI3120_DISABLE_WATCHDOG;
+               }
+               // Disable timer interrupt
+               devpriv->b_ModeSelectRegister =
+                       devpriv->
+                       b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT;
+
+               // Write above states  to register
+               outb(devpriv->b_ModeSelectRegister,
+                       devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
+
+               // Reset Gate 2
+               devpriv->us_OutputRegister =
+                       devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT;
+               outw(devpriv->us_OutputRegister,
+                       devpriv->iobase + APCI3120_WR_ADDRESS);
+
+               // Reset FC_TIMER BIT
+               inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
+
+               // Disable timer
+               //devpriv->b_Timer2Mode=APCI3120_DISABLE;
+
+               break;
+
+       case 2:         //write new value to Timer
+               if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
+                       comedi_error(dev,
+                               "write :timer2  not configured  in TIMER MODE");
+                       return -EINVAL;
+               }
+               // ui_Timervalue2=data[1]; // passed as argument
+               us_TmpValue =
+                       (USHORT) inw(devpriv->iobase + APCI3120_RD_STATUS);
+
+               //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
+               // and calculate the time value to set in the timer
+               if ((us_TmpValue & 0x00B0) == 0x00B0
+                       || !strcmp(this_board->pc_DriverName, "apci3001")) {
+                       //Calculate the time value to set in the timer
+                       ui_Timervalue2 = ui_Timervalue2 / 50;
+               } else {
+                       //Calculate the time value to set in the timer
+                       ui_Timervalue2 = ui_Timervalue2 / 70;
+               }
+               //Writing LOW WORD
+               b_Tmp = ((devpriv->
+                               b_DigitalOutputRegister) & 0xF0) |
+                       APCI3120_SELECT_TIMER_2_LOW_WORD;
+               outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+
+               outw(LOWORD(ui_Timervalue2),
+                       devpriv->iobase + APCI3120_TIMER_VALUE);
+
+               //Writing HIGH WORD
+               b_Tmp = ((devpriv->
+                               b_DigitalOutputRegister) & 0xF0) |
+                       APCI3120_SELECT_TIMER_2_HIGH_WORD;
+               outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+
+               outw(HIWORD(ui_Timervalue2),
+                       devpriv->iobase + APCI3120_TIMER_VALUE);
+
+               break;
+       default:
+               return -EINVAL; // Not a valid input
+       }
+
+       return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     : int i_APCI3120_InsnReadTimer(struct comedi_device *dev,           |
+|              struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data)                 |
+|                                                                                                               |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Task              : read the Timer value                                                      |
++----------------------------------------------------------------------------+
+| Input Parameters  :  struct comedi_device *dev                                                                        |
+|                     struct comedi_subdevice *s                                                                        |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data                                                                                |
+|                                                                                                                               |
++----------------------------------------------------------------------------+
+| Return Value      :                                                                                                           |
+|                      for Timer:      data[0]= Timer constant                                          |
+|                                                                                                                                       |
+|                      for watchdog: data[0]=0 (still running)                  |
+|                                        data[0]=1  (run down)                                  |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+int i_APCI3120_InsnReadTimer(struct comedi_device * dev, struct comedi_subdevice * s,
+       struct comedi_insn * insn, unsigned int * data)
+{
+       BYTE b_Tmp;
+       USHORT us_TmpValue, us_TmpValue_2, us_StatusValue;
+
+       if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
+               && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
+               comedi_error(dev, "\nread:timer2  not configured ");
+       }
+
+       //this_board->i_hwdrv_InsnReadTimer(dev,data);
+       if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
+
+               //Read the LOW WORD of Timer 2 register
+               b_Tmp = ((devpriv->
+                               b_DigitalOutputRegister) & 0xF0) |
+                       APCI3120_SELECT_TIMER_2_LOW_WORD;
+               outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+
+               us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
+
+               //Read the HIGH WORD of Timer 2 register
+               b_Tmp = ((devpriv->
+                               b_DigitalOutputRegister) & 0xF0) |
+                       APCI3120_SELECT_TIMER_2_HIGH_WORD;
+               outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+
+               us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
+
+               // combining both words
+               data[0] = (UINT) ((us_TmpValue) | ((us_TmpValue_2) << 16));
+
+       } else                  // Read watch dog status
+       {
+
+               us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS);
+               us_StatusValue =
+                       ((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1;
+               if (us_StatusValue == 1) {
+                       // RESET FC_TIMER BIT
+                       inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
+               }
+               data[0] = us_StatusValue;       // when data[0] = 1 then the watch dog has rundown
+       }
+       return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+|                           DIGITAL INPUT SUBDEVICE                             |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev,     |
+|                      struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)   |
+|                                                                                                               |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Task              : Reads the value of the specified  Digital input channel|
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev                                                                         |
+|                     struct comedi_subdevice *s                                                                        |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data                                                                                |
++----------------------------------------------------------------------------+
+| Return Value      :                                                                           |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev,
+                                   struct comedi_subdevice *s,
+                                   struct comedi_insn *insn,
+                                   unsigned int *data)
+{
+       UINT ui_Chan, ui_TmpValue;
+
+       ui_Chan = CR_CHAN(insn->chanspec);      // channel specified
+
+       //this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data);
+       if (ui_Chan >= 0 && ui_Chan <= 3) {
+               ui_TmpValue = (UINT) inw(devpriv->iobase + APCI3120_RD_STATUS);
+
+               //      since only 1 channel reqd  to bring it to last bit it is rotated
+               //  8 +(chan - 1) times then ANDed with 1 for last bit.
+               *data = (ui_TmpValue >> (ui_Chan + 8)) & 1;
+               //return 0;
+       } else {
+               //      comedi_error(dev," chan spec wrong");
+               return -EINVAL; // "sorry channel spec wrong "
+       }
+       return insn->n;
+
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, |
+|struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)                      |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Task              : Reads the value of the Digital input Port i.e.4channels|
+|   value is returned in data[0]                                                                                        |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev                                                                         |
+|                     struct comedi_subdevice *s                                                                        |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data                                                                                |
++----------------------------------------------------------------------------+
+| Return Value      :                                                                           |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+int i_APCI3120_InsnBitsDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s,
+       struct comedi_insn * insn, unsigned int * data)
+{
+       UINT ui_TmpValue;
+       ui_TmpValue = (UINT) inw(devpriv->iobase + APCI3120_RD_STATUS);
+       /*****  state of 4 channels  in the 11, 10, 9, 8   bits of status reg
+                       rotated right 8 times to bring them to last four bits
+                       ANDed with oxf for  value.
+       *****/
+
+       *data = (ui_TmpValue >> 8) & 0xf;
+       //this_board->i_hwdrv_InsnBitsDigitalInput(dev,data);
+       return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+|                           DIGITAL OUTPUT SUBDEVICE                                    |
++----------------------------------------------------------------------------+
+*/
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device    |
+| *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)                          |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Task              :Configure the output memory ON or OFF                                  |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  :struct comedi_device *dev                                                                          |
+|                     struct comedi_subdevice *s                                                                        |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data                                                                                |
++----------------------------------------------------------------------------+
+| Return Value      :                                                                           |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device * dev,
+       struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+
+       if ((data[0] != 0) && (data[0] != 1)) {
+               comedi_error(dev,
+                       "Not a valid Data !!! ,Data should be 1 or 0\n");
+               return -EINVAL;
+       }
+       if (data[0]) {
+               devpriv->b_OutputMemoryStatus = APCI3120_ENABLE;
+
+       } else {
+               devpriv->b_OutputMemoryStatus = APCI3120_DISABLE;
+               devpriv->b_DigitalOutputRegister = 0;
+       }
+       if (!devpriv->b_OutputMemoryStatus) {
+               ui_Temp = 0;
+
+       }                       //if(!devpriv->b_OutputMemoryStatus )
+
+       return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev,    |
+|              struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)                 |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Task              : write diatal output port                                                      |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev                                                                         |
+|                     struct comedi_subdevice *s                                                                        |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data                                                                                |
+                      data[0]     Value to be written
+                      data[1]    :1 Set digital o/p ON
+                      data[1]     2 Set digital o/p OFF with memory ON
++----------------------------------------------------------------------------+
+| Return Value      :                                                                           |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device * dev,
+                                    struct comedi_subdevice *s,
+                                    struct comedi_insn *insn,
+                                    unsigned int *data)
+{
+       if ((data[0] > this_board->i_DoMaxdata) || (data[0] < 0)) {
+
+               comedi_error(dev, "Data is not valid !!! \n");
+               return -EINVAL;
+       }
+
+       switch (data[1]) {
+       case 1:
+               data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
+               break;
+
+       case 2:
+               data[0] = data[0];
+               break;
+       default:
+               printk("\nThe parameter passed is in error \n");
+               return -EINVAL;
+       }                       // switch(data[1])
+       outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
+
+       devpriv->b_DigitalOutputRegister = data[0] & 0xF0;
+
+       return insn->n;
+
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,|
+|struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)                                    |
+|                                                                                               |
++----------------------------------------------------------------------------+
+| Task              : Write digiatl output                                                                  |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev                                                                         |
+|                     struct comedi_subdevice *s                                                                        |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data                                                                                |
+                      data[0]     Value to be written
+                      data[1]    :1 Set digital o/p ON
+                      data[1]     2 Set digital o/p OFF with memory ON
++----------------------------------------------------------------------------+
+| Return Value      :                                                                           |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,
+                                     struct comedi_subdevice *s,
+                                     struct comedi_insn *insn,
+                                     unsigned int *data)
+{
+
+       UINT ui_Temp1;
+
+       UINT ui_NoOfChannel = CR_CHAN(insn->chanspec);  // get the channel
+
+       if ((data[0] != 0) && (data[0] != 1)) {
+               comedi_error(dev,
+                       "Not a valid Data !!! ,Data should be 1 or 0\n");
+               return -EINVAL;
+       }
+       if ((ui_NoOfChannel > (this_board->i_NbrDoChannel - 1))
+               || (ui_NoOfChannel < 0)) {
+               comedi_error(dev,
+                       "This board doesn't have specified channel !!! \n");
+               return -EINVAL;
+       }
+
+       switch (data[1]) {
+       case 1:
+               data[0] = (data[0] << ui_NoOfChannel);
+//ES05                   data[0]=(data[0]<<4)|ui_Temp;
+               data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
+               break;
+
+       case 2:
+               data[0] = ~data[0] & 0x1;
+               ui_Temp1 = 1;
+               ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
+               ui_Temp1 = ui_Temp1 << 4;
+//ES05                   ui_Temp=ui_Temp|ui_Temp1;
+               devpriv->b_DigitalOutputRegister =
+                       devpriv->b_DigitalOutputRegister | ui_Temp1;
+
+               data[0] = (data[0] << ui_NoOfChannel) ^ 0xf;
+               data[0] = data[0] << 4;
+//ES05                   data[0]=data[0]& ui_Temp;
+               data[0] = data[0] & devpriv->b_DigitalOutputRegister;
+               break;
+       default:
+               printk("\nThe parameter passed is in error \n");
+               return -EINVAL;
+       }                       // switch(data[1])
+       outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
+
+//ES05        ui_Temp=data[0] & 0xf0;
+       devpriv->b_DigitalOutputRegister = data[0] & 0xf0;
+       return (insn->n);
+
+}
+
+/*
++----------------------------------------------------------------------------+
+|                            ANALOG OUTPUT SUBDEVICE                         |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,|
+|struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)                                   |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Task              : Write  analog output                                                          |
+|                                                                                                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev                                                                         |
+|                     struct comedi_subdevice *s                                                                        |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data                                                                                |
++----------------------------------------------------------------------------+
+| Return Value      :                                                                           |
+|                                                                                                                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,
+                                    struct comedi_subdevice *s,
+                                    struct comedi_insn *insn,
+                                    unsigned int *data)
+{
+       UINT ui_Range, ui_Channel;
+       USHORT us_TmpValue;
+
+       ui_Range = CR_RANGE(insn->chanspec);
+       ui_Channel = CR_CHAN(insn->chanspec);
+
+       //this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]);
+       if (ui_Range)           // if 1 then unipolar
+       {
+
+               if (data[0] != 0)
+                       data[0] =
+                               ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
+                                       13) | (data[0] + 8191));
+               else
+                       data[0] =
+                               ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
+                                       13) | 8192);
+
+       } else                  // if 0 then   bipolar
+       {
+               data[0] =
+                       ((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) |
+                       data[0]);
+
+       }
+
+       //out put n values at the given channel.
+       // rt_printk("\nwaiting for DA_READY BIT");
+       do                      //Waiting of DA_READY BIT
+       {
+               us_TmpValue =
+                       ((USHORT) inw(devpriv->iobase +
+                               APCI3120_RD_STATUS)) & 0x0001;
+       } while (us_TmpValue != 0x0001);
+
+       if (ui_Channel <= 3)
+               // for channel 0-3 out at  the register 1 (wrDac1-8)
+               // data[i] typecasted to ushort since  word write is to be done
+               outw((USHORT) data[0],
+                       devpriv->iobase + APCI3120_ANALOG_OUTPUT_1);
+       else
+               // for channel 4-7 out at the register 2 (wrDac5-8)
+               //data[i] typecasted to ushort since  word write is to be done
+               outw((USHORT) data[0],
+                       devpriv->iobase + APCI3120_ANALOG_OUTPUT_2);
+
+       return insn->n;
+}