Skip to content
Commit 9a327405 authored by Mika Westerberg's avatar Mika Westerberg Committed by Jiri Kosina
Browse files

HID: i2c-hid: Prevent sending reports from racing with device reset



When an i2c-hid device is resumed from system sleep the driver resets
the device to be sure it is in known state. The device is expected to
issue an interrupt when reset is complete.

This reset might take few milliseconds to complete so if the HID driver
on top (hid-rmi) starts to set up the device by sending feature reports
etc. the device might not issue the reset complete interrupt anymore.

Below is what happens to touchpad on Lenovo Yoga 900 during resume from
system sleep:

  [   24.790951] i2c_hid i2c-SYNA2B29:00: i2c_hid_hwreset
  [   24.790973] i2c_hid i2c-SYNA2B29:00: i2c_hid_set_power
  [   24.790982] i2c_hid i2c-SYNA2B29:00: __i2c_hid_command: cmd=22 00 00 08
  [   24.793011] i2c_hid i2c-SYNA2B29:00: resetting...
  [   24.793016] i2c_hid i2c-SYNA2B29:00: __i2c_hid_command: cmd=22 00 00 01

Here i2c-hid sends reset command to the touchpad.

  [   24.794012] i2c_hid i2c-SYNA2B29:00: input: 06 00 01 00 00 00
  [   24.794051] i2c_hid i2c-SYNA2B29:00: i2c_hid_set_or_send_report
  [   24.794059] i2c_hid i2c-SYNA2B29:00: __i2c_hid_command:
                 cmd=22 00 3f 03 0f 23 00 04 00 0f 01

Now hid-rmi puts the touchpad to correct mode by sending it a feature
report. This makes the touchpad not to issue reset complete interrupt.

  [   24.796092] i2c_hid i2c-SYNA2B29:00: __i2c_hid_command: waiting...

i2c-hid starts to wait for the reset interrupt to trigger which never
happens.

  [   24.798304] i2c_hid i2c-SYNA2B29:00: i2c_hid_set_or_send_report
  [   24.798313] i2c_hid i2c-SYNA2B29:00: __i2c_hid_command:
                 cmd=25 00 17 00 09 01 42 00 2e 00 19 19 00 10 cc 06 74 04 0f
                     19 00 00 00 00 00

Yet another output report from hid-rmi driver.

  [   29.795630] i2c_hid i2c-SYNA2B29:00: __i2c_hid_command: finished.
  [   29.795637] i2c_hid i2c-SYNA2B29:00: failed to reset device.

After 5 seconds i2c-hid driver times out.

  [   29.795642] i2c_hid i2c-SYNA2B29:00: i2c_hid_set_power
  [   29.795649] i2c_hid i2c-SYNA2B29:00: __i2c_hid_command: cmd=22 00 01 08
  [   29.797576] dpm_run_callback(): i2c_hid_resume+0x0/0xb0 returns -61
  [   29.797584] PM: Device i2c-SYNA2B29:00 failed to resume: error -61

After this the touchpad does not work anymore (and also resume itself
gets slowed down because of the timeout).

Prevent sending of feature/output reports while the device is being
reset by adding a mutex which is held during that time.

Reported-and-tested-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Reported-by: default avatarNish Aravamudan <nish.aravamudan@gmail.com>
Suggested-by: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
Reviewed-by: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 2078665a
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment