/**
@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          Dieselstraße 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     : API APCI1710    | Compiler : gcc                        |
  | Module name : SSI.C           | Version  : 2.96                       |
  +-------------------------------+---------------------------------------+
  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
  +-----------------------------------------------------------------------+
  | Description :   APCI-1710 SSI counter module                          |
  |                                                                       |
  |                                                                       |
  +-----------------------------------------------------------------------+
  |                             UPDATES                                   |
  +-----------------------------------------------------------------------+
  |   Date   |   Author  |          Description of updates                |
  +----------+-----------+------------------------------------------------+
  | 13/05/98 | S. Weber  | SSI digital input / output implementation      |
  |----------|-----------|------------------------------------------------|
  | 22/03/00 | C.Guinot  | 0100/0226 -> 0200/0227                         |
  |          |           | Änderung in InitSSI Funktion                   |
  |          |           | b_SSIProfile >= 2 anstatt b_SSIProfile > 2     |
  |          |           |                                                |
  +-----------------------------------------------------------------------+
  | 08/05/00 | Guinot C  | - 0400/0228 All Function in RING 0             |
  |          |           |   available                                    |
  +-----------------------------------------------------------------------+
*/

/*
+----------------------------------------------------------------------------+
|                               Included files                               |
+----------------------------------------------------------------------------+
*/

#include "APCI1710_Ssi.h"

/*
+----------------------------------------------------------------------------+
| Function Name     : _INT_ i_APCI1710_InitSSI                               |
|                               (unsigned char_    b_BoardHandle,                     |
|                                unsigned char_    b_ModulNbr,                        |
|                                unsigned char_    b_SSIProfile,                      |
|                                unsigned char_    b_PositionTurnLength,              |
|                                unsigned char_    b_TurnCptLength,                   |
|                                unsigned char_    b_PCIInputClock,                   |
|                                ULONG_  ul_SSIOutputClock,                  |
|                                unsigned char_    b_SSICountingMode)                 |
+----------------------------------------------------------------------------+
| Task              : Configure the SSI operating mode from selected module  |
|                     (b_ModulNbr). You must calling this function be for you|
|                     call any other function witch access of SSI.           |
+----------------------------------------------------------------------------+
| Input Parameters  : unsigned char_ b_BoardHandle         : Handle of board APCI-1710|
|                     unsigned char_ b_ModulNbr            : Module number to         |
|                                                   configure (0 to 3)       |
|                     unsigned char_  b_SSIProfile         : Selection from SSI       |
|                                                   profile length (2 to 32).|
|                     unsigned char_  b_PositionTurnLength : Selection from SSI       |
|                                                   position data length     |
|                                                   (1 to 31).               |
|                     unsigned char_  b_TurnCptLength      : Selection from SSI turn  |
|                                                   counter data length      |
|                                                   (1 to 31).               |
|                     unsigned char   b_PCIInputClock      : Selection from PCI bus   |
|                                                   clock                    |
|                                                 - APCI1710_30MHZ :         |
|                                                   The PC have a PCI bus    |
|                                                   clock from 30 MHz        |
|                                                 - APCI1710_33MHZ :         |
|                                                   The PC have a PCI bus    |
|                                                   clock from 33 MHz        |
|                     ULONG_ ul_SSIOutputClock    : Selection from SSI output|
|                                                   clock.                   |
|                                                   From  229 to 5 000 000 Hz|
|                                                   for 30 MHz selection.    |
|                                                   From  252 to 5 000 000 Hz|
|                                                   for 33 MHz selection.    |
|                     unsigned char   b_SSICountingMode    : SSI counting mode        |
|                                                   selection                |
|                                                 - APCI1710_BINARY_MODE :   |
|                                                    Binary counting mode.   |
|                                                 - APCI1710_GRAY_MODE :     |
|                                                    Gray counting mode.

	b_ModulNbr			= CR_AREF(insn->chanspec);
	b_SSIProfile		= (unsigned char) data[0];
	b_PositionTurnLength= (unsigned char) data[1];
	b_TurnCptLength		= (unsigned char) data[2];
	b_PCIInputClock		= (unsigned char) data[3];
	ul_SSIOutputClock	= (unsigned int) data[4];
	b_SSICountingMode	= (unsigned char)  data[5];     |
+----------------------------------------------------------------------------+
| Output Parameters : -                                                      |
+----------------------------------------------------------------------------+
| Return Value      : 0: No error                                            |
|                    -1: The handle parameter of the board is wrong          |
|                    -2: The module parameter is wrong                       |
|                    -3: The module is not a SSI module                      |
|                    -4: The selected SSI profile length is wrong            |
|                    -5: The selected SSI position data length is wrong      |
|                    -6: The selected SSI turn counter data length is wrong  |
|                    -7: The selected PCI input clock is wrong               |
|                    -8: The selected SSI output clock is wrong              |
|                    -9: The selected SSI counting mode parameter is wrong   |
+----------------------------------------------------------------------------+
*/

int i_APCI1710_InsnConfigInitSSI(struct comedi_device *dev, struct comedi_subdevice *s,
	struct comedi_insn *insn, unsigned int *data)
{
	int i_ReturnValue = 0;
	unsigned int ui_TimerValue;
	unsigned char b_ModulNbr, b_SSIProfile, b_PositionTurnLength, b_TurnCptLength,
		b_PCIInputClock, b_SSICountingMode;
	unsigned int ul_SSIOutputClock;

	b_ModulNbr = CR_AREF(insn->chanspec);
	b_SSIProfile = (unsigned char) data[0];
	b_PositionTurnLength = (unsigned char) data[1];
	b_TurnCptLength = (unsigned char) data[2];
	b_PCIInputClock = (unsigned char) data[3];
	ul_SSIOutputClock = (unsigned int) data[4];
	b_SSICountingMode = (unsigned char) data[5];

	i_ReturnValue = insn->n;
	/**************************/
	/* Test the module number */
	/**************************/

	if (b_ModulNbr < 4) {
	   /***********************/
		/* Test if SSI counter */
	   /***********************/

		if ((devpriv->s_BoardInfos.
				dw_MolduleConfiguration[b_ModulNbr] &
				0xFFFF0000UL) == APCI1710_SSI_COUNTER) {
	      /*******************************/
			/* Test the SSI profile length */
	      /*******************************/

			/*  CG 22/03/00 b_SSIProfile >= 2 anstatt b_SSIProfile > 2 */
			if (b_SSIProfile >= 2 && b_SSIProfile < 33) {
		 /*************************************/
				/* Test the SSI position data length */
		 /*************************************/

				if (b_PositionTurnLength > 0
					&& b_PositionTurnLength < 32) {
		    /*****************************************/
					/* Test the SSI turn counter data length */
		    /*****************************************/

					if (b_TurnCptLength > 0
						&& b_TurnCptLength < 32) {
		       /***************************/
						/* Test the profile length */
		       /***************************/

						if ((b_TurnCptLength +
								b_PositionTurnLength)
							<= b_SSIProfile) {
			  /****************************/
							/* Test the PCI input clock */
			  /****************************/

							if (b_PCIInputClock ==
								APCI1710_30MHZ
								||
								b_PCIInputClock
								==
								APCI1710_33MHZ)
							{
			     /*************************/
								/* Test the output clock */
			     /*************************/

								if ((b_PCIInputClock == APCI1710_30MHZ && (ul_SSIOutputClock > 228 && ul_SSIOutputClock <= 5000000UL)) || (b_PCIInputClock == APCI1710_33MHZ && (ul_SSIOutputClock > 251 && ul_SSIOutputClock <= 5000000UL))) {
									if (b_SSICountingMode == APCI1710_BINARY_MODE || b_SSICountingMode == APCI1710_GRAY_MODE) {
				   /**********************/
										/* Save configuration */
				   /**********************/
										devpriv->
											s_ModuleInfo
											[b_ModulNbr].
											s_SSICounterInfo.
											b_SSIProfile
											=
											b_SSIProfile;

										devpriv->
											s_ModuleInfo
											[b_ModulNbr].
											s_SSICounterInfo.
											b_PositionTurnLength
											=
											b_PositionTurnLength;

										devpriv->
											s_ModuleInfo
											[b_ModulNbr].
											s_SSICounterInfo.
											b_TurnCptLength
											=
											b_TurnCptLength;

				   /*********************************/
										/* Initialise the profile length */
				   /*********************************/

										if (b_SSICountingMode == APCI1710_BINARY_MODE) {

											outl(b_SSIProfile + 1, devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr));
										} else {

											outl(b_SSIProfile, devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr));
										}

				   /******************************/
										/* Calculate the output clock */
				   /******************************/

										ui_TimerValue
											=
											(unsigned int)
											(
											((unsigned int) (b_PCIInputClock) * 500000UL) / ul_SSIOutputClock);

				   /************************/
										/* Initialise the timer */
				   /************************/

										outl(ui_TimerValue, devpriv->s_BoardInfos.ui_Address + (64 * b_ModulNbr));

				   /********************************/
										/* Initialise the counting mode */
				   /********************************/

										outl(7 * b_SSICountingMode, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr));

										devpriv->
											s_ModuleInfo
											[b_ModulNbr].
											s_SSICounterInfo.
											b_SSIInit
											=
											1;
									} else {
				   /*****************************************************/
										/* The selected SSI counting mode parameter is wrong */
				   /*****************************************************/

										DPRINTK("The selected SSI counting mode parameter is wrong\n");
										i_ReturnValue
											=
											-9;
									}
								} else {
				/******************************************/
									/* The selected SSI output clock is wrong */
				/******************************************/

									DPRINTK("The selected SSI output clock is wrong\n");
									i_ReturnValue
										=
										-8;
								}
							} else {
			     /*****************************************/
								/* The selected PCI input clock is wrong */
			     /*****************************************/

								DPRINTK("The selected PCI input clock is wrong\n");
								i_ReturnValue =
									-7;
							}
						} else {
			  /********************************************/
							/* The selected SSI profile length is wrong */
			  /********************************************/

							DPRINTK("The selected SSI profile length is wrong\n");
							i_ReturnValue = -4;
						}
					} else {
		       /******************************************************/
						/* The selected SSI turn counter data length is wrong */
		       /******************************************************/

						DPRINTK("The selected SSI turn counter data length is wrong\n");
						i_ReturnValue = -6;
					}
				} else {
		    /**************************************************/
					/* The selected SSI position data length is wrong */
		    /**************************************************/

					DPRINTK("The selected SSI position data length is wrong\n");
					i_ReturnValue = -5;
				}
			} else {
		 /********************************************/
				/* The selected SSI profile length is wrong */
		 /********************************************/

				DPRINTK("The selected SSI profile length is wrong\n");
				i_ReturnValue = -4;
			}
		} else {
	      /**********************************/
			/* The module is not a SSI module */
	      /**********************************/

			DPRINTK("The module is not a SSI module\n");
			i_ReturnValue = -3;
		}
	} else {
	   /***********************/
		/* Module number error */
	   /***********************/

		DPRINTK("Module number error\n");
		i_ReturnValue = -2;
	}

	return i_ReturnValue;
}

/*
+----------------------------------------------------------------------------+
| Function Name     : _INT_  i_APCI1710_Read1SSIValue                        |
|                               (unsigned char_     b_BoardHandle,                    |
|                                unsigned char_     b_ModulNbr,                       |
|                                unsigned char_     b_SelectedSSI,                    |
|                                PULONG_ pul_Position,                       |
|                                PULONG_ pul_TurnCpt)
 int i_APCI1710_ReadSSIValue(struct comedi_device *dev,struct comedi_subdevice *s,
	struct comedi_insn *insn,unsigned int *data)                       |
+----------------------------------------------------------------------------+
| Task              :


						Read the selected SSI counter (b_SelectedSSI) from     |
|                     selected module (b_ModulNbr).
						or Read all SSI counter (b_SelectedSSI) from              |
|                     selected module (b_ModulNbr).                            |
+----------------------------------------------------------------------------+
| Input Parameters  : unsigned char_ b_BoardHandle         : Handle of board APCI-1710|
|                     unsigned char_ b_ModulNbr            : Module number to         |
|                                                   configure (0 to 3)       |
|                     unsigned char_ b_SelectedSSI         : Selection from SSI       |
|                                                   counter (0 to 2)

    b_ModulNbr		=   (unsigned char) CR_AREF(insn->chanspec);
	b_SelectedSSI	=	(unsigned char) CR_CHAN(insn->chanspec); (in case of single ssi)
	b_ReadType		=	(unsigned char) CR_RANGE(insn->chanspec);
|
+----------------------------------------------------------------------------+
| Output Parameters : PULONG_  pul_Position       : SSI position in the turn |
|                     PULONG_  pul_TurnCpt        : Number of turns

pul_Position	=	(unsigned int *) &data[0];
	pul_TurnCpt		=	(unsigned int *) &data[1];         |
+----------------------------------------------------------------------------+
| Return Value      : 0: No error                                            |
|                    -1: The handle parameter of the board is wrong          |
|                    -2: The module parameter is wrong                       |
|                    -3: The module is not a SSI module                      |
|                    -4: SSI not initialised see function                    |
|                        "i_APCI1710_InitSSI"                                |
|                    -5: The selected SSI is wrong                           |
+----------------------------------------------------------------------------+
*/

int i_APCI1710_InsnReadSSIValue(struct comedi_device *dev, struct comedi_subdevice *s,
	struct comedi_insn *insn, unsigned int *data)
{
	int i_ReturnValue = 0;
	unsigned char b_Cpt;
	unsigned char b_Length;
	unsigned char b_Schift;
	unsigned char b_SSICpt;
	unsigned int dw_And;
	unsigned int dw_And1;
	unsigned int dw_And2;
	unsigned int dw_StatusReg;
	unsigned int dw_CounterValue;
	unsigned char b_ModulNbr;
	unsigned char b_SelectedSSI;
	unsigned char b_ReadType;
	unsigned int *pul_Position;
	unsigned int *pul_TurnCpt;
	unsigned int *pul_Position1;
	unsigned int *pul_TurnCpt1;

	i_ReturnValue = insn->n;
	pul_Position1 = (unsigned int *) &data[0];
/* For Read1 */
	pul_TurnCpt1 = (unsigned int *) &data[1];
/* For Read all */
	pul_Position = (unsigned int *) &data[0];	/* 0-2 */
	pul_TurnCpt = (unsigned int *) &data[3];	/* 3-5 */
	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
	b_SelectedSSI = (unsigned char) CR_CHAN(insn->chanspec);
	b_ReadType = (unsigned char) CR_RANGE(insn->chanspec);

	/**************************/
	/* Test the module number */
	/**************************/

	if (b_ModulNbr < 4) {
	   /***********************/
		/* Test if SSI counter */
	   /***********************/

		if ((devpriv->s_BoardInfos.
				dw_MolduleConfiguration[b_ModulNbr] &
				0xFFFF0000UL) == APCI1710_SSI_COUNTER) {
	      /***************************/
			/* Test if SSI initialised */
	      /***************************/

			if (devpriv->s_ModuleInfo[b_ModulNbr].
				s_SSICounterInfo.b_SSIInit == 1) {

				switch (b_ReadType) {

				case APCI1710_SSI_READ1VALUE:
		 /****************************************/
					/* Test the selected SSI counter number */
		 /****************************************/

					if (b_SelectedSSI < 3) {
		    /************************/
						/* Start the conversion */
		    /************************/

						outl(0, devpriv->s_BoardInfos.
							ui_Address + 8 +
							(64 * b_ModulNbr));

						do {
		       /*******************/
							/* Read the status */
		       /*******************/

							dw_StatusReg =
								inl(devpriv->
								s_BoardInfos.
								ui_Address +
								(64 * b_ModulNbr));
						} while ((dw_StatusReg & 0x1)
							 != 0);

		    /******************************/
						/* Read the SSI counter value */
		    /******************************/

						dw_CounterValue =
							inl(devpriv->
							s_BoardInfos.
							ui_Address + 4 +
							(b_SelectedSSI * 4) +
							(64 * b_ModulNbr));

						b_Length =
							devpriv->
							s_ModuleInfo
							[b_ModulNbr].
							s_SSICounterInfo.
							b_SSIProfile / 2;

						if ((b_Length * 2) !=
							devpriv->
							s_ModuleInfo
							[b_ModulNbr].
							s_SSICounterInfo.
							b_SSIProfile) {
							b_Length++;
						}

						b_Schift =
							b_Length -
							devpriv->
							s_ModuleInfo
							[b_ModulNbr].
							s_SSICounterInfo.
							b_PositionTurnLength;

						*pul_Position1 =
							dw_CounterValue >>
							b_Schift;

						dw_And = 1;

						for (b_Cpt = 0;
							b_Cpt <
							devpriv->
							s_ModuleInfo
							[b_ModulNbr].
							s_SSICounterInfo.
							b_PositionTurnLength;
							b_Cpt++) {
							dw_And = dw_And * 2;
						}

						*pul_Position1 =
							*pul_Position1 &
							((dw_And) - 1);

						*pul_TurnCpt1 =
							dw_CounterValue >>
							b_Length;

						dw_And = 1;

						for (b_Cpt = 0;
							b_Cpt <
							devpriv->
							s_ModuleInfo
							[b_ModulNbr].
							s_SSICounterInfo.
							b_TurnCptLength;
							b_Cpt++) {
							dw_And = dw_And * 2;
						}

						*pul_TurnCpt1 =
							*pul_TurnCpt1 &
							((dw_And) - 1);
					} else {
		    /*****************************/
						/* The selected SSI is wrong */
		    /*****************************/

						DPRINTK("The selected SSI is wrong\n");
						i_ReturnValue = -5;
					}
					break;

				case APCI1710_SSI_READALLVALUE:
					dw_And1 = 1;

					for (b_Cpt = 0;
						b_Cpt <
						devpriv->
						s_ModuleInfo[b_ModulNbr].
						s_SSICounterInfo.
						b_PositionTurnLength; b_Cpt++) {
						dw_And1 = dw_And1 * 2;
					}

					dw_And2 = 1;

					for (b_Cpt = 0;
						b_Cpt <
						devpriv->
						s_ModuleInfo[b_ModulNbr].
						s_SSICounterInfo.
						b_TurnCptLength; b_Cpt++) {
						dw_And2 = dw_And2 * 2;
					}

		 /************************/
					/* Start the conversion */
		 /************************/

					outl(0, devpriv->s_BoardInfos.
						ui_Address + 8 +
						(64 * b_ModulNbr));

					do {
		    /*******************/
						/* Read the status */
		    /*******************/

						dw_StatusReg =
							inl(devpriv->
							s_BoardInfos.
							ui_Address +
							(64 * b_ModulNbr));
					} while ((dw_StatusReg & 0x1) != 0);

					for (b_SSICpt = 0; b_SSICpt < 3;
						b_SSICpt++) {
		    /******************************/
						/* Read the SSI counter value */
		    /******************************/

						dw_CounterValue =
							inl(devpriv->
							s_BoardInfos.
							ui_Address + 4 +
							(b_SSICpt * 4) +
							(64 * b_ModulNbr));

						b_Length =
							devpriv->
							s_ModuleInfo
							[b_ModulNbr].
							s_SSICounterInfo.
							b_SSIProfile / 2;

						if ((b_Length * 2) !=
							devpriv->
							s_ModuleInfo
							[b_ModulNbr].
							s_SSICounterInfo.
							b_SSIProfile) {
							b_Length++;
						}

						b_Schift =
							b_Length -
							devpriv->
							s_ModuleInfo
							[b_ModulNbr].
							s_SSICounterInfo.
							b_PositionTurnLength;

						pul_Position[b_SSICpt] =
							dw_CounterValue >>
							b_Schift;
						pul_Position[b_SSICpt] =
							pul_Position[b_SSICpt] &
							((dw_And1) - 1);

						pul_TurnCpt[b_SSICpt] =
							dw_CounterValue >>
							b_Length;
						pul_TurnCpt[b_SSICpt] =
							pul_TurnCpt[b_SSICpt] &
							((dw_And2) - 1);
					}
					break;

				default:
					printk("Read Type Inputs Wrong\n");

				}	/*  switch  ending */

			} else {
		 /***********************/
				/* SSI not initialised */
		 /***********************/

				DPRINTK("SSI not initialised\n");
				i_ReturnValue = -4;
			}
		} else {
	      /**********************************/
			/* The module is not a SSI module */
	      /**********************************/

			DPRINTK("The module is not a SSI module\n");
			i_ReturnValue = -3;

		}
	} else {
	   /***********************/
		/* Module number error */
	   /***********************/

		DPRINTK("Module number error\n");
		i_ReturnValue = -2;
	}

	return i_ReturnValue;
}

/*
+----------------------------------------------------------------------------+
| Function Name     : _INT_   i_APCI1710_ReadSSI1DigitalInput                |
|                                       (unsigned char_     b_BoardHandle,            |
|                                        unsigned char_     b_ModulNbr,               |
|                                        unsigned char_     b_InputChannel,           |
|                                        unsigned char *_   pb_ChannelStatus)          |
+----------------------------------------------------------------------------+
| Task              :
					(0) Set the digital output from selected SSI moule         |
|                     (b_ModuleNbr) ON
                    (1) Set the digital output from selected SSI moule         |
|                     (b_ModuleNbr) OFF
					(2)Read the status from selected SSI digital input        |
|                     (b_InputChannel)
                    (3)Read the status from all SSI digital inputs from       |
|                     selected SSI module (b_ModulNbr)                   |
+----------------------------------------------------------------------------+
| Input Parameters  : unsigned char_ b_BoardHandle         : Handle of board APCI-1710|
|                     unsigned char_ b_ModulNbr    CR_AREF        : Module number to         |
|                                                   configure (0 to 3)       |
|                     unsigned char_ b_InputChannel CR_CHAN       : Selection from digital   |
|                        data[0] which IOTYPE                           input ( 0 to 2)          |
+----------------------------------------------------------------------------+
| Output Parameters : unsigned char *_  pb_ChannelStatus    : Digital input channel    |
|                                 data[0]                  status                   |
|                                                   0 : Channle is not active|
|                                                   1 : Channle is active    |
+----------------------------------------------------------------------------+
| Return Value      : 0: No error                                            |
|                    -1: The handle parameter of the board is wrong          |
|                    -2: The module parameter is wrong                       |
|                    -3: The module is not a SSI module                      |
|                    -4: The selected SSI digital input is wrong             |
+----------------------------------------------------------------------------+
*/

int i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device *dev, struct comedi_subdevice *s,
	struct comedi_insn *insn, unsigned int *data)
{
	int i_ReturnValue = 0;
	unsigned int dw_StatusReg;
	unsigned char b_ModulNbr;
	unsigned char b_InputChannel;
	unsigned char *pb_ChannelStatus;
	unsigned char *pb_InputStatus;
	unsigned char b_IOType;
	i_ReturnValue = insn->n;
	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
	b_IOType = (unsigned char) data[0];

	/**************************/
	/* Test the module number */
	/**************************/

	if (b_ModulNbr < 4) {
	   /***********************/
		/* Test if SSI counter */
	   /***********************/

		if ((devpriv->s_BoardInfos.
				dw_MolduleConfiguration[b_ModulNbr] &
				0xFFFF0000UL) == APCI1710_SSI_COUNTER) {
			switch (b_IOType) {
			case APCI1710_SSI_SET_CHANNELON:
					/*****************************/
				/* Set the digital output ON */
					/*****************************/

				outl(1, devpriv->s_BoardInfos.ui_Address + 16 +
					(64 * b_ModulNbr));
				break;

			case APCI1710_SSI_SET_CHANNELOFF:
					/******************************/
				/* Set the digital output OFF */
					/******************************/

				outl(0, devpriv->s_BoardInfos.ui_Address + 16 +
					(64 * b_ModulNbr));
				break;

			case APCI1710_SSI_READ_1CHANNEL:
				   /******************************************/
				/* Test the digital imnput channel number */
				   /******************************************/

				b_InputChannel = (unsigned char) CR_CHAN(insn->chanspec);
				pb_ChannelStatus = (unsigned char *) &data[0];

				if (b_InputChannel <= 2) {
					/**************************/
					/* Read all digital input */
					/**************************/

					dw_StatusReg =
						inl(devpriv->s_BoardInfos.
						ui_Address + (64 * b_ModulNbr));
					*pb_ChannelStatus =
						(unsigned char) (((~dw_StatusReg) >> (4 +
								b_InputChannel))
						& 1);
				} else {
					/********************************/
					/* Selected digital input error */
					/********************************/

					DPRINTK("Selected digital input error\n");
					i_ReturnValue = -4;
				}
				break;

			case APCI1710_SSI_READ_ALLCHANNEL:
					/**************************/
				/* Read all digital input */
					/**************************/
				pb_InputStatus = (unsigned char *) &data[0];

				dw_StatusReg =
					inl(devpriv->s_BoardInfos.ui_Address +
					(64 * b_ModulNbr));
				*pb_InputStatus =
					(unsigned char) (((~dw_StatusReg) >> 4) & 7);
				break;

			default:
				printk("IO type wrong\n");

			}	/* switch end */
		} else {
	      /**********************************/
			/* The module is not a SSI module */
	      /**********************************/

			DPRINTK("The module is not a SSI module\n");
			i_ReturnValue = -3;
		}
	} else {
	   /***********************/
		/* Module number error */
	   /***********************/

		DPRINTK("Module number error\n");
		i_ReturnValue = -2;
	}

	return i_ReturnValue;
}
