]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.16.4/hid-input-fix-battery-level-reporting-on-bt-mice.patch
Fixes for 4.19
[thirdparty/kernel/stable-queue.git] / releases / 4.16.4 / hid-input-fix-battery-level-reporting-on-bt-mice.patch
1 From 2e210bbb7429cdcf1a1a3ad00c1bf98bd9bf2452 Mon Sep 17 00:00:00 2001
2 From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
3 Date: Tue, 3 Apr 2018 10:52:20 -0700
4 Subject: HID: input: fix battery level reporting on BT mice
5
6 From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
7
8 commit 2e210bbb7429cdcf1a1a3ad00c1bf98bd9bf2452 upstream.
9
10 The commit 581c4484769e ("HID: input: map digitizer battery usage")
11 assumed that devices having input (qas opposed to feature) report for
12 battery strength would report the data on their own, without the need to
13 be polled by the kernel; unfortunately it is not so. Many wireless mice
14 do not send unsolicited reports with battery strength data and have to
15 be polled explicitly. As a complication, stylus devices on digitizers
16 are not normally connected to the base and thus can not be polled - the
17 base can only determine battery strength in the stylus when it is in
18 proximity.
19
20 To solve this issue, we add a special flag that tells the kernel
21 to avoid polling the device (and expect unsolicited reports) and set it
22 when report field with physical usage of digitizer stylus (HID_DG_STYLUS).
23 Unless this flag is set, and we have not seen the unsolicited reports,
24 the kernel will attempt to poll the device when userspace attempts to
25 read "capacity" and "state" attributes of power_supply object
26 corresponding to the devices battery.
27
28 Fixes: 581c4484769e ("HID: input: map digitizer battery usage")
29 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=198095
30 Cc: stable@vger.kernel.org
31 Reported-and-tested-by: Martin van Es <martin@mrvanes.com>
32 Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
33 Signed-off-by: Jiri Kosina <jkosina@suse.cz>
34 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
35
36 ---
37 drivers/hid/hid-input.c | 24 +++++++++++++++++-------
38 include/linux/hid.h | 9 ++++++++-
39 2 files changed, 25 insertions(+), 8 deletions(-)
40
41 --- a/drivers/hid/hid-input.c
42 +++ b/drivers/hid/hid-input.c
43 @@ -387,7 +387,8 @@ static int hidinput_get_battery_property
44 break;
45
46 case POWER_SUPPLY_PROP_CAPACITY:
47 - if (dev->battery_report_type == HID_FEATURE_REPORT) {
48 + if (dev->battery_status != HID_BATTERY_REPORTED &&
49 + !dev->battery_avoid_query) {
50 value = hidinput_query_battery_capacity(dev);
51 if (value < 0)
52 return value;
53 @@ -403,17 +404,17 @@ static int hidinput_get_battery_property
54 break;
55
56 case POWER_SUPPLY_PROP_STATUS:
57 - if (!dev->battery_reported &&
58 - dev->battery_report_type == HID_FEATURE_REPORT) {
59 + if (dev->battery_status != HID_BATTERY_REPORTED &&
60 + !dev->battery_avoid_query) {
61 value = hidinput_query_battery_capacity(dev);
62 if (value < 0)
63 return value;
64
65 dev->battery_capacity = value;
66 - dev->battery_reported = true;
67 + dev->battery_status = HID_BATTERY_QUERIED;
68 }
69
70 - if (!dev->battery_reported)
71 + if (dev->battery_status == HID_BATTERY_UNKNOWN)
72 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
73 else if (dev->battery_capacity == 100)
74 val->intval = POWER_SUPPLY_STATUS_FULL;
75 @@ -486,6 +487,14 @@ static int hidinput_setup_battery(struct
76 dev->battery_report_type = report_type;
77 dev->battery_report_id = field->report->id;
78
79 + /*
80 + * Stylus is normally not connected to the device and thus we
81 + * can't query the device and get meaningful battery strength.
82 + * We have to wait for the device to report it on its own.
83 + */
84 + dev->battery_avoid_query = report_type == HID_INPUT_REPORT &&
85 + field->physical == HID_DG_STYLUS;
86 +
87 dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg);
88 if (IS_ERR(dev->battery)) {
89 error = PTR_ERR(dev->battery);
90 @@ -530,9 +539,10 @@ static void hidinput_update_battery(stru
91
92 capacity = hidinput_scale_battery_capacity(dev, value);
93
94 - if (!dev->battery_reported || capacity != dev->battery_capacity) {
95 + if (dev->battery_status != HID_BATTERY_REPORTED ||
96 + capacity != dev->battery_capacity) {
97 dev->battery_capacity = capacity;
98 - dev->battery_reported = true;
99 + dev->battery_status = HID_BATTERY_REPORTED;
100 power_supply_changed(dev->battery);
101 }
102 }
103 --- a/include/linux/hid.h
104 +++ b/include/linux/hid.h
105 @@ -515,6 +515,12 @@ enum hid_type {
106 HID_TYPE_USBNONE
107 };
108
109 +enum hid_battery_status {
110 + HID_BATTERY_UNKNOWN = 0,
111 + HID_BATTERY_QUERIED, /* Kernel explicitly queried battery strength */
112 + HID_BATTERY_REPORTED, /* Device sent unsolicited battery strength report */
113 +};
114 +
115 struct hid_driver;
116 struct hid_ll_driver;
117
118 @@ -557,7 +563,8 @@ struct hid_device { /* device repo
119 __s32 battery_max;
120 __s32 battery_report_type;
121 __s32 battery_report_id;
122 - bool battery_reported;
123 + enum hid_battery_status battery_status;
124 + bool battery_avoid_query;
125 #endif
126
127 unsigned int status; /* see STAT flags above */