Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 92eb3795 authored by H Hartley Sweeten's avatar H Hartley Sweeten Committed by Greg Kroah-Hartman
Browse files

staging: comedi: addi_apci_16xx: rewrite low-level support code



The current low-level support code in hwdrv_apci16xx.c is seriously
broken. Besides that, it's overly complicated.

Rewrite, and simplify, the low-level code so it complies with the
comedi API.

Signed-off-by: default avatarH Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 26b39899
Loading
Loading
Loading
Loading
+0 −542
Original line number Diff line number Diff line
/**
@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 should 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 APCI1648    | Compiler : gcc                        |
  | Module name : TTL.C           | Version  : 2.96                       |
  +-------------------------------+---------------------------------------+
  | Project manager: S. Weber     | Date     :  25/05/2005                |
  +-----------------------------------------------------------------------+
  | Description :   APCI-16XX TTL I/O module                              |
  |                                                                       |
  |                                                                       |
  +-----------------------------------------------------------------------+
  |                             UPDATES                                   |
  +-----------------------------------------------------------------------+
  |   Date   |   Author  |          Description of updates                |
  +----------+-----------+------------------------------------------------+
  |25.05.2005| S.Weber   | Creation                                       |
  |          |           |                                                |
  +-----------------------------------------------------------------------+
*/

#define APCI16XX_TTL_INIT		0
#define APCI16XX_TTL_INITDIRECTION	1
#define APCI16XX_TTL_OUTPUTMEMORY	2

#define APCI16XX_TTL_READCHANNEL	0
#define APCI16XX_TTL_READPORT		1

#define APCI16XX_TTL_WRITECHANNEL_ON	0
#define APCI16XX_TTL_WRITECHANNEL_OFF	1
#define APCI16XX_TTL_WRITEPORT_ON	2
#define APCI16XX_TTL_WRITEPORT_OFF	3

#define APCI16XX_TTL_READ_ALL_INPUTS	0
#define APCI16XX_TTL_READ_ALL_OUTPUTS	1

/*
+----------------------------------------------------------------------------+
| Function Name     : int   i_APCI16XX_InsnConfigInitTTLIO                   |
|                          (struct comedi_device    *dev,                           |
|                           struct comedi_subdevice *s,                             |
|                           struct comedi_insn      *insn,                          |
|                           unsigned int         *data)                          |
+----------------------------------------------------------------------------+
| Task           APCI16XX_TTL_INIT (using defaults)   :                      |
|                Configure the TTL I/O operating mode from all ports         |
|                You must calling this function be                           |
|                for you call any other function witch access of TTL.        |
|                APCI16XX_TTL_INITDIRECTION(user inputs for direction)       |
+----------------------------------------------------------------------------+
| Input Parameters  : b_InitType    = (unsigned char) data[0];                        |
|                     b_Port0Mode   = (unsigned char) data[1];                        |
|                     b_Port1Mode   = (unsigned char) data[2];                        |
|                     b_Port2Mode   = (unsigned char) data[3];                        |
|                     b_Port3Mode   = (unsigned char) data[4];                        |
|                     ........                                               |
+----------------------------------------------------------------------------+
| Output Parameters : -                                                      |
+----------------------------------------------------------------------------+
| Return Value      :>0: No error                                            |
|                    -1: Port 0 mode selection is wrong                      |
|                    -2: Port 1 mode selection is wrong                      |
|                    -3: Port 2 mode selection is wrong                      |
|                    -4: Port 3 mode selection is wrong                      |
|                    -X: Port X-1 mode selection is wrong                    |
|                    ....                                                    |
|                    -100 : Config command error                             |
|                    -101 : Data size error                                  |
+----------------------------------------------------------------------------+
*/
static int i_APCI16XX_InsnConfigInitTTLIO(struct comedi_device *dev,
					  struct comedi_subdevice *s,
					  struct comedi_insn *insn,
					  unsigned int *data)
{
	struct addi_private *devpriv = dev->private;
	int i_ReturnValue = insn->n;
	unsigned char b_Command = 0;
	unsigned char b_Cpt = 0;
	unsigned char b_NumberOfPort = s->n_chan / 8;

	/* Test the buffer size */
	if (insn->n >= 1) {
		/* Get the command */
		b_Command = (unsigned char) data[0];

		/* Test the command */
		if ((b_Command == APCI16XX_TTL_INIT) ||
			(b_Command == APCI16XX_TTL_INITDIRECTION) ||
			(b_Command == APCI16XX_TTL_OUTPUTMEMORY)) {
			/* Test the initialisation buffer size */
			if ((b_Command == APCI16XX_TTL_INITDIRECTION)
				&& ((unsigned char) (insn->n - 1) != b_NumberOfPort)) {
				printk("\nBuffer size error");
				i_ReturnValue = -101;
			}

			if ((b_Command == APCI16XX_TTL_OUTPUTMEMORY)
				&& ((unsigned char) (insn->n) != 2)) {
				printk("\nBuffer size error");
				i_ReturnValue = -101;
			}
		} else {
			printk("\nCommand selection error");
			i_ReturnValue = -100;
		}
	} else {
		printk("\nBuffer size error");
		i_ReturnValue = -101;
	}

	/* Test if no error occur and APCI16XX_TTL_INITDIRECTION command selected */
	if ((i_ReturnValue >= 0) && (b_Command == APCI16XX_TTL_INITDIRECTION)) {
		memset(devpriv->ul_TTLPortConfiguration, 0,
			sizeof(devpriv->ul_TTLPortConfiguration));

		/* Test the port direction selection */
		for (b_Cpt = 1;
			(b_Cpt <= b_NumberOfPort) && (i_ReturnValue >= 0);
			b_Cpt++) {
			/* Test the direction */
			if ((data[b_Cpt] != 0) && (data[b_Cpt] != 0xFF)) {
				printk("\nPort %d direction selection error",
					(int) b_Cpt);
				i_ReturnValue = -(int) b_Cpt;
			}

			/* Save the configuration */
			devpriv->ul_TTLPortConfiguration[(b_Cpt - 1) / 4] =
				devpriv->ul_TTLPortConfiguration[(b_Cpt -
					1) / 4] | (data[b_Cpt] << (8 * ((b_Cpt -
							1) % 4)));
		}
	}

	/* Test if no error occur */
	if (i_ReturnValue >= 0) {
		/* Test if TTL port initilaisation */
		if ((b_Command == APCI16XX_TTL_INIT)
			|| (b_Command == APCI16XX_TTL_INITDIRECTION)) {
			/* Set all port configuration */
			for (b_Cpt = 0; b_Cpt <= b_NumberOfPort; b_Cpt++) {
				if ((b_Cpt % 4) == 0) {
					/* Set the configuration */
					outl(devpriv->
						ul_TTLPortConfiguration[b_Cpt /
							4],
						dev->iobase + 32 + b_Cpt);
				}
			}
		}
	}

	/* Test if output memory initialisation command */
	if (b_Command == APCI16XX_TTL_OUTPUTMEMORY) {
		if (data[1]) {
			devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE;
		} else {
			devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE;
		}
	}

	return i_ReturnValue;
}

/*
+----------------------------------------------------------------------------+
| Function Name     : int     i_APCI16XX_InsnBitsReadTTLIO                   |
|                          (struct comedi_device    *dev,                           |
|                           struct comedi_subdevice *s,                             |
|                           struct comedi_insn      *insn,                          |
|                           unsigned int         *data)                          |
+----------------------------------------------------------------------------+
| Task              : Read the status from selected TTL digital input        |
|                     (b_InputChannel)                                       |
+----------------------------------------------------------------------------+
| Task              : Read the status from digital input port                |
|                     (b_SelectedPort)                                       |
+----------------------------------------------------------------------------+
| Input Parameters  :                                                        |
|              APCI16XX_TTL_READCHANNEL                                      |
|                    b_SelectedPort= CR_RANGE(insn->chanspec);               |
|                    b_InputChannel= CR_CHAN(insn->chanspec);                |
|                    b_ReadType	  = (unsigned char) data[0];                          |
|                                                                            |
|              APCI16XX_TTL_READPORT                                         |
|                    b_SelectedPort= CR_RANGE(insn->chanspec);               |
|                    b_ReadType	  = (unsigned char) data[0];                          |
+----------------------------------------------------------------------------+
| Output Parameters : data[0]    0 : Channle is not active                   |
|                                1 : Channle is active                       |
+----------------------------------------------------------------------------+
| Return Value      : >0  : No error                                         |
|                    -100 : Config command error                             |
|                    -101 : Data size error                                  |
|                    -102 : The selected TTL input port is wrong             |
|                    -103 : The selected TTL digital input is wrong          |
+----------------------------------------------------------------------------+
*/
static int i_APCI16XX_InsnBitsReadTTLIO(struct comedi_device *dev,
					struct comedi_subdevice *s,
					struct comedi_insn *insn,
					unsigned int *data)
{
	struct addi_private *devpriv = dev->private;
	int i_ReturnValue = insn->n;
	unsigned char b_Command = 0;
	unsigned char b_NumberOfPort = s->n_chan / 8;
	unsigned char b_SelectedPort = CR_RANGE(insn->chanspec);
	unsigned char b_InputChannel = CR_CHAN(insn->chanspec);
	unsigned char *pb_Status;
	unsigned int dw_Status;

	/* Test the buffer size */
	if (insn->n >= 1) {
		/* Get the command */
		b_Command = (unsigned char) data[0];

		/* Test the command */
		if ((b_Command == APCI16XX_TTL_READCHANNEL)
			|| (b_Command == APCI16XX_TTL_READPORT)) {
			/* Test the selected port */
			if (b_SelectedPort < b_NumberOfPort) {
				/* Test if input port */
				if (((devpriv->ul_TTLPortConfiguration
							[b_SelectedPort /
								4] >> (8 *
								(b_SelectedPort
									%
									4))) &
						0xFF) == 0) {
					/* Test the channel number */
					if ((b_Command ==
							APCI16XX_TTL_READCHANNEL)
						&& (b_InputChannel > 7)) {
						printk("\nChannel selection error");
						i_ReturnValue = -103;
					}
				} else {
					printk("\nPort selection error");
					i_ReturnValue = -102;
				}
			} else {
				printk("\nPort selection error");
				i_ReturnValue = -102;
			}
		} else {
			printk("\nCommand selection error");
			i_ReturnValue = -100;
		}
	} else {
		printk("\nBuffer size error");
		i_ReturnValue = -101;
	}

	/* Test if no error occur */
	if (i_ReturnValue >= 0) {
		pb_Status = (unsigned char *) &data[0];

		/* Get the digital inpu status */
		dw_Status =
			inl(dev->iobase + 8 + ((b_SelectedPort / 4) * 4));
		dw_Status = (dw_Status >> (8 * (b_SelectedPort % 4))) & 0xFF;

		/* Save the port value */
		*pb_Status = (unsigned char) dw_Status;

		/* Test if read channel status command */
		if (b_Command == APCI16XX_TTL_READCHANNEL) {
			*pb_Status = (*pb_Status >> b_InputChannel) & 1;
		}
	}

	return i_ReturnValue;
}

/*
+----------------------------------------------------------------------------+
| Function Name     : int i_APCI16XX_InsnReadTTLIOAllPortValue               |
|                          (struct comedi_device    *dev,                           |
|                           struct comedi_subdevice *s,                             |
|                           struct comedi_insn      *insn,                          |
|                           unsigned int         *data)                          |
+----------------------------------------------------------------------------+
| Task              : Read the status from all digital input ports           |
+----------------------------------------------------------------------------+
| Input Parameters  : -                                                      |
+----------------------------------------------------------------------------+
| Output Parameters : data[0] : Port 0 to 3 data                             |
|                     data[1] : Port 4 to 7 data                             |
|                     ....                                                   |
+----------------------------------------------------------------------------+
| Return Value      : 0: No error                                            |
|                    -100 : Read command error                               |
|                    -101 : Data size error                                  |
+----------------------------------------------------------------------------+
*/
static int i_APCI16XX_InsnReadTTLIOAllPortValue(struct comedi_device *dev,
						struct comedi_subdevice *s,
						struct comedi_insn *insn,
						unsigned int *data)
{
	struct addi_private *devpriv = dev->private;
	unsigned char b_Command = (unsigned char) CR_AREF(insn->chanspec);
	int i_ReturnValue = insn->n;
	unsigned char b_Cpt = 0;
	unsigned char b_NumberOfPort = 0;
	unsigned int *pls_ReadData = data;

	/* Test the command */
	if ((b_Command == APCI16XX_TTL_READ_ALL_INPUTS)
		|| (b_Command == APCI16XX_TTL_READ_ALL_OUTPUTS)) {
		/* Get the number of 32-Bit ports */
		b_NumberOfPort = s->n_chan / 32;
		if ((b_NumberOfPort * 32) < s->n_chan)
			b_NumberOfPort = b_NumberOfPort + 1;

		/* Test the buffer size */
		if (insn->n >= b_NumberOfPort) {
			if (b_Command == APCI16XX_TTL_READ_ALL_INPUTS) {
				/* Read all digital input */
				for (b_Cpt = 0; b_Cpt < b_NumberOfPort; b_Cpt++) {
					/* Read the 32-Bit port */
					pls_ReadData[b_Cpt] =
						inl(dev->iobase + 8 +
						(b_Cpt * 4));

					/* Mask all channels used als outputs */
					pls_ReadData[b_Cpt] =
						pls_ReadData[b_Cpt] &
						(~devpriv->
						ul_TTLPortConfiguration[b_Cpt]);
				}
			} else {
				/* Read all digital outputs */
				for (b_Cpt = 0; b_Cpt < b_NumberOfPort; b_Cpt++) {
					/* Read the 32-Bit port */
					pls_ReadData[b_Cpt] =
						inl(dev->iobase + 20 +
						(b_Cpt * 4));

					/* Mask all channels used als outputs */
					pls_ReadData[b_Cpt] =
						pls_ReadData[b_Cpt] & devpriv->
						ul_TTLPortConfiguration[b_Cpt];
				}
			}
		} else {
			printk("\nBuffer size error");
			i_ReturnValue = -101;
		}
	} else {
		printk("\nCommand selection error");
		i_ReturnValue = -100;
	}

	return i_ReturnValue;
}

/*
+----------------------------------------------------------------------------+
| Function Name     : int     i_APCI16XX_InsnBitsWriteTTLIO                  |
|                          (struct comedi_device    *dev,                           |
|                           struct comedi_subdevice *s,                             |
|                           struct comedi_insn      *insn,                          |
|                           unsigned int         *data)                          |
+----------------------------------------------------------------------------+
| Task              : Set the state from selected TTL digital output         |
|                     (b_OutputChannel)                                      |
+----------------------------------------------------------------------------+
| Task              : Set the state from digital output port                 |
|                     (b_SelectedPort)                                       |
+----------------------------------------------------------------------------+
| Input Parameters  :                                                        |
|              APCI16XX_TTL_WRITECHANNEL_ON | APCI16XX_TTL_WRITECHANNEL_OFF  |
|                    b_SelectedPort = CR_RANGE(insn->chanspec);              |
|                    b_OutputChannel= CR_CHAN(insn->chanspec);               |
|                    b_Command      = (unsigned char) data[0];                        |
|                                                                            |
|              APCI16XX_TTL_WRITEPORT_ON | APCI16XX_TTL_WRITEPORT_OFF        |
|                    b_SelectedPort = CR_RANGE(insn->chanspec);              |
|                    b_Command      = (unsigned char) data[0];                        |
+----------------------------------------------------------------------------+
| Output Parameters : data[0] : TTL output port 0 to 3 data                  |
|                     data[1] : TTL output port 4 to 7 data                  |
|                     ....                                                   |
+----------------------------------------------------------------------------+
| Return Value      : >0  : No error                                         |
|                    -100 : Command error                                    |
|                    -101 : Data size error                                  |
|                    -102 : The selected TTL output port is wrong            |
|                    -103 : The selected TTL digital output is wrong         |
|                    -104 : Output memory disabled                           |
+----------------------------------------------------------------------------+
*/
static int i_APCI16XX_InsnBitsWriteTTLIO(struct comedi_device *dev,
					 struct comedi_subdevice *s,
					 struct comedi_insn *insn,
					 unsigned int *data)
{
	struct addi_private *devpriv = dev->private;
	int i_ReturnValue = insn->n;
	unsigned char b_Command = 0;
	unsigned char b_NumberOfPort = s->n_chan / 8;
	unsigned char b_SelectedPort = CR_RANGE(insn->chanspec);
	unsigned char b_OutputChannel = CR_CHAN(insn->chanspec);
	unsigned int dw_Status = 0;

	/* Test the buffer size */
	if (insn->n >= 1) {
		/* Get the command */
		b_Command = (unsigned char) data[0];

		/* Test the command */
		if ((b_Command == APCI16XX_TTL_WRITECHANNEL_ON) ||
			(b_Command == APCI16XX_TTL_WRITEPORT_ON) ||
			(b_Command == APCI16XX_TTL_WRITECHANNEL_OFF) ||
			(b_Command == APCI16XX_TTL_WRITEPORT_OFF)) {
			/* Test the selected port */
			if (b_SelectedPort < b_NumberOfPort) {
				/* Test if output port */
				if (((devpriv->ul_TTLPortConfiguration
							[b_SelectedPort /
								4] >> (8 *
								(b_SelectedPort
									%
									4))) &
						0xFF) == 0xFF) {
					/* Test the channel number */
					if (((b_Command == APCI16XX_TTL_WRITECHANNEL_ON) || (b_Command == APCI16XX_TTL_WRITECHANNEL_OFF)) && (b_OutputChannel > 7)) {
						printk("\nChannel selection error");
						i_ReturnValue = -103;
					}

					if (((b_Command == APCI16XX_TTL_WRITECHANNEL_OFF) || (b_Command == APCI16XX_TTL_WRITEPORT_OFF)) && (devpriv->b_OutputMemoryStatus == ADDIDATA_DISABLE)) {
						printk("\nOutput memory disabled");
						i_ReturnValue = -104;
					}

					/* Test the buffer size */
					if (((b_Command == APCI16XX_TTL_WRITEPORT_ON) || (b_Command == APCI16XX_TTL_WRITEPORT_OFF)) && (insn->n < 2)) {
						printk("\nBuffer size error");
						i_ReturnValue = -101;
					}
				} else {
					printk("\nPort selection error %lX",
						(unsigned long)devpriv->
						ul_TTLPortConfiguration[0]);
					i_ReturnValue = -102;
				}
			} else {
				printk("\nPort selection error %d %d",
					b_SelectedPort, b_NumberOfPort);
				i_ReturnValue = -102;
			}
		} else {
			printk("\nCommand selection error");
			i_ReturnValue = -100;
		}
	} else {
		printk("\nBuffer size error");
		i_ReturnValue = -101;
	}

	/* Test if no error occur */
	if (i_ReturnValue >= 0) {
		/* Get the digital output state */
		dw_Status =
			inl(dev->iobase + 20 + ((b_SelectedPort / 4) * 4));

		/* Test if output memory not used */
		if (devpriv->b_OutputMemoryStatus == ADDIDATA_DISABLE) {
			/* Clear the selected port value */
			dw_Status =
				dw_Status & (0xFFFFFFFFUL -
				(0xFFUL << (8 * (b_SelectedPort % 4))));
		}

		/* Test if setting channel ON */
		if (b_Command == APCI16XX_TTL_WRITECHANNEL_ON) {
			dw_Status =
				dw_Status | (1UL << ((8 * (b_SelectedPort %
							4)) + b_OutputChannel));
		}

		/* Test if setting port ON */
		if (b_Command == APCI16XX_TTL_WRITEPORT_ON) {
			dw_Status =
				dw_Status | ((data[1] & 0xFF) << (8 *
					(b_SelectedPort % 4)));
		}

		/* Test if setting channel OFF */
		if (b_Command == APCI16XX_TTL_WRITECHANNEL_OFF) {
			dw_Status =
				dw_Status & (0xFFFFFFFFUL -
				(1UL << ((8 * (b_SelectedPort % 4)) +
						b_OutputChannel)));
		}

		/* Test if setting port OFF */
		if (b_Command == APCI16XX_TTL_WRITEPORT_OFF) {
			dw_Status =
				dw_Status & (0xFFFFFFFFUL -
				((data[1] & 0xFF) << (8 * (b_SelectedPort %
							4))));
		}

		outl(dw_Status,
			dev->iobase + 20 + ((b_SelectedPort / 4) * 4));
	}

	return i_ReturnValue;
}
+103 −25

File changed.

Preview size limit exceeded, changes collapsed.