4.15-stable review patch. If anyone has any objections, please let me know. ------------------ From: Jason Gerecke <killertofu@xxxxxxxxx> commit 403c0f681c1964ff1db8c2fb8de8c4067779d081 upstream. Touch toggle softkeys send a '1' while pressed and a '0' while released, requring the kernel to keep track of wether touch should be enabled or disabled. The code does not handle the state transitions properly, however. If the key is pressed repeatedly, the following four states of states are cycled through (assuming touch starts out enabled): Press: shared->is_touch_on => 0, SW_MUTE_DEVICE => 1 Release: shared->is_touch_on => 0, SW_MUTE_DEVICE => 1 Press: shared->is_touch_on => 1, SW_MUTE_DEVICE => 0 Release: shared->is_touch_on => 1, SW_MUTE_DEVICE => 1 The hardware always properly enables/disables touch when the key is pressed but applications that listen for SW_MUTE_DEVICE events to provide feedback about the state will only ever show touch as being enabled while the key is held, and only every-other time. This sequence occurs because the fallthrough WACOM_HID_WD_TOUCHONOFF case is always handled, and it uses the value of the *local* is_touch_on variable as the value to report to userspace. The local value is equal to the shared value when the button is pressed, but equal to zero when the button is released. Reporting the shared value to userspace fixes this problem, but the fallthrough case needs to update the shared value in an incompatible way (which is why the local variable was introduced in the first place). To work around this, we just handle both cases in a single block of code and update the shared variable as appropriate. Fixes: d793ff8187 ("HID: wacom: generic: support touch on/off softkey") Signed-off-by: Jason Gerecke <jason.gerecke@xxxxxxxxx> Reviewed-by: Aaron Skomra <aaron.skomra@xxxxxxxxx> Tested-by: Aaron Skomra <aaron.skomra@xxxxxxxxx> Signed-off-by: Jiri Kosina <jkosina@xxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/hid/wacom_wac.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1924,7 +1924,6 @@ static void wacom_wac_pad_event(struct h struct wacom_features *features = &wacom_wac->features; unsigned equivalent_usage = wacom_equivalent_usage(usage->hid); int i; - bool is_touch_on = value; bool do_report = false; /* @@ -1969,16 +1968,17 @@ static void wacom_wac_pad_event(struct h break; case WACOM_HID_WD_MUTE_DEVICE: - if (wacom_wac->shared->touch_input && value) { - wacom_wac->shared->is_touch_on = !wacom_wac->shared->is_touch_on; - is_touch_on = wacom_wac->shared->is_touch_on; - } - - /* fall through*/ case WACOM_HID_WD_TOUCHONOFF: if (wacom_wac->shared->touch_input) { + bool *is_touch_on = &wacom_wac->shared->is_touch_on; + + if (equivalent_usage == WACOM_HID_WD_MUTE_DEVICE && value) + *is_touch_on = !(*is_touch_on); + else if (equivalent_usage == WACOM_HID_WD_TOUCHONOFF) + *is_touch_on = value; + input_report_switch(wacom_wac->shared->touch_input, - SW_MUTE_DEVICE, !is_touch_on); + SW_MUTE_DEVICE, !(*is_touch_on)); input_sync(wacom_wac->shared->touch_input); } break;