]> git.itanic.dy.fi Git - linux-stable/commitdiff
HID: wacom: Force pen out of prox if no events have been received in a while
authorJason Gerecke <killertofu@gmail.com>
Fri, 15 Jul 2022 23:05:19 +0000 (16:05 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 30 May 2023 11:42:12 +0000 (12:42 +0100)
commit 94b179052f95c294d83e9c9c34f7833cf3cd4305 upstream.

Prox-out events may not be reliably sent by some AES firmware. This can
cause problems for users, particularly due to arbitration logic disabling
touch input while the pen is in prox.

This commit adds a timer which is reset every time a new prox event is
received. When the timer expires we check to see if the pen is still in
prox and force it out if necessary. This is patterend off of the same
solution used by 'hid-letsketch' driver which has a similar problem.

Link: https://github.com/linuxwacom/input-wacom/issues/310
Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Cc: Ping Cheng <pinglinux@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/hid/wacom.h
drivers/hid/wacom_sys.c
drivers/hid/wacom_wac.c

index 9c0900c35b236b71b9b89ab5d33a922f2f15c7b9..45636d82ec306ec902ae7e21eec1a80460f55555 100644 (file)
@@ -94,6 +94,7 @@
 #include <linux/leds.h>
 #include <linux/usb/input.h>
 #include <linux/power_supply.h>
+#include <linux/timer.h>
 #include <asm/unaligned.h>
 
 /*
@@ -170,6 +171,7 @@ struct wacom {
        struct delayed_work init_work;
        struct wacom_remote *remote;
        struct work_struct mode_change_work;
+       struct timer_list idleprox_timer;
        bool generic_has_leds;
        struct wacom_leds {
                struct wacom_group_leds *groups;
@@ -242,4 +244,5 @@ struct wacom_led *wacom_led_find(struct wacom *wacom, unsigned int group,
 struct wacom_led *wacom_led_next(struct wacom *wacom, struct wacom_led *cur);
 int wacom_equivalent_usage(int usage);
 int wacom_initialize_leds(struct wacom *wacom);
+void wacom_idleprox_timeout(struct timer_list *list);
 #endif
index 8e32415e0a9099cabb44ad0e57275f50d2960a36..4e4a3424c1f9fdb6702c7d7e5c06ca63d4a0b231 100644 (file)
@@ -2754,6 +2754,7 @@ static int wacom_probe(struct hid_device *hdev,
        INIT_WORK(&wacom->battery_work, wacom_battery_work);
        INIT_WORK(&wacom->remote_work, wacom_remote_work);
        INIT_WORK(&wacom->mode_change_work, wacom_mode_change_work);
+       timer_setup(&wacom->idleprox_timer, &wacom_idleprox_timeout, TIMER_DEFERRABLE);
 
        /* ask for the report descriptor to be loaded by HID */
        error = hid_parse(hdev);
@@ -2802,6 +2803,7 @@ static void wacom_remove(struct hid_device *hdev)
        cancel_work_sync(&wacom->battery_work);
        cancel_work_sync(&wacom->remote_work);
        cancel_work_sync(&wacom->mode_change_work);
+       del_timer_sync(&wacom->idleprox_timer);
        if (hdev->bus == BUS_BLUETOOTH)
                device_remove_file(&hdev->dev, &dev_attr_speed);
 
index 0747e58472c1efedb1b4d2883e96719d8e80e556..c3ebc0cb69b80cbd55c94e49cffff0b63b0dc19a 100644 (file)
@@ -15,6 +15,7 @@
 #include "wacom_wac.h"
 #include "wacom.h"
 #include <linux/input/mt.h>
+#include <linux/jiffies.h>
 
 /* resolution for penabled devices */
 #define WACOM_PL_RES           20
@@ -45,6 +46,43 @@ static int wacom_numbered_button_to_key(int n);
 
 static void wacom_update_led(struct wacom *wacom, int button_count, int mask,
                             int group);
+
+static void wacom_force_proxout(struct wacom_wac *wacom_wac)
+{
+       struct input_dev *input = wacom_wac->pen_input;
+
+       wacom_wac->shared->stylus_in_proximity = 0;
+
+       input_report_key(input, BTN_TOUCH, 0);
+       input_report_key(input, BTN_STYLUS, 0);
+       input_report_key(input, BTN_STYLUS2, 0);
+       input_report_key(input, BTN_STYLUS3, 0);
+       input_report_key(input, wacom_wac->tool[0], 0);
+       if (wacom_wac->serial[0]) {
+               input_report_abs(input, ABS_MISC, 0);
+       }
+       input_report_abs(input, ABS_PRESSURE, 0);
+
+       wacom_wac->tool[0] = 0;
+       wacom_wac->id[0] = 0;
+       wacom_wac->serial[0] = 0;
+
+       input_sync(input);
+}
+
+void wacom_idleprox_timeout(struct timer_list *list)
+{
+       struct wacom *wacom = from_timer(wacom, list, idleprox_timer);
+       struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+
+       if (!wacom_wac->hid_data.sense_state) {
+               return;
+       }
+
+       hid_warn(wacom->hdev, "%s: tool appears to be hung in-prox. forcing it out.\n", __func__);
+       wacom_force_proxout(wacom_wac);
+}
+
 /*
  * Percent of battery capacity for Graphire.
  * 8th value means AC online and show 100% capacity.
@@ -2255,6 +2293,7 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
                value = field->logical_maximum - value;
                break;
        case HID_DG_INRANGE:
+               mod_timer(&wacom->idleprox_timer, jiffies + msecs_to_jiffies(100));
                wacom_wac->hid_data.inrange_state = value;
                if (!(features->quirks & WACOM_QUIRK_SENSE))
                        wacom_wac->hid_data.sense_state = value;