Re: [PATCH] HID: i2c-hid: Support batch read of input events from fifo

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Srinivas,

On Sat, May 10, 2014 at 2:48 PM, Srinivas Pandruvada
<srinivas.pandruvada@xxxxxxxxxxxxxxx> wrote:
> Hi Benjamin,
>
> On 05/08/2014 07:28 AM, Benjamin Tissoires wrote:
>>
>> On Thu, May 8, 2014 at 9:32 AM, Archana Patni
>> <archana.patni@xxxxxxxxxxxxxxx> wrote:
>>>
>>> Some i2c_hid devices like a sensor hub have built-in fifos which
>>> can accumulate input events in their buffers and trigger an interrupt
>>> at end of a user defined event like fifo full or a timeout. The current
>>> implementation reads one event at a time in the IRQ handler leading to
>>> several hundred interrupts being necessary to flush the fifo.
>>>
>>> This patch changes the threaded IRQ handler to keep input events until
>>> there are no input events left to read. In the normal case, this will
>>> invoke one additional call to fetch an input event to check for no
>>> pending
>>> events and terminate the loop.
>>
>> I must say, I don't like this patch.
>> It seems to me that it will solve your problem but will break other
>> devices. Nothing in the spec says what happens if the host tries to
>> read while the interrupt line is *not* asserted. I can easily imagine
>> several scenarios where the device would hang until the next available
>> data, or will just fail.
>>
>> So the proper way according to the spec is to check the status of the
>> interrupt line. This line is the responsibility of the device to be
>> asserted and we should rely on it to know if we can read again.
>>
>> However, a quick check on the interrupt API did not provide me the
>> function I would like, so I guess this is something to be work on.
>>
>> I can not ack this one until we can be sure not breaking other stuff.
>>
>> So: NACK.
>
> I understand your reason, there may be some HID device which will have issue
> with this change.
> I am interested in throwing some idea, as I am trying to keep the devices in
> deepest idle states as
> long as possible. Sensors are one of the offenders.
> - This driver can register i2c_driver, command callback. We can define one
> of the command to set the set the max size dynamically or fire this logic to
> empty buffers. This way, we can only enable such logic, when a sensor hub
> has capability and notifies this capability dynamically without affecting
> any other hid devices.

I am OK with the logic as long as the i2c calls are independent of the
HID layer. Remember that if the advertised bus is BUS_I2C, it might as
well be an uhid device which will not handle the i2c calls.

Another solution could be to add a HID quirk which triggers the "empty
while input are here" and set this quirk in hid-sensor-hub. This way,
you will be in control of it and other devices might use it as well if
they support it.

I am not a big fan of quirks, so I would still prefer your solution if
you can control it without disturbing the HID subsystem. This will all
depend where you can enable the functionality on the device.

Cheers,
Benjamin

>
> Thanks,
> Srinivas
>
>
>> Cheers,
>> Benjamin
>>
>>> Signed-off-by: Archana Patni <archana.patni@xxxxxxxxx>
>>> Signed-off-by: Subramony Sesha <subramony.sesha@xxxxxxxxx>
>>> Reviewed-by: Mika Westerberg <mika.westerberg@xxxxxxxxx>
>>> Reviewed-by: Srinivas Pandruvada <srinivas.pandruvada@xxxxxxxxx>
>>> ---
>>>   drivers/hid/i2c-hid/i2c-hid.c |   20 +++++++++++++-------
>>>   1 file changed, 13 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/drivers/hid/i2c-hid/i2c-hid.c
>>> b/drivers/hid/i2c-hid/i2c-hid.c
>>> index 21aafc8..3f09a50 100644
>>> --- a/drivers/hid/i2c-hid/i2c-hid.c
>>> +++ b/drivers/hid/i2c-hid/i2c-hid.c
>>> @@ -52,6 +52,7 @@
>>>   static bool debug;
>>>   module_param(debug, bool, 0444);
>>>   MODULE_PARM_DESC(debug, "print a lot of debug information");
>>> +#define MAX_INPUT_EVENT_READ 100
>>>
>>>   #define i2c_hid_dbg(ihid, fmt, arg...)
>>> \
>>>   do {
>>> \
>>> @@ -366,7 +367,7 @@ static int i2c_hid_hwreset(struct i2c_client *client)
>>>          return 0;
>>>   }
>>>
>>> -static void i2c_hid_get_input(struct i2c_hid *ihid)
>>> +static int i2c_hid_get_input(struct i2c_hid *ihid)
>>>   {
>>>          int ret, ret_size;
>>>          int size = le16_to_cpu(ihid->hdesc.wMaxInputLength);
>>> @@ -374,11 +375,11 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)
>>>          ret = i2c_master_recv(ihid->client, ihid->inbuf, size);
>>>          if (ret != size) {
>>>                  if (ret < 0)
>>> -                       return;
>>> +                       return ret;
>>>
>>>                  dev_err(&ihid->client->dev, "%s: got %d data instead of
>>> %d\n",
>>>                          __func__, ret, size);
>>> -               return;
>>> +               return -EIO;
>>>          }
>>>
>>>          ret_size = ihid->inbuf[0] | ihid->inbuf[1] << 8;
>>> @@ -387,13 +388,13 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)
>>>                  /* host or device initiated RESET completed */
>>>                  if (test_and_clear_bit(I2C_HID_RESET_PENDING,
>>> &ihid->flags))
>>>                          wake_up(&ihid->wait);
>>> -               return;
>>> +               return 0;
>>>          }
>>>
>>>          if (ret_size > size) {
>>>                  dev_err(&ihid->client->dev, "%s: incomplete report
>>> (%d/%d)\n",
>>>                          __func__, size, ret_size);
>>> -               return;
>>> +               return -EIO;
>>>          }
>>>
>>>          i2c_hid_dbg(ihid, "input: %*ph\n", ret_size, ihid->inbuf);
>>> @@ -402,17 +403,22 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)
>>>                  hid_input_report(ihid->hid, HID_INPUT_REPORT,
>>> ihid->inbuf + 2,
>>>                                  ret_size - 2, 1);
>>>
>>> -       return;
>>> +       return 1;
>>>   }
>>>
>>>   static irqreturn_t i2c_hid_irq(int irq, void *dev_id)
>>>   {
>>>          struct i2c_hid *ihid = dev_id;
>>> +       int ret;
>>> +       int count = 0;
>>>
>>>          if (test_bit(I2C_HID_READ_PENDING, &ihid->flags))
>>>                  return IRQ_HANDLED;
>>> +       do {
>>> +               count++;
>>> +               ret = i2c_hid_get_input(ihid);
>>>
>>> -       i2c_hid_get_input(ihid);
>>> +       } while (count < MAX_INPUT_EVENT_READ && ret > 0);
>>>
>>>          return IRQ_HANDLED;
>>>   }
>>> --
>>> 1.7.9.5
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-input" in
>>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-input" in
>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux