From da6578abd7c7535e59cae5eb0c54f5cd13902a6d Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 12 Jun 2013 16:15:27 -0700 Subject: [PATCH] staging: comedi: addi_apci_3xxx: refactor the ttl digital i/o support Currently, the subdevice functions used to configure and read/write the ttl digital i/o ports is way over to complicated. The (*insn_config) function also abuses the comedi API by overriding the instruction command passed in data[0]. Fix the ttl digital i/o support to work like the comedi core expects. The (*insn_config) function supports the three instructions common for COMEDI_SUBD_DIO subdevices: INSN_CONFIG_DIO_INPUT - configure the specified channel as input INSN_CONFIG_DIO_OUTPUT - configure the specified channel as output INSN_CONFIG_DIO_QUERY - returns the status of the specified channel Port 0 (channels 0-7) is always input Port 1 (channels 8-15) is always output Port 2 (channels 9-23) are programmable i/o (all channels are input or output) The (*insn_bits) function allows writing to the output channels and returns the state of all channels. The (*insn_read) and (*insn_write) functions are not required. The comedi core will emulate them using the (*insn_bits) function. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- .../comedi/drivers/addi-data/hwdrv_apci3xxx.c | 520 ------------------ .../staging/comedi/drivers/addi_apci_3xxx.c | 84 ++- 2 files changed, 79 insertions(+), 525 deletions(-) diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c index dc4b16544848..e859b6039d8c 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c @@ -514,523 +514,3 @@ static int i_APCI3XXX_InsnReadAnalogInput(struct comedi_device *dev, } 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 = (unsigned char) data[0]; | -| b_Port2Mode = (unsigned char) data[1]; | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value :>0: No error | -| -1: Port 2 mode selection is wrong | -| .... | -| -100 : Config command error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnConfigInitTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct apci3xxx_private *devpriv = dev->private; - int i_ReturnValue = insn->n; - unsigned char b_Command = 0; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - /*******************/ - /* Get the command */ - /* **************** */ - - b_Command = (unsigned char) 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 | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnBitsTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct apci3xxx_private *devpriv = dev->private; - int i_ReturnValue = insn->n; - unsigned char b_ChannelCpt = 0; - unsigned int dw_ChannelMask = 0; - unsigned int dw_BitMask = 0; - unsigned int 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 | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnReadTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct apci3xxx_private *devpriv = dev->private; - unsigned char b_Channel = (unsigned char) 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 | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnWriteTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct apci3xxx_private *devpriv = dev->private; - int i_ReturnValue = insn->n; - unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec); - unsigned char b_State = 0; - unsigned int dw_Status = 0; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - b_State = (unsigned char) data[0]; - - /***********************/ - /* Test if read port 0 */ - /***********************/ - - if (b_Channel < 8) { - /*****************************************************************************/ - /* Read port 0 (first digital output port) and set/reset the selected 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 selected 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; -} diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c index c3dfe5188e7a..ffcacade5f82 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c +++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c @@ -378,7 +378,6 @@ struct apci3xxx_private { unsigned char b_EocEosConversionTimeBase; unsigned char b_SingelDiff; struct task_struct *tsk_Current; - unsigned int ul_TTLPortConfiguration[10]; }; #include "addi-data/hwdrv_apci3xxx.c" @@ -477,6 +476,83 @@ static int apci3xxx_do_insn_bits(struct comedi_device *dev, return insn->n; } +static int apci3xxx_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask = 1 << chan; + unsigned int bits; + + /* + * Port 0 (channels 0-7) are always inputs + * Port 1 (channels 8-15) are always outputs + * Port 2 (channels 16-23) are programmable i/o + * + * Changing any channel in port 2 changes the entire port. + */ + if (mask & 0xff0000) + bits = 0xff0000; + else + bits = 0; + + 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_OUTPUT : COMEDI_INPUT; + return insn->n; + default: + return -EINVAL; + } + + /* update port 2 configuration */ + if (bits) + outl((s->io_bits >> 24) & 0xff, devpriv->iobase + 224); + + return insn->n; +} + +static int apci3xxx_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int mask = data[0]; + unsigned int bits = data[1]; + unsigned int val; + + /* only update output channels */ + mask &= s->io_bits; + if (mask) { + s->state &= ~mask; + s->state |= (bits & mask); + + if (mask & 0xff) + outl(s->state & 0xff, devpriv->iobase + 80); + if (mask & 0xff0000) + outl((s->state >> 16) & 0xff, devpriv->iobase + 112); + } + + val = inl(devpriv->iobase + 80); + val |= (inl(devpriv->iobase + 64) << 8); + if (s->io_bits & 0xff0000) + val |= (inl(devpriv->iobase + 112) << 16); + else + val |= (inl(devpriv->iobase + 96) << 16); + + data[1] = val; + + return insn->n; +} + static int apci3xxx_reset(struct comedi_device *dev) { struct apci3xxx_private *devpriv = dev->private; @@ -632,10 +708,8 @@ static int apci3xxx_auto_attach(struct comedi_device *dev, s->maxdata = 1; s->io_bits = 0xff; /* channels 0-7 are always outputs */ s->range_table = &range_digital; - s->insn_config = i_APCI3XXX_InsnConfigInitTTLIO; - s->insn_bits = i_APCI3XXX_InsnBitsTTLIO; - s->insn_read = i_APCI3XXX_InsnReadTTLIO; - s->insn_write = i_APCI3XXX_InsnWriteTTLIO; + s->insn_config = apci3xxx_dio_insn_config; + s->insn_bits = apci3xxx_dio_insn_bits; } else { s->type = COMEDI_SUBD_UNUSED; } -- 2.34.1