Skip to content
  • Mika Westerberg's avatar
    HID: i2c-hid: Prevent sending reports from racing with device reset · 9a327405
    Mika Westerberg authored
    
    
    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>
    9a327405