]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c
Merge branch 'omap-pool'
[linux-2.6-omap-h63xx.git] / drivers / staging / comedi / drivers / addi-data / hwdrv_apci3xxx.c
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c
new file mode 100644 (file)
index 0000000..b7268e4
--- /dev/null
@@ -0,0 +1,1691 @@
+/**
+@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-3XXX       | Compiler   : GCC                      |
+  | Module name : hwdrv_apci3xxx.c| Version    : 2.96                     |
+  +-------------------------------+---------------------------------------+
+  | Project manager: S. Weber     | Date       :  15/09/2005              |
+  +-----------------------------------------------------------------------+
+  | Description :APCI3XXX Module.  Hardware abstraction Layer for APCI3XXX|
+  +-----------------------------------------------------------------------+
+  |                             UPDATE'S                                  |
+  +-----------------------------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |          |                  |                                                |
+  |          |           |                                               |
+  +----------+-----------+------------------------------------------------+
+*/
+
+#include "hwdrv_apci3xxx.h"
+
+/*
++----------------------------------------------------------------------------+
+|                         ANALOG INPUT FUNCTIONS                             |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT   i_APCI3XXX_TestConversionStarted                 |
+|                          (struct comedi_device    *dev)                           |
++----------------------------------------------------------------------------+
+| Task                Test if any conversion started                         |
++----------------------------------------------------------------------------+
+| Input Parameters  : -                                                      |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0 : Conversion not started                             |
+|                     1 : Conversion started                                 |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_TestConversionStarted(struct comedi_device * dev)
+{
+       if ((readl((void *)(devpriv->dw_AiBase + 8)) & 0x80000UL) == 0x80000UL) {
+               return (1);
+       } else {
+               return (0);
+       }
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT   i_APCI3XXX_AnalogInputConfigOperatingMode        |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task           Converting mode and convert time selection                  |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_SingleDiff  = (BYTE)  data[1];                       |
+|                     b_TimeBase    = (BYTE)  data[2]; (0: ns, 1:micros 2:ms)|
+|                    dw_ReloadValue = (DWORD) data[3];                       |
+|                     ........                                               |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :>0 : No error                                           |
+|                    -1 : Single/Diff selection error                        |
+|                    -2 : Convert time base unity selection error            |
+|                    -3 : Convert time value selection error                 |
+|                    -10: Any conversion started                             |
+|                    ....                                                    |
+|                    -100 : Config command error                             |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_AnalogInputConfigOperatingMode(struct comedi_device * dev,
+       struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+       INT i_ReturnValue = insn->n;
+       BYTE b_TimeBase = 0;
+       BYTE b_SingleDiff = 0;
+       DWORD dw_ReloadValue = 0;
+       DWORD dw_TestReloadValue = 0;
+
+       /************************/
+       /* Test the buffer size */
+       /************************/
+
+       if (insn->n == 4) {
+          /****************************/
+               /* Get the Singel/Diff flag */
+          /****************************/
+
+               b_SingleDiff = (BYTE) data[1];
+
+          /****************************/
+               /* Get the time base unitiy */
+          /****************************/
+
+               b_TimeBase = (BYTE) data[2];
+
+          /*************************************/
+               /* Get the convert time reload value */
+          /*************************************/
+
+               dw_ReloadValue = (DWORD) data[3];
+
+          /**********************/
+               /* Test the time base */
+          /**********************/
+
+               if ((devpriv->ps_BoardInfo->
+                               b_AvailableConvertUnit & (1 << b_TimeBase)) !=
+                       0) {
+             /*******************************/
+                       /* Test the convert time value */
+             /*******************************/
+
+                       if ((dw_ReloadValue >= 0) && (dw_ReloadValue <= 65535)) {
+                               dw_TestReloadValue = dw_ReloadValue;
+
+                               if (b_TimeBase == 1) {
+                                       dw_TestReloadValue =
+                                               dw_TestReloadValue * 1000UL;
+                               }
+                               if (b_TimeBase == 2) {
+                                       dw_TestReloadValue =
+                                               dw_TestReloadValue * 1000000UL;
+                               }
+
+                /*******************************/
+                               /* Test the convert time value */
+                /*******************************/
+
+                               if (dw_TestReloadValue >=
+                                       devpriv->ps_BoardInfo->
+                                       ui_MinAcquisitiontimeNs) {
+                                       if ((b_SingleDiff == APCI3XXX_SINGLE)
+                                               || (b_SingleDiff ==
+                                                       APCI3XXX_DIFF)) {
+                                               if (((b_SingleDiff == APCI3XXX_SINGLE) && (devpriv->ps_BoardInfo->i_NbrAiChannel == 0)) || ((b_SingleDiff == APCI3XXX_DIFF) && (devpriv->ps_BoardInfo->i_NbrAiChannelDiff == 0))) {
+                          /*******************************/
+                                                       /* Single/Diff selection error */
+                          /*******************************/
+
+                                                       printk("Single/Diff selection error\n");
+                                                       i_ReturnValue = -1;
+                                               } else {
+                          /**********************************/
+                                                       /* Test if conversion not started */
+                          /**********************************/
+
+                                                       if (i_APCI3XXX_TestConversionStarted(dev) == 0) {
+                                                               devpriv->
+                                                                       ui_EocEosConversionTime
+                                                                       =
+                                                                       (UINT)
+                                                                       dw_ReloadValue;
+                                                               devpriv->
+                                                                       b_EocEosConversionTimeBase
+                                                                       =
+                                                                       b_TimeBase;
+                                                               devpriv->
+                                                                       b_SingelDiff
+                                                                       =
+                                                                       b_SingleDiff;
+                                                               devpriv->
+                                                                       b_AiInitialisation
+                                                                       = 1;
+
+                             /*******************************/
+                                                               /* Set the convert timing unit */
+                             /*******************************/
+
+                                                               writel((DWORD)
+                                                                       b_TimeBase,
+                                                                       (void *)
+                                                                       (devpriv->
+                                                                               dw_AiBase
+                                                                               +
+                                                                               36));
+
+                             /**************************/
+                                                               /* Set the convert timing */
+                             /*************************/
+
+                                                               writel(dw_ReloadValue, (void *)(devpriv->dw_AiBase + 32));
+                                                       } else {
+                             /**************************/
+                                                               /* Any conversion started */
+                             /**************************/
+
+                                                               printk("Any conversion started\n");
+                                                               i_ReturnValue =
+                                                                       -10;
+                                                       }
+                                               }
+                                       } else {
+                      /*******************************/
+                                               /* Single/Diff selection error */
+                      /*******************************/
+
+                                               printk("Single/Diff selection error\n");
+                                               i_ReturnValue = -1;
+                                       }
+                               } else {
+                   /************************/
+                                       /* Time selection error */
+                   /************************/
+
+                                       printk("Convert time value selection error\n");
+                                       i_ReturnValue = -3;
+                               }
+                       } else {
+                /************************/
+                               /* Time selection error */
+                /************************/
+
+                               printk("Convert time value selection error\n");
+                               i_ReturnValue = -3;
+                       }
+               } else {
+             /*****************************/
+                       /* Time base selection error */
+             /*****************************/
+
+                       printk("Convert time base unity selection error\n");
+                       i_ReturnValue = -2;
+               }
+       } else {
+          /*******************/
+               /* Data size error */
+          /*******************/
+
+               printk("Buffer size error\n");
+               i_ReturnValue = -101;
+       }
+
+       return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT   i_APCI3XXX_InsnConfigAnalogInput                 |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task           Converting mode and convert time selection                  |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_ConvertMode = (BYTE)  data[0];                       |
+|                     b_TimeBase    = (BYTE)  data[1]; (0: ns, 1:micros 2:ms)|
+|                    dw_ReloadValue = (DWORD) data[2];                       |
+|                     ........                                               |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :>0: No error                                            |
+|                    ....                                                    |
+|                    -100 : Config command error                             |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnConfigAnalogInput(struct comedi_device * dev,
+       struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+       INT i_ReturnValue = insn->n;
+
+       /************************/
+       /* Test the buffer size */
+       /************************/
+
+       if (insn->n >= 1) {
+               switch ((BYTE) data[0]) {
+               case APCI3XXX_CONFIGURATION:
+                       i_ReturnValue =
+                               i_APCI3XXX_AnalogInputConfigOperatingMode(dev,
+                               s, insn, data);
+                       break;
+
+               default:
+                       i_ReturnValue = -100;
+                       printk("Config command error %d\n", data[0]);
+                       break;
+               }
+       } else {
+          /*******************/
+               /* Data size error */
+          /*******************/
+
+               printk("Buffer size error\n");
+               i_ReturnValue = -101;
+       }
+
+       return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT   i_APCI3XXX_InsnReadAnalogInput                   |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task                Read 1 analog input                                    |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_Range             = CR_RANGE(insn->chanspec);        |
+|                     b_Channel           = CR_CHAN(insn->chanspec);         |
+|                     dw_NbrOfAcquisition = insn->n;                         |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :>0: No error                                            |
+|                    -3 : Channel selection error                            |
+|                    -4 : Configuration selelection error                    |
+|                    -10: Any conversion started                             |
+|                    ....                                                    |
+|                    -100 : Config command error                             |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnReadAnalogInput(struct comedi_device * dev,
+       struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+       INT i_ReturnValue = insn->n;
+       BYTE b_Configuration = (BYTE) CR_RANGE(insn->chanspec);
+       BYTE b_Channel = (BYTE) CR_CHAN(insn->chanspec);
+       DWORD dw_Temp = 0;
+       DWORD dw_Configuration = 0;
+       DWORD dw_AcquisitionCpt = 0;
+       BYTE b_Interrupt = 0;
+
+       /*************************************/
+       /* Test if operating mode configured */
+       /*************************************/
+
+       if (devpriv->b_AiInitialisation) {
+          /***************************/
+               /* Test the channel number */
+          /***************************/
+
+               if (((b_Channel < devpriv->ps_BoardInfo->i_NbrAiChannel)
+                               && (devpriv->b_SingelDiff == APCI3XXX_SINGLE))
+                       || ((b_Channel < devpriv->ps_BoardInfo->
+                                       i_NbrAiChannelDiff)
+                               && (devpriv->b_SingelDiff == APCI3XXX_DIFF))) {
+             /**********************************/
+                       /* Test the channel configuration */
+             /**********************************/
+
+                       if (b_Configuration > 7) {
+                /***************************/
+                               /* Channel not initialised */
+                /***************************/
+
+                               i_ReturnValue = -4;
+                               printk("Channel %d range %d selection error\n",
+                                       b_Channel, b_Configuration);
+                       }
+               } else {
+             /***************************/
+                       /* Channel selection error */
+             /***************************/
+
+                       i_ReturnValue = -3;
+                       printk("Channel %d selection error\n", b_Channel);
+               }
+
+          /**************************/
+               /* Test if no error occur */
+          /**************************/
+
+               if (i_ReturnValue >= 0) {
+             /************************/
+                       /* Test the buffer size */
+             /************************/
+
+                       if ((b_Interrupt != 0) || ((b_Interrupt == 0)
+                                       && (insn->n >= 1))) {
+                /**********************************/
+                               /* Test if conversion not started */
+                /**********************************/
+
+                               if (i_APCI3XXX_TestConversionStarted(dev) == 0) {
+                   /******************/
+                                       /* Clear the FIFO */
+                   /******************/
+
+                                       writel(0x10000UL,
+                                               (void *)(devpriv->dw_AiBase +
+                                                       12));
+
+                   /*******************************/
+                                       /* Get and save the delay mode */
+                   /*******************************/
+
+                                       dw_Temp =
+                                               readl((void *)(devpriv->
+                                                       dw_AiBase + 4));
+                                       dw_Temp = dw_Temp & 0xFFFFFEF0UL;
+
+                   /***********************************/
+                                       /* Channel configuration selection */
+                   /***********************************/
+
+                                       writel(dw_Temp,
+                                               (void *)(devpriv->dw_AiBase +
+                                                       4));
+
+                   /**************************/
+                                       /* Make the configuration */
+                   /**************************/
+
+                                       dw_Configuration =
+                                               (b_Configuration & 3) |
+                                               ((DWORD) (b_Configuration >> 2)
+                                               << 6) | ((DWORD) devpriv->
+                                               b_SingelDiff << 7);
+
+                   /***************************/
+                                       /* Write the configuration */
+                   /***************************/
+
+                                       writel(dw_Configuration,
+                                               (void *)(devpriv->dw_AiBase +
+                                                       0));
+
+                   /*********************/
+                                       /* Channel selection */
+                   /*********************/
+
+                                       writel(dw_Temp | 0x100UL,
+                                               (void *)(devpriv->dw_AiBase +
+                                                       4));
+                                       writel((DWORD) b_Channel,
+                                               (void *)(devpriv->dw_AiBase +
+                                                       0));
+
+                   /***********************/
+                                       /* Restaure delay mode */
+                   /***********************/
+
+                                       writel(dw_Temp,
+                                               (void *)(devpriv->dw_AiBase +
+                                                       4));
+
+                   /***********************************/
+                                       /* Set the number of sequence to 1 */
+                   /***********************************/
+
+                                       writel(1,
+                                               (void *)(devpriv->dw_AiBase +
+                                                       48));
+
+                   /***************************/
+                                       /* Save the interrupt flag */
+                   /***************************/
+
+                                       devpriv->b_EocEosInterrupt =
+                                               b_Interrupt;
+
+                   /*******************************/
+                                       /* Save the number of channels */
+                   /*******************************/
+
+                                       devpriv->ui_AiNbrofChannels = 1;
+
+                   /******************************/
+                                       /* Test if interrupt not used */
+                   /******************************/
+
+                                       if (b_Interrupt == 0) {
+                                               for (dw_AcquisitionCpt = 0;
+                                                       dw_AcquisitionCpt <
+                                                       insn->n;
+                                                       dw_AcquisitionCpt++) {
+                         /************************/
+                                                       /* Start the conversion */
+                         /************************/
+
+                                                       writel(0x80000UL,
+                                                               (void *)
+                                                               (devpriv->
+                                                                       dw_AiBase
+                                                                       + 8));
+
+                         /****************/
+                                                       /* Wait the EOS */
+                         /****************/
+
+                                                       do {
+                                                               dw_Temp =
+                                                                       readl(
+                                                                       (void *)
+                                                                       (devpriv->
+                                                                               dw_AiBase
+                                                                               +
+                                                                               20));
+                                                               dw_Temp =
+                                                                       dw_Temp
+                                                                       & 1;
+                                                       }
+                                                       while (dw_Temp != 1);
+
+                         /*************************/
+                                                       /* Read the analog value */
+                         /*************************/
+
+                                                       data[dw_AcquisitionCpt]
+                                                               =
+                                                               (unsigned int)
+                                                               readl((void
+                                                                       *)
+                                                               (devpriv->
+                                                                       dw_AiBase
+                                                                       + 28));
+                                               }
+                                       } else {
+                      /************************/
+                                               /* Start the conversion */
+                      /************************/
+
+                                               writel(0x180000UL,
+                                                       (void *)(devpriv->
+                                                               dw_AiBase + 8));
+                                       }
+                               } else {
+                   /**************************/
+                                       /* Any conversion started */
+                   /**************************/
+
+                                       printk("Any conversion started\n");
+                                       i_ReturnValue = -10;
+                               }
+                       } else {
+                /*******************/
+                               /* Data size error */
+                /*******************/
+
+                               printk("Buffer size error\n");
+                               i_ReturnValue = -101;
+                       }
+               }
+       } else {
+          /***************************/
+               /* Channel selection error */
+          /***************************/
+
+               printk("Operating mode not configured\n");
+               i_ReturnValue = -1;
+       }
+       return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     : void v_APCI3XXX_Interrupt (int            irq,         |
+|                                                void           *d)       |
++----------------------------------------------------------------------------+
+| Task              :Interrupt handler for APCI3XXX                          |
+|                    When interrupt occurs this gets called.                 |
+|                    First it finds which interrupt has been generated and   |
+|                    handles  corresponding interrupt                        |
++----------------------------------------------------------------------------+
+| Input Parameters  : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : -                                                      |
++----------------------------------------------------------------------------+
+*/
+
+void v_APCI3XXX_Interrupt(int irq, void *d)
+{
+       struct comedi_device *dev = d;
+       BYTE b_CopyCpt = 0;
+       DWORD dw_Status = 0;
+
+       /***************************/
+       /* Test if interrupt occur */
+       /***************************/
+
+       if (((dw_Status = readl((void *)(devpriv->dw_AiBase + 16))) & 0x2UL) ==
+               0x2UL) {
+          /***********************/
+               /* Reset the interrupt */
+          /***********************/
+
+               writel(dw_Status, (void *)(devpriv->dw_AiBase + 16));
+
+          /*****************************/
+               /* Test if interrupt enabled */
+          /*****************************/
+
+               if (devpriv->b_EocEosInterrupt == 1) {
+             /********************************/
+                       /* Read all analog inputs value */
+             /********************************/
+
+                       for (b_CopyCpt = 0;
+                               b_CopyCpt < devpriv->ui_AiNbrofChannels;
+                               b_CopyCpt++) {
+                               devpriv->ui_AiReadData[b_CopyCpt] =
+                                       (UINT) readl((void *)(devpriv->
+                                               dw_AiBase + 28));
+                       }
+
+             /**************************/
+                       /* Set the interrupt flag */
+             /**************************/
+
+                       devpriv->b_EocEosInterrupt = 2;
+
+             /**********************************************/
+                       /* Send a signal to from kernel to user space */
+             /**********************************************/
+
+                       send_sig(SIGIO, devpriv->tsk_Current, 0);
+               }
+       }
+}
+
+/*
++----------------------------------------------------------------------------+
+|                            ANALOG OUTPUT SUBDEVICE                         |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT   i_APCI3XXX_InsnWriteAnalogOutput                 |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task                Read 1 analog input                                    |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_Range    = CR_RANGE(insn->chanspec);                 |
+|                     b_Channel  = CR_CHAN(insn->chanspec);                  |
+|                     data[0]    = analog value;                             |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :>0: No error                                            |
+|                    -3 : Channel selection error                            |
+|                    -4 : Configuration selelection error                    |
+|                    ....                                                    |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnWriteAnalogOutput(struct comedi_device * dev,
+       struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+       BYTE b_Range = (BYTE) CR_RANGE(insn->chanspec);
+       BYTE b_Channel = (BYTE) CR_CHAN(insn->chanspec);
+       DWORD dw_Status = 0;
+       INT i_ReturnValue = insn->n;
+
+       /************************/
+       /* Test the buffer size */
+       /************************/
+
+       if (insn->n >= 1) {
+          /***************************/
+               /* Test the channel number */
+          /***************************/
+
+               if (b_Channel < devpriv->ps_BoardInfo->i_NbrAoChannel) {
+             /**********************************/
+                       /* Test the channel configuration */
+             /**********************************/
+
+                       if (b_Range < 2) {
+                /***************************/
+                               /* Set the range selection */
+                /***************************/
+
+                               writel(b_Range,
+                                       (void *)(devpriv->dw_AiBase + 96));
+
+                /**************************************************/
+                               /* Write the analog value to the selected channel */
+                /**************************************************/
+
+                               writel((data[0] << 8) | b_Channel,
+                                       (void *)(devpriv->dw_AiBase + 100));
+
+                /****************************/
+                               /* Wait the end of transfer */
+                /****************************/
+
+                               do {
+                                       dw_Status =
+                                               readl((void *)(devpriv->
+                                                       dw_AiBase + 96));
+                               }
+                               while ((dw_Status & 0x100) != 0x100);
+                       } else {
+                /***************************/
+                               /* Channel not initialised */
+                /***************************/
+
+                               i_ReturnValue = -4;
+                               printk("Channel %d range %d selection error\n",
+                                       b_Channel, b_Range);
+                       }
+               } else {
+             /***************************/
+                       /* Channel selection error */
+             /***************************/
+
+                       i_ReturnValue = -3;
+                       printk("Channel %d selection error\n", b_Channel);
+               }
+       } else {
+          /*******************/
+               /* Data size error */
+          /*******************/
+
+               printk("Buffer size error\n");
+               i_ReturnValue = -101;
+       }
+
+       return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+|                              TTL FUNCTIONS                                 |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT   i_APCI3XXX_InsnConfigInitTTLIO                   |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task           You must calling this function be                           |
+|                for you call any other function witch access of TTL.        |
+|                APCI3XXX_TTL_INIT_DIRECTION_PORT2(user inputs for direction)|
++----------------------------------------------------------------------------+
+| Input Parameters  : b_InitType    = (BYTE) data[0];                        |
+|                     b_Port2Mode   = (BYTE) data[1];                        |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :>0: No error                                            |
+|                    -1: Port 2 mode selection is wrong                      |
+|                    ....                                                    |
+|                    -100 : Config command error                             |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnConfigInitTTLIO(struct comedi_device * dev,
+       struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+       INT i_ReturnValue = insn->n;
+       BYTE b_Command = 0;
+
+       /************************/
+       /* Test the buffer size */
+       /************************/
+
+       if (insn->n >= 1) {
+          /*******************/
+               /* Get the command */
+               /* **************** */
+
+               b_Command = (BYTE) data[0];
+
+          /********************/
+               /* Test the command */
+          /********************/
+
+               if (b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2) {
+             /***************************************/
+                       /* Test the initialisation buffer size */
+             /***************************************/
+
+                       if ((b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2)
+                               && (insn->n != 2)) {
+                /*******************/
+                               /* Data size error */
+                /*******************/
+
+                               printk("Buffer size error\n");
+                               i_ReturnValue = -101;
+                       }
+               } else {
+             /************************/
+                       /* Config command error */
+             /************************/
+
+                       printk("Command selection error\n");
+                       i_ReturnValue = -100;
+               }
+       } else {
+          /*******************/
+               /* Data size error */
+          /*******************/
+
+               printk("Buffer size error\n");
+               i_ReturnValue = -101;
+       }
+
+       /*********************************************************************************/
+       /* Test if no error occur and APCI3XXX_TTL_INIT_DIRECTION_PORT2 command selected */
+       /*********************************************************************************/
+
+       if ((i_ReturnValue >= 0)
+               && (b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2)) {
+          /**********************/
+               /* Test the direction */
+          /**********************/
+
+               if ((data[1] == 0) || (data[1] == 0xFF)) {
+             /**************************/
+                       /* Save the configuration */
+             /**************************/
+
+                       devpriv->ul_TTLPortConfiguration[0] =
+                               devpriv->ul_TTLPortConfiguration[0] | data[1];
+               } else {
+             /************************/
+                       /* Port direction error */
+             /************************/
+
+                       printk("Port 2 direction selection error\n");
+                       i_ReturnValue = -1;
+               }
+       }
+
+       /**************************/
+       /* Test if no error occur */
+       /**************************/
+
+       if (i_ReturnValue >= 0) {
+          /***********************************/
+               /* Test if TTL port initilaisation */
+          /***********************************/
+
+               if (b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2) {
+             /*************************/
+                       /* Set the configuration */
+             /*************************/
+
+                       outl(data[1], devpriv->iobase + 224);
+               }
+       }
+
+       return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+|                        TTL INPUT FUNCTIONS                                 |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT     i_APCI3XXX_InsnBitsTTLIO                       |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task              : Write the selected output mask and read the status from|
+|                     all TTL channles                                       |
++----------------------------------------------------------------------------+
+| Input Parameters  : dw_ChannelMask = data [0];                             |
+|                     dw_BitMask     = data [1];                             |
++----------------------------------------------------------------------------+
+| Output Parameters : data[1] : All TTL channles states                      |
++----------------------------------------------------------------------------+
+| Return Value      : >0  : No error                                         |
+|                    -4   : Channel mask error                               |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnBitsTTLIO(struct comedi_device * dev,
+       struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+       INT i_ReturnValue = insn->n;
+       BYTE b_ChannelCpt = 0;
+       DWORD dw_ChannelMask = 0;
+       DWORD dw_BitMask = 0;
+       DWORD dw_Status = 0;
+
+       /************************/
+       /* Test the buffer size */
+       /************************/
+
+       if (insn->n >= 2) {
+          /*******************************/
+               /* Get the channe and bit mask */
+          /*******************************/
+
+               dw_ChannelMask = data[0];
+               dw_BitMask = data[1];
+
+          /*************************/
+               /* Test the channel mask */
+          /*************************/
+
+               if (((dw_ChannelMask & 0XFF00FF00) == 0) &&
+                       (((devpriv->ul_TTLPortConfiguration[0] & 0xFF) == 0xFF)
+                               || (((devpriv->ul_TTLPortConfiguration[0] &
+                                                       0xFF) == 0)
+                                       && ((dw_ChannelMask & 0XFF0000) ==
+                                               0)))) {
+             /*********************************/
+                       /* Test if set/reset any channel */
+             /*********************************/
+
+                       if (dw_ChannelMask) {
+                /****************************************/
+                               /* Test if set/rest any port 0 channels */
+                /****************************************/
+
+                               if (dw_ChannelMask & 0xFF) {
+                   /*******************************************/
+                                       /* Read port 0 (first digital output port) */
+                   /*******************************************/
+
+                                       dw_Status = inl(devpriv->iobase + 80);
+
+                                       for (b_ChannelCpt = 0; b_ChannelCpt < 8;
+                                               b_ChannelCpt++) {
+                                               if ((dw_ChannelMask >>
+                                                               b_ChannelCpt) &
+                                                       1) {
+                                                       dw_Status =
+                                                               (dw_Status &
+                                                               (0xFF - (1 << b_ChannelCpt))) | (dw_BitMask & (1 << b_ChannelCpt));
+                                               }
+                                       }
+
+                                       outl(dw_Status, devpriv->iobase + 80);
+                               }
+
+                /****************************************/
+                               /* Test if set/rest any port 2 channels */
+                /****************************************/
+
+                               if (dw_ChannelMask & 0xFF0000) {
+                                       dw_BitMask = dw_BitMask >> 16;
+                                       dw_ChannelMask = dw_ChannelMask >> 16;
+
+                   /********************************************/
+                                       /* Read port 2 (second digital output port) */
+                   /********************************************/
+
+                                       dw_Status = inl(devpriv->iobase + 112);
+
+                                       for (b_ChannelCpt = 0; b_ChannelCpt < 8;
+                                               b_ChannelCpt++) {
+                                               if ((dw_ChannelMask >>
+                                                               b_ChannelCpt) &
+                                                       1) {
+                                                       dw_Status =
+                                                               (dw_Status &
+                                                               (0xFF - (1 << b_ChannelCpt))) | (dw_BitMask & (1 << b_ChannelCpt));
+                                               }
+                                       }
+
+                                       outl(dw_Status, devpriv->iobase + 112);
+                               }
+                       }
+
+             /*******************************************/
+                       /* Read port 0 (first digital output port) */
+             /*******************************************/
+
+                       data[1] = inl(devpriv->iobase + 80);
+
+             /******************************************/
+                       /* Read port 1 (first digital input port) */
+             /******************************************/
+
+                       data[1] = data[1] | (inl(devpriv->iobase + 64) << 8);
+
+             /************************/
+                       /* Test if port 2 input */
+             /************************/
+
+                       if ((devpriv->ul_TTLPortConfiguration[0] & 0xFF) == 0) {
+                               data[1] =
+                                       data[1] | (inl(devpriv->iobase +
+                                               96) << 16);
+                       } else {
+                               data[1] =
+                                       data[1] | (inl(devpriv->iobase +
+                                               112) << 16);
+                       }
+               } else {
+             /************************/
+                       /* Config command error */
+             /************************/
+
+                       printk("Channel mask error\n");
+                       i_ReturnValue = -4;
+               }
+       } else {
+          /*******************/
+               /* Data size error */
+          /*******************/
+
+               printk("Buffer size error\n");
+               i_ReturnValue = -101;
+       }
+
+       return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT i_APCI3XXX_InsnReadTTLIO                           |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task              : Read the status from selected channel                  |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_Channel = CR_CHAN(insn->chanspec)                    |
++----------------------------------------------------------------------------+
+| Output Parameters : data[0] : Selected TTL channel state                   |
++----------------------------------------------------------------------------+
+| Return Value      : 0   : No error                                         |
+|                    -3   : Channel selection error                          |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnReadTTLIO(struct comedi_device * dev,
+       struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+       BYTE b_Channel = (BYTE) CR_CHAN(insn->chanspec);
+       INT i_ReturnValue = insn->n;
+       unsigned int *pls_ReadData = data;
+
+       /************************/
+       /* Test the buffer size */
+       /************************/
+
+       if (insn->n >= 1) {
+          /***********************/
+               /* Test if read port 0 */
+          /***********************/
+
+               if (b_Channel < 8) {
+             /*******************************************/
+                       /* Read port 0 (first digital output port) */
+             /*******************************************/
+
+                       pls_ReadData[0] = inl(devpriv->iobase + 80);
+                       pls_ReadData[0] = (pls_ReadData[0] >> b_Channel) & 1;
+               } else {
+             /***********************/
+                       /* Test if read port 1 */
+             /***********************/
+
+                       if ((b_Channel > 7) && (b_Channel < 16)) {
+                /******************************************/
+                               /* Read port 1 (first digital input port) */
+                /******************************************/
+
+                               pls_ReadData[0] = inl(devpriv->iobase + 64);
+                               pls_ReadData[0] =
+                                       (pls_ReadData[0] >> (b_Channel -
+                                               8)) & 1;
+                       } else {
+                /***********************/
+                               /* Test if read port 2 */
+                /***********************/
+
+                               if ((b_Channel > 15) && (b_Channel < 24)) {
+                   /************************/
+                                       /* Test if port 2 input */
+                   /************************/
+
+                                       if ((devpriv->ul_TTLPortConfiguration[0]
+                                                       & 0xFF) == 0) {
+                                               pls_ReadData[0] =
+                                                       inl(devpriv->iobase +
+                                                       96);
+                                               pls_ReadData[0] =
+                                                       (pls_ReadData[0] >>
+                                                       (b_Channel - 16)) & 1;
+                                       } else {
+                                               pls_ReadData[0] =
+                                                       inl(devpriv->iobase +
+                                                       112);
+                                               pls_ReadData[0] =
+                                                       (pls_ReadData[0] >>
+                                                       (b_Channel - 16)) & 1;
+                                       }
+                               } else {
+                   /***************************/
+                                       /* Channel selection error */
+                   /***************************/
+
+                                       i_ReturnValue = -3;
+                                       printk("Channel %d selection error\n",
+                                               b_Channel);
+                               }
+                       }
+               }
+       } else {
+          /*******************/
+               /* Data size error */
+          /*******************/
+
+               printk("Buffer size error\n");
+               i_ReturnValue = -101;
+       }
+
+       return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+|                        TTL OUTPUT FUNCTIONS                                |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT     i_APCI3XXX_InsnWriteTTLIO                      |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task              : Set the state from TTL output channel                  |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_Channel = CR_CHAN(insn->chanspec)                    |
+|                     b_State   = data [0]                                   |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0   : No error                                         |
+|                    -3   : Channel selection error                          |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnWriteTTLIO(struct comedi_device * dev,
+       struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+       INT i_ReturnValue = insn->n;
+       BYTE b_Channel = (BYTE) CR_CHAN(insn->chanspec);
+       BYTE b_State = 0;
+       DWORD dw_Status = 0;
+
+       /************************/
+       /* Test the buffer size */
+       /************************/
+
+       if (insn->n >= 1) {
+               b_State = (BYTE) data[0];
+
+          /***********************/
+               /* Test if read port 0 */
+          /***********************/
+
+               if (b_Channel < 8) {
+             /*****************************************************************************/
+                       /* Read port 0 (first digital output port) and set/reset the selcted channel */
+             /*****************************************************************************/
+
+                       dw_Status = inl(devpriv->iobase + 80);
+                       dw_Status =
+                               (dw_Status & (0xFF -
+                                       (1 << b_Channel))) | ((b_State & 1) <<
+                               b_Channel);
+                       outl(dw_Status, devpriv->iobase + 80);
+               } else {
+             /***********************/
+                       /* Test if read port 2 */
+             /***********************/
+
+                       if ((b_Channel > 15) && (b_Channel < 24)) {
+                /*************************/
+                               /* Test if port 2 output */
+                /*************************/
+
+                               if ((devpriv->ul_TTLPortConfiguration[0] & 0xFF)
+                                       == 0xFF) {
+                   /*****************************************************************************/
+                                       /* Read port 2 (first digital output port) and set/reset the selcted channel */
+                   /*****************************************************************************/
+
+                                       dw_Status = inl(devpriv->iobase + 112);
+                                       dw_Status =
+                                               (dw_Status & (0xFF -
+                                                       (1 << (b_Channel -
+                                                                       16)))) |
+                                               ((b_State & 1) << (b_Channel -
+                                                       16));
+                                       outl(dw_Status, devpriv->iobase + 112);
+                               } else {
+                   /***************************/
+                                       /* Channel selection error */
+                   /***************************/
+
+                                       i_ReturnValue = -3;
+                                       printk("Channel %d selection error\n",
+                                               b_Channel);
+                               }
+                       } else {
+                /***************************/
+                               /* Channel selection error */
+                /***************************/
+
+                               i_ReturnValue = -3;
+                               printk("Channel %d selection error\n",
+                                       b_Channel);
+                       }
+               }
+       } else {
+          /*******************/
+               /* Data size error */
+          /*******************/
+
+               printk("Buffer size error\n");
+               i_ReturnValue = -101;
+       }
+
+       return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+|                           DIGITAL INPUT SUBDEVICE                          |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3XXX_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  : b_Channel = CR_CHAN(insn->chanspec) (0 to 3)           |
++----------------------------------------------------------------------------+
+| Output Parameters : data[0] : Channel value                                |
++----------------------------------------------------------------------------+
+| Return Value      : 0   : No error                                         |
+|                    -3   : Channel selection error                          |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnReadDigitalInput(struct comedi_device * dev,
+       struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+       INT i_ReturnValue = insn->n;
+       BYTE b_Channel = (BYTE) CR_CHAN(insn->chanspec);
+       DWORD dw_Temp = 0;
+
+       /***************************/
+       /* Test the channel number */
+       /***************************/
+
+       if (b_Channel <= devpriv->ps_BoardInfo->i_NbrDiChannel) {
+          /************************/
+               /* Test the buffer size */
+          /************************/
+
+               if (insn->n >= 1) {
+                       dw_Temp = inl(devpriv->iobase + 32);
+                       *data = (dw_Temp >> b_Channel) & 1;
+               } else {
+             /*******************/
+                       /* Data size error */
+             /*******************/
+
+                       printk("Buffer size error\n");
+                       i_ReturnValue = -101;
+               }
+       } else {
+          /***************************/
+               /* Channel selection error */
+          /***************************/
+
+               printk("Channel selection error\n");
+               i_ReturnValue = -3;
+       }
+
+       return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3XXX_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|
++----------------------------------------------------------------------------+
+| Input Parameters  : -                                                      |
++----------------------------------------------------------------------------+
+| Output Parameters : data[0] : Port value                                   |
++----------------------------------------------------------------------------+
+| Return Value      :>0: No error                                            |
+|                    ....                                                    |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+int i_APCI3XXX_InsnBitsDigitalInput(struct comedi_device * dev,
+       struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+       INT i_ReturnValue = insn->n;
+       DWORD dw_Temp = 0;
+
+       /************************/
+       /* Test the buffer size */
+       /************************/
+
+       if (insn->n >= 1) {
+               dw_Temp = inl(devpriv->iobase + 32);
+               *data = dw_Temp & 0xf;
+       } else {
+          /*******************/
+               /* Data size error */
+          /*******************/
+
+               printk("Buffer size error\n");
+               i_ReturnValue = -101;
+       }
+
+       return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+|                           DIGITAL OUTPUT SUBDEVICE                         |
++----------------------------------------------------------------------------+
+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3XXX_InsnBitsDigitalOutput                    |
+|                                          (struct comedi_device *dev,              |
+|                                           struct comedi_subdevice *s,             |
+|                                           struct comedi_insn *insn,               |
+|                                           unsigned int *data)                  |
++----------------------------------------------------------------------------+
+| Task              : Write the selected output mask and read the status from|
+|                     all digital output channles                            |
++----------------------------------------------------------------------------+
+| Input Parameters  : dw_ChannelMask = data [0];                             |
+|                     dw_BitMask     = data [1];                             |
++----------------------------------------------------------------------------+
+| Output Parameters : data[1] : All digital output channles states           |
++----------------------------------------------------------------------------+
+| Return Value      : >0  : No error                                         |
+|                    -4   : Channel mask error                               |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+int i_APCI3XXX_InsnBitsDigitalOutput(struct comedi_device * dev,
+       struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+       INT i_ReturnValue = insn->n;
+       BYTE b_ChannelCpt = 0;
+       DWORD dw_ChannelMask = 0;
+       DWORD dw_BitMask = 0;
+       DWORD dw_Status = 0;
+
+       /************************/
+       /* Test the buffer size */
+       /************************/
+
+       if (insn->n >= 2) {
+          /*******************************/
+               /* Get the channe and bit mask */
+          /*******************************/
+
+               dw_ChannelMask = data[0];
+               dw_BitMask = data[1];
+
+          /*************************/
+               /* Test the channel mask */
+          /*************************/
+
+               if ((dw_ChannelMask & 0XFFFFFFF0) == 0) {
+             /*********************************/
+                       /* Test if set/reset any channel */
+             /*********************************/
+
+                       if (dw_ChannelMask & 0xF) {
+                /********************************/
+                               /* Read the digital output port */
+                /********************************/
+
+                               dw_Status = inl(devpriv->iobase + 48);
+
+                               for (b_ChannelCpt = 0; b_ChannelCpt < 4;
+                                       b_ChannelCpt++) {
+                                       if ((dw_ChannelMask >> b_ChannelCpt) &
+                                               1) {
+                                               dw_Status =
+                                                       (dw_Status & (0xF -
+                                                               (1 << b_ChannelCpt))) | (dw_BitMask & (1 << b_ChannelCpt));
+                                       }
+                               }
+
+                               outl(dw_Status, devpriv->iobase + 48);
+                       }
+
+             /********************************/
+                       /* Read the digital output port */
+             /********************************/
+
+                       data[1] = inl(devpriv->iobase + 48);
+               } else {
+             /************************/
+                       /* Config command error */
+             /************************/
+
+                       printk("Channel mask error\n");
+                       i_ReturnValue = -4;
+               }
+       } else {
+          /*******************/
+               /* Data size error */
+          /*******************/
+
+               printk("Buffer size error\n");
+               i_ReturnValue = -101;
+       }
+
+       return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3XXX_InsnWriteDigitalOutput                   |
+|                                          (struct comedi_device *dev,              |
+|                                           struct comedi_subdevice *s,             |
+|                                           struct comedi_insn *insn,               |
+|                                           unsigned int *data)                  |
++----------------------------------------------------------------------------+
+| Task              : Set the state from digital output channel              |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_Channel = CR_CHAN(insn->chanspec)                    |
+|                     b_State   = data [0]                                   |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : >0  : No error                                         |
+|                    -3   : Channel selection error                          |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnWriteDigitalOutput(struct comedi_device * dev,
+       struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+       INT i_ReturnValue = insn->n;
+       BYTE b_Channel = CR_CHAN(insn->chanspec);
+       BYTE b_State = 0;
+       DWORD dw_Status = 0;
+
+       /************************/
+       /* Test the buffer size */
+       /************************/
+
+       if (insn->n >= 1) {
+          /***************************/
+               /* Test the channel number */
+          /***************************/
+
+               if (b_Channel < devpriv->ps_BoardInfo->i_NbrDoChannel) {
+             /*******************/
+                       /* Get the command */
+             /*******************/
+
+                       b_State = (BYTE) data[0];
+
+             /********************************/
+                       /* Read the digital output port */
+             /********************************/
+
+                       dw_Status = inl(devpriv->iobase + 48);
+
+                       dw_Status =
+                               (dw_Status & (0xF -
+                                       (1 << b_Channel))) | ((b_State & 1) <<
+                               b_Channel);
+                       outl(dw_Status, devpriv->iobase + 48);
+               } else {
+             /***************************/
+                       /* Channel selection error */
+             /***************************/
+
+                       printk("Channel selection error\n");
+                       i_ReturnValue = -3;
+               }
+       } else {
+          /*******************/
+               /* Data size error */
+          /*******************/
+
+               printk("Buffer size error\n");
+               i_ReturnValue = -101;
+       }
+
+       return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3XXX_InsnReadDigitalOutput                    |
+|                                          (struct comedi_device *dev,              |
+|                                           struct comedi_subdevice *s,             |
+|                                           struct comedi_insn *insn,               |
+|                                           unsigned int *data)                  |
++----------------------------------------------------------------------------+
+| Task              : Read the state from digital output channel             |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_Channel = CR_CHAN(insn->chanspec)                    |
++----------------------------------------------------------------------------+
+| Output Parameters : b_State   = data [0]                                   |
++----------------------------------------------------------------------------+
+| Return Value      : >0  : No error                                         |
+|                    -3   : Channel selection error                          |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnReadDigitalOutput(struct comedi_device * dev,
+       struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+       INT i_ReturnValue = insn->n;
+       BYTE b_Channel = CR_CHAN(insn->chanspec);
+       DWORD dw_Status = 0;
+
+       /************************/
+       /* Test the buffer size */
+       /************************/
+
+       if (insn->n >= 1) {
+          /***************************/
+               /* Test the channel number */
+          /***************************/
+
+               if (b_Channel < devpriv->ps_BoardInfo->i_NbrDoChannel) {
+             /********************************/
+                       /* Read the digital output port */
+             /********************************/
+
+                       dw_Status = inl(devpriv->iobase + 48);
+
+                       dw_Status = (dw_Status >> b_Channel) & 1;
+                       *data = dw_Status;
+               } else {
+             /***************************/
+                       /* Channel selection error */
+             /***************************/
+
+                       printk("Channel selection error\n");
+                       i_ReturnValue = -3;
+               }
+       } else {
+          /*******************/
+               /* Data size error */
+          /*******************/
+
+               printk("Buffer size error\n");
+               i_ReturnValue = -101;
+       }
+
+       return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI3XXX_Reset(struct comedi_device *dev)               |                                                         +----------------------------------------------------------------------------+
+| Task              :resets all the registers                                |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev                                     |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : -                                                      |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_Reset(struct comedi_device * dev)
+{
+       unsigned char b_Cpt = 0;
+
+       /*************************/
+       /* Disable the interrupt */
+       /*************************/
+
+       disable_irq(dev->irq);
+
+       /****************************/
+       /* Reset the interrupt flag */
+       /****************************/
+
+       devpriv->b_EocEosInterrupt = 0;
+
+       /***************************/
+       /* Clear the start command */
+       /***************************/
+
+       writel(0, (void *)(devpriv->dw_AiBase + 8));
+
+       /*****************************/
+       /* Reset the interrupt flags */
+       /*****************************/
+
+       writel(readl((void *)(devpriv->dw_AiBase + 16)),
+               (void *)(devpriv->dw_AiBase + 16));
+
+       /*****************/
+       /* clear the EOS */
+       /*****************/
+
+       readl((void *)(devpriv->dw_AiBase + 20));
+
+       /******************/
+       /* Clear the FIFO */
+       /******************/
+
+       for (b_Cpt = 0; b_Cpt < 16; b_Cpt++) {
+               readl((void *)(devpriv->dw_AiBase + 28));
+       }
+
+       /************************/
+       /* Enable the interrupt */
+       /************************/
+
+       enable_irq(dev->irq);
+
+       return 0;
+}