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: H Hartley Sweeten <hsweeten@visionengravers.com> Cc: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
26b3989946
commit
92eb37959f
@ -1,542 +0,0 @@
|
||||
/**
|
||||
@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;
|
||||
}
|
@ -1,9 +1,12 @@
|
||||
#include "../comedidev.h"
|
||||
#include "comedi_fc.h"
|
||||
|
||||
#include "addi-data/addi_common.h"
|
||||
|
||||
#include "addi-data/hwdrv_apci16xx.c"
|
||||
/*
|
||||
* Register I/O map
|
||||
*/
|
||||
#define APCI16XX_IN_REG(x) (((x) * 4) + 0x08)
|
||||
#define APCI16XX_OUT_REG(x) (((x) * 4) + 0x14)
|
||||
#define APCI16XX_DIR_REG(x) (((x) * 4) + 0x20)
|
||||
|
||||
struct apci16xx_boardinfo {
|
||||
const char *name;
|
||||
@ -17,15 +20,78 @@ static const struct apci16xx_boardinfo apci16xx_boardtypes[] = {
|
||||
.name = "apci1648",
|
||||
.vendor = PCI_VENDOR_ID_ADDIDATA,
|
||||
.device = 0x1009,
|
||||
.n_chan = 48,
|
||||
.n_chan = 48, /* 2 subdevices */
|
||||
}, {
|
||||
.name = "apci1696",
|
||||
.vendor = PCI_VENDOR_ID_ADDIDATA,
|
||||
.device = 0x100A,
|
||||
.n_chan = 96,
|
||||
.n_chan = 96, /* 3 subdevices */
|
||||
},
|
||||
};
|
||||
|
||||
static int apci16xx_insn_config(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec);
|
||||
unsigned int bits;
|
||||
|
||||
/*
|
||||
* Each 8-bit "port" is configurable as either input or
|
||||
* output. Changing the configuration of any channel in
|
||||
* a port changes the entire port.
|
||||
*/
|
||||
if (chan_mask & 0x000000ff)
|
||||
bits = 0x000000ff;
|
||||
else if (chan_mask & 0x0000ff00)
|
||||
bits = 0x0000ff00;
|
||||
else if (chan_mask & 0x00ff0000)
|
||||
bits = 0x00ff0000;
|
||||
else
|
||||
bits = 0xff000000;
|
||||
|
||||
switch (data[0]) {
|
||||
case INSN_CONFIG_DIO_INPUT:
|
||||
s->io_bits &= ~bits;
|
||||
break;
|
||||
case INSN_CONFIG_DIO_OUTPUT:
|
||||
s->io_bits |= bits;
|
||||
break;
|
||||
case INSN_CONFIG_DIO_QUERY:
|
||||
data[1] = (s->io_bits & bits) ? COMEDI_INPUT : COMEDI_OUTPUT;
|
||||
return insn->n;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
outl(s->io_bits, dev->iobase + APCI16XX_DIR_REG(s->index));
|
||||
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static int apci16xx_dio_insn_bits(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
unsigned int mask = data[0];
|
||||
unsigned int bits = data[1];
|
||||
|
||||
/* Only update the channels configured as outputs */
|
||||
mask &= s->io_bits;
|
||||
if (mask) {
|
||||
s->state &= ~mask;
|
||||
s->state |= (bits & mask);
|
||||
|
||||
outl(s->state, dev->iobase + APCI16XX_OUT_REG(s->index));
|
||||
}
|
||||
|
||||
data[1] = inl(dev->iobase + APCI16XX_IN_REG(s->index));
|
||||
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static const void *apci16xx_find_boardinfo(struct comedi_device *dev,
|
||||
struct pci_dev *pcidev)
|
||||
{
|
||||
@ -46,8 +112,10 @@ static int apci16xx_auto_attach(struct comedi_device *dev,
|
||||
{
|
||||
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
|
||||
const struct apci16xx_boardinfo *board;
|
||||
struct addi_private *devpriv;
|
||||
struct comedi_subdevice *s;
|
||||
unsigned int n_subdevs;
|
||||
unsigned int last;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
board = apci16xx_find_boardinfo(dev, pcidev);
|
||||
@ -56,34 +124,44 @@ static int apci16xx_auto_attach(struct comedi_device *dev,
|
||||
dev->board_ptr = board;
|
||||
dev->board_name = board->name;
|
||||
|
||||
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
|
||||
if (!devpriv)
|
||||
return -ENOMEM;
|
||||
dev->private = devpriv;
|
||||
|
||||
ret = comedi_pci_enable(pcidev, dev->board_name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev->iobase = pci_resource_start(pcidev, 0);
|
||||
|
||||
ret = comedi_alloc_subdevices(dev, 1);
|
||||
/*
|
||||
* Work out the nubmer of subdevices needed to support all the
|
||||
* digital i/o channels on the board. Each subdevice supports
|
||||
* up to 32 channels.
|
||||
*/
|
||||
n_subdevs = board->n_chan / 32;
|
||||
if ((n_subdevs * 32) < board->n_chan) {
|
||||
last = board->n_chan - (n_subdevs * 32);
|
||||
n_subdevs++;
|
||||
} else {
|
||||
last = 0;
|
||||
}
|
||||
|
||||
ret = comedi_alloc_subdevices(dev, n_subdevs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Initialize the TTL digital i/o */
|
||||
s = &dev->subdevices[0];
|
||||
s->type = COMEDI_SUBD_DIO;
|
||||
s->subdev_flags = SDF_WRITEABLE | SDF_READABLE;
|
||||
s->n_chan = board->n_chan;
|
||||
s->maxdata = 1;
|
||||
s->io_bits = 0; /* all bits input */
|
||||
s->len_chanlist = board->n_chan;
|
||||
s->range_table = &range_digital;
|
||||
s->insn_config = i_APCI16XX_InsnConfigInitTTLIO;
|
||||
s->insn_bits = i_APCI16XX_InsnBitsReadTTLIO;
|
||||
s->insn_read = i_APCI16XX_InsnReadTTLIOAllPortValue;
|
||||
s->insn_write = i_APCI16XX_InsnBitsWriteTTLIO;
|
||||
/* Initialize the TTL digital i/o subdevices */
|
||||
for (i = 0; i < n_subdevs; i++) {
|
||||
s = &dev->subdevices[i];
|
||||
s->type = COMEDI_SUBD_DIO;
|
||||
s->subdev_flags = SDF_WRITEABLE | SDF_READABLE;
|
||||
s->n_chan = ((i * 32) < board->n_chan) ? 32 : last;
|
||||
s->maxdata = 1;
|
||||
s->range_table = &range_digital;
|
||||
s->insn_config = apci16xx_insn_config;
|
||||
s->insn_bits = apci16xx_dio_insn_bits;
|
||||
|
||||
/* Default all channels to inputs */
|
||||
s->io_bits = 0;
|
||||
outl(s->io_bits, dev->iobase + APCI16XX_DIR_REG(i));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user