HID: wacom: remove the battery when the EKR is off

commit 9ac6678b95 upstream.

Currently the EKR battery remains even after we stop getting information
from the device. This can lead to a stale battery persisting indefinitely
in userspace.

The remote sends a heartbeat every 10 seconds. Delete the battery if we
miss two heartbeats (after 21 seconds). Restore the battery once we see
a heartbeat again.

Signed-off-by: Aaron Skomra <skomra@gmail.com>
Signed-off-by: Aaron Armstrong Skomra <aaron.skomra@wacom.com>
Reviewed-by: Jason Gerecke <jason.gerecke@wacom.com>
Fixes: 9f1015d45f ("HID: wacom: EKR: attach the power_supply on first connection")
CC: stable@vger.kernel.org
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Aaron Armstrong Skomra 2023-07-25 15:20:25 -07:00 committed by Greg Kroah-Hartman
parent ee6ed5c7a7
commit eb64714c90
4 changed files with 24 additions and 4 deletions

View file

@ -156,6 +156,7 @@ struct wacom_remote {
struct input_dev *input; struct input_dev *input;
bool registered; bool registered;
struct wacom_battery battery; struct wacom_battery battery;
ktime_t active_time;
} remotes[WACOM_MAX_REMOTES]; } remotes[WACOM_MAX_REMOTES];
}; };

View file

@ -2500,6 +2500,18 @@ static void wacom_wireless_work(struct work_struct *work)
return; return;
} }
static void wacom_remote_destroy_battery(struct wacom *wacom, int index)
{
struct wacom_remote *remote = wacom->remote;
if (remote->remotes[index].battery.battery) {
devres_release_group(&wacom->hdev->dev,
&remote->remotes[index].battery.bat_desc);
remote->remotes[index].battery.battery = NULL;
remote->remotes[index].active_time = 0;
}
}
static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index) static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
{ {
struct wacom_remote *remote = wacom->remote; struct wacom_remote *remote = wacom->remote;
@ -2514,9 +2526,7 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
remote->remotes[i].registered = false; remote->remotes[i].registered = false;
spin_unlock_irqrestore(&remote->remote_lock, flags); spin_unlock_irqrestore(&remote->remote_lock, flags);
if (remote->remotes[i].battery.battery) wacom_remote_destroy_battery(wacom, i);
devres_release_group(&wacom->hdev->dev,
&remote->remotes[i].battery.bat_desc);
if (remote->remotes[i].group.name) if (remote->remotes[i].group.name)
devres_release_group(&wacom->hdev->dev, devres_release_group(&wacom->hdev->dev,
@ -2524,7 +2534,6 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
remote->remotes[i].serial = 0; remote->remotes[i].serial = 0;
remote->remotes[i].group.name = NULL; remote->remotes[i].group.name = NULL;
remote->remotes[i].battery.battery = NULL;
wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN; wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
} }
} }
@ -2609,6 +2618,9 @@ static int wacom_remote_attach_battery(struct wacom *wacom, int index)
if (remote->remotes[index].battery.battery) if (remote->remotes[index].battery.battery)
return 0; return 0;
if (!remote->remotes[index].active_time)
return 0;
if (wacom->led.groups[index].select == WACOM_STATUS_UNKNOWN) if (wacom->led.groups[index].select == WACOM_STATUS_UNKNOWN)
return 0; return 0;
@ -2624,6 +2636,7 @@ static void wacom_remote_work(struct work_struct *work)
{ {
struct wacom *wacom = container_of(work, struct wacom, remote_work); struct wacom *wacom = container_of(work, struct wacom, remote_work);
struct wacom_remote *remote = wacom->remote; struct wacom_remote *remote = wacom->remote;
ktime_t kt = ktime_get();
struct wacom_remote_data data; struct wacom_remote_data data;
unsigned long flags; unsigned long flags;
unsigned int count; unsigned int count;
@ -2650,6 +2663,10 @@ static void wacom_remote_work(struct work_struct *work)
serial = data.remote[i].serial; serial = data.remote[i].serial;
if (data.remote[i].connected) { if (data.remote[i].connected) {
if (kt - remote->remotes[i].active_time > WACOM_REMOTE_BATTERY_TIMEOUT
&& remote->remotes[i].active_time != 0)
wacom_remote_destroy_battery(wacom, i);
if (remote->remotes[i].serial == serial) { if (remote->remotes[i].serial == serial) {
wacom_remote_attach_battery(wacom, i); wacom_remote_attach_battery(wacom, i);
continue; continue;

View file

@ -1077,6 +1077,7 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
if (index < 0 || !remote->remotes[index].registered) if (index < 0 || !remote->remotes[index].registered)
goto out; goto out;
remote->remotes[i].active_time = ktime_get();
input = remote->remotes[index].input; input = remote->remotes[index].input;
input_report_key(input, BTN_0, (data[9] & 0x01)); input_report_key(input, BTN_0, (data[9] & 0x01));

View file

@ -19,6 +19,7 @@
#define WACOM_NAME_MAX 64 #define WACOM_NAME_MAX 64
#define WACOM_MAX_REMOTES 5 #define WACOM_MAX_REMOTES 5
#define WACOM_STATUS_UNKNOWN 255 #define WACOM_STATUS_UNKNOWN 255
#define WACOM_REMOTE_BATTERY_TIMEOUT 21000000000ll
/* packet length for individual models */ /* packet length for individual models */
#define WACOM_PKGLEN_BBFUN 9 #define WACOM_PKGLEN_BBFUN 9