staging: comedi: addi_apci_3xxx: refactor the ttl digital i/o support
authorH Hartley Sweeten <hsweeten@visionengravers.com>
Wed, 12 Jun 2013 23:15:27 +0000 (16:15 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 17 Jun 2013 21:33:42 +0000 (14:33 -0700)
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 <hsweeten@visionengravers.com>
Reviewed-by: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c
drivers/staging/comedi/drivers/addi_apci_3xxx.c

index dc4b165..e859b60 100644 (file)
@@ -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;
-}
index c3dfe51..ffcacad 100644 (file)
@@ -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;
        }