Takashi Iwai f0a979
From 94b179052f95c294d83e9c9c34f7833cf3cd4305 Mon Sep 17 00:00:00 2001
Takashi Iwai f0a979
From: Jason Gerecke <killertofu@gmail.com>
Takashi Iwai f0a979
Date: Fri, 15 Jul 2022 16:05:19 -0700
Takashi Iwai f0a979
Subject: [PATCH] HID: wacom: Force pen out of prox if no events have been received in a while
Takashi Iwai f0a979
Git-commit: 94b179052f95c294d83e9c9c34f7833cf3cd4305
Takashi Iwai f0a979
Patch-mainline: v6.0-rc1
Takashi Iwai f0a979
References: git-fixes
Takashi Iwai f0a979
Takashi Iwai f0a979
Prox-out events may not be reliably sent by some AES firmware. This can
Takashi Iwai f0a979
cause problems for users, particularly due to arbitration logic disabling
Takashi Iwai f0a979
touch input while the pen is in prox.
Takashi Iwai f0a979
Takashi Iwai f0a979
This commit adds a timer which is reset every time a new prox event is
Takashi Iwai f0a979
received. When the timer expires we check to see if the pen is still in
Takashi Iwai f0a979
prox and force it out if necessary. This is patterend off of the same
Takashi Iwai f0a979
solution used by 'hid-letsketch' driver which has a similar problem.
Takashi Iwai f0a979
Takashi Iwai f0a979
Link: https://github.com/linuxwacom/input-wacom/issues/310
Takashi Iwai f0a979
Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
Takashi Iwai f0a979
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Takashi Iwai f0a979
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai f0a979
Takashi Iwai f0a979
---
Takashi Iwai f0a979
 drivers/hid/wacom.h     |  3 +++
Takashi Iwai f0a979
 drivers/hid/wacom_sys.c |  2 ++
Takashi Iwai f0a979
 drivers/hid/wacom_wac.c | 39 +++++++++++++++++++++++++++++++++++++++
Takashi Iwai f0a979
 3 files changed, 44 insertions(+)
Takashi Iwai f0a979
Takashi Iwai f0a979
diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h
Takashi Iwai f0a979
index 203d27d198b8..3f8b24a57014 100644
Takashi Iwai f0a979
--- a/drivers/hid/wacom.h
Takashi Iwai f0a979
+++ b/drivers/hid/wacom.h
Takashi Iwai f0a979
@@ -91,6 +91,7 @@
Takashi Iwai f0a979
 #include <linux/leds.h>
Takashi Iwai f0a979
 #include <linux/usb/input.h>
Takashi Iwai f0a979
 #include <linux/power_supply.h>
Takashi Iwai f0a979
+#include <linux/timer.h>
Takashi Iwai f0a979
 #include <asm/unaligned.h>
Takashi Iwai f0a979
 
Takashi Iwai f0a979
 /*
Takashi Iwai f0a979
@@ -167,6 +168,7 @@ struct wacom {
Takashi Iwai f0a979
 	struct delayed_work init_work;
Takashi Iwai f0a979
 	struct wacom_remote *remote;
Takashi Iwai f0a979
 	struct work_struct mode_change_work;
Takashi Iwai f0a979
+	struct timer_list idleprox_timer;
Takashi Iwai f0a979
 	bool generic_has_leds;
Takashi Iwai f0a979
 	struct wacom_leds {
Takashi Iwai f0a979
 		struct wacom_group_leds *groups;
Takashi Iwai f0a979
@@ -239,4 +241,5 @@ struct wacom_led *wacom_led_find(struct wacom *wacom, unsigned int group,
Takashi Iwai f0a979
 struct wacom_led *wacom_led_next(struct wacom *wacom, struct wacom_led *cur);
Takashi Iwai f0a979
 int wacom_equivalent_usage(int usage);
Takashi Iwai f0a979
 int wacom_initialize_leds(struct wacom *wacom);
Takashi Iwai f0a979
+void wacom_idleprox_timeout(struct timer_list *list);
Takashi Iwai f0a979
 #endif
Takashi Iwai f0a979
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
Takashi Iwai f0a979
index 98384b911288..194a2e327591 100644
Takashi Iwai f0a979
--- a/drivers/hid/wacom_sys.c
Takashi Iwai f0a979
+++ b/drivers/hid/wacom_sys.c
Takashi Iwai f0a979
@@ -2781,6 +2781,7 @@ static int wacom_probe(struct hid_device *hdev,
Takashi Iwai f0a979
 	INIT_WORK(&wacom->battery_work, wacom_battery_work);
Takashi Iwai f0a979
 	INIT_WORK(&wacom->remote_work, wacom_remote_work);
Takashi Iwai f0a979
 	INIT_WORK(&wacom->mode_change_work, wacom_mode_change_work);
Takashi Iwai f0a979
+	timer_setup(&wacom->idleprox_timer, &wacom_idleprox_timeout, TIMER_DEFERRABLE);
Takashi Iwai f0a979
 
Takashi Iwai f0a979
 	/* ask for the report descriptor to be loaded by HID */
Takashi Iwai f0a979
 	error = hid_parse(hdev);
Takashi Iwai f0a979
@@ -2821,6 +2822,7 @@ static void wacom_remove(struct hid_device *hdev)
Takashi Iwai f0a979
 	cancel_work_sync(&wacom->battery_work);
Takashi Iwai f0a979
 	cancel_work_sync(&wacom->remote_work);
Takashi Iwai f0a979
 	cancel_work_sync(&wacom->mode_change_work);
Takashi Iwai f0a979
+	del_timer_sync(&wacom->idleprox_timer);
Takashi Iwai f0a979
 	if (hdev->bus == BUS_BLUETOOTH)
Takashi Iwai f0a979
 		device_remove_file(&hdev->dev, &dev_attr_speed);
Takashi Iwai f0a979
 
Takashi Iwai f0a979
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
Takashi Iwai f0a979
index f8cc4bb3e3a7..d049239256a2 100644
Takashi Iwai f0a979
--- a/drivers/hid/wacom_wac.c
Takashi Iwai f0a979
+++ b/drivers/hid/wacom_wac.c
Takashi Iwai f0a979
@@ -11,6 +11,7 @@
Takashi Iwai f0a979
 #include "wacom_wac.h"
Takashi Iwai f0a979
 #include "wacom.h"
Takashi Iwai f0a979
 #include <linux/input/mt.h>
Takashi Iwai f0a979
+#include <linux/jiffies.h>
Takashi Iwai f0a979
 
Takashi Iwai f0a979
 /* resolution for penabled devices */
Takashi Iwai f0a979
 #define WACOM_PL_RES		20
Takashi Iwai f0a979
@@ -41,6 +42,43 @@ static int wacom_numbered_button_to_key(int n);
Takashi Iwai f0a979
 
Takashi Iwai f0a979
 static void wacom_update_led(struct wacom *wacom, int button_count, int mask,
Takashi Iwai f0a979
 			     int group);
Takashi Iwai f0a979
+
Takashi Iwai f0a979
+static void wacom_force_proxout(struct wacom_wac *wacom_wac)
Takashi Iwai f0a979
+{
Takashi Iwai f0a979
+	struct input_dev *input = wacom_wac->pen_input;
Takashi Iwai f0a979
+
Takashi Iwai f0a979
+	wacom_wac->shared->stylus_in_proximity = 0;
Takashi Iwai f0a979
+
Takashi Iwai f0a979
+	input_report_key(input, BTN_TOUCH, 0);
Takashi Iwai f0a979
+	input_report_key(input, BTN_STYLUS, 0);
Takashi Iwai f0a979
+	input_report_key(input, BTN_STYLUS2, 0);
Takashi Iwai f0a979
+	input_report_key(input, BTN_STYLUS3, 0);
Takashi Iwai f0a979
+	input_report_key(input, wacom_wac->tool[0], 0);
Takashi Iwai f0a979
+	if (wacom_wac->serial[0]) {
Takashi Iwai f0a979
+		input_report_abs(input, ABS_MISC, 0);
Takashi Iwai f0a979
+	}
Takashi Iwai f0a979
+	input_report_abs(input, ABS_PRESSURE, 0);
Takashi Iwai f0a979
+
Takashi Iwai f0a979
+	wacom_wac->tool[0] = 0;
Takashi Iwai f0a979
+	wacom_wac->id[0] = 0;
Takashi Iwai f0a979
+	wacom_wac->serial[0] = 0;
Takashi Iwai f0a979
+
Takashi Iwai f0a979
+	input_sync(input);
Takashi Iwai f0a979
+}
Takashi Iwai f0a979
+
Takashi Iwai f0a979
+void wacom_idleprox_timeout(struct timer_list *list)
Takashi Iwai f0a979
+{
Takashi Iwai f0a979
+	struct wacom *wacom = from_timer(wacom, list, idleprox_timer);
Takashi Iwai f0a979
+	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
Takashi Iwai f0a979
+
Takashi Iwai f0a979
+	if (!wacom_wac->hid_data.sense_state) {
Takashi Iwai f0a979
+		return;
Takashi Iwai f0a979
+	}
Takashi Iwai f0a979
+
Takashi Iwai f0a979
+	hid_warn(wacom->hdev, "%s: tool appears to be hung in-prox. forcing it out.\n", __func__);
Takashi Iwai f0a979
+	wacom_force_proxout(wacom_wac);
Takashi Iwai f0a979
+}
Takashi Iwai f0a979
+
Takashi Iwai f0a979
 /*
Takashi Iwai f0a979
  * Percent of battery capacity for Graphire.
Takashi Iwai f0a979
  * 8th value means AC online and show 100% capacity.
Takashi Iwai f0a979
@@ -2329,6 +2367,7 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
Takashi Iwai f0a979
 		value = field->logical_maximum - value;
Takashi Iwai f0a979
 		break;
Takashi Iwai f0a979
 	case HID_DG_INRANGE:
Takashi Iwai f0a979
+		mod_timer(&wacom->idleprox_timer, jiffies + msecs_to_jiffies(100));
Takashi Iwai f0a979
 		wacom_wac->hid_data.inrange_state = value;
Takashi Iwai f0a979
 		if (!(features->quirks & WACOM_QUIRK_SENSE))
Takashi Iwai f0a979
 			wacom_wac->hid_data.sense_state = value;
Takashi Iwai f0a979
-- 
Takashi Iwai f0a979
2.35.3
Takashi Iwai f0a979