Skip to content

Commit a608dc1

Browse files
JoseExpositoJiri Kosina
authored andcommitted
HID: input: map battery system charging
HID descriptors with Battery System (0x85) Charging (0x44) usage are ignored and POWER_SUPPLY_STATUS_DISCHARGING is always reported to user space, even when the device is charging. Map this usage and when it is reported set the right charging status. In addition, add KUnit tests to make sure that the charging status is correctly set and reported. They can be run with the usual command: $ ./tools/testing/kunit/kunit.py run --kunitconfig=drivers/hid Signed-off-by: José Expósito <jose.exposito89@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
1 parent 2043f9a commit a608dc1

File tree

5 files changed

+118
-2
lines changed

5 files changed

+118
-2
lines changed

drivers/hid/.kunitconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
CONFIG_KUNIT=y
22
CONFIG_USB=y
33
CONFIG_USB_HID=y
4+
CONFIG_HID_BATTERY_STRENGTH=y
45
CONFIG_HID_UCLOGIC=y
56
CONFIG_HID_KUNIT_TEST=y

drivers/hid/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,6 +1264,7 @@ config HID_MCP2221
12641264
config HID_KUNIT_TEST
12651265
tristate "KUnit tests for HID" if !KUNIT_ALL_TESTS
12661266
depends on KUNIT=y
1267+
depends on HID_BATTERY_STRENGTH
12671268
depends on HID_UCLOGIC
12681269
default KUNIT_ALL_TESTS
12691270
help

drivers/hid/hid-input-test.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// SPDX-License-Identifier: GPL-2.0+
2+
/*
3+
* HID to Linux Input mapping
4+
*
5+
* Copyright (c) 2022 José Expósito <jose.exposito89@gmail.com>
6+
*/
7+
8+
#include <kunit/test.h>
9+
10+
static void hid_test_input_set_battery_charge_status(struct kunit *test)
11+
{
12+
struct hid_device *dev;
13+
bool handled;
14+
15+
dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL);
16+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
17+
18+
handled = hidinput_set_battery_charge_status(dev, HID_DG_HEIGHT, 0);
19+
KUNIT_EXPECT_FALSE(test, handled);
20+
KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_UNKNOWN);
21+
22+
handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 0);
23+
KUNIT_EXPECT_TRUE(test, handled);
24+
KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_DISCHARGING);
25+
26+
handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 1);
27+
KUNIT_EXPECT_TRUE(test, handled);
28+
KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_CHARGING);
29+
}
30+
31+
static void hid_test_input_get_battery_property(struct kunit *test)
32+
{
33+
struct power_supply *psy;
34+
struct hid_device *dev;
35+
union power_supply_propval val;
36+
int ret;
37+
38+
dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL);
39+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
40+
dev->battery_avoid_query = true;
41+
42+
psy = kunit_kzalloc(test, sizeof(*psy), GFP_KERNEL);
43+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, psy);
44+
psy->drv_data = dev;
45+
46+
dev->battery_status = HID_BATTERY_UNKNOWN;
47+
dev->battery_charge_status = POWER_SUPPLY_STATUS_CHARGING;
48+
ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val);
49+
KUNIT_EXPECT_EQ(test, ret, 0);
50+
KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_UNKNOWN);
51+
52+
dev->battery_status = HID_BATTERY_REPORTED;
53+
dev->battery_charge_status = POWER_SUPPLY_STATUS_CHARGING;
54+
ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val);
55+
KUNIT_EXPECT_EQ(test, ret, 0);
56+
KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_CHARGING);
57+
58+
dev->battery_status = HID_BATTERY_REPORTED;
59+
dev->battery_charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
60+
ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val);
61+
KUNIT_EXPECT_EQ(test, ret, 0);
62+
KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_DISCHARGING);
63+
}
64+
65+
static struct kunit_case hid_input_tests[] = {
66+
KUNIT_CASE(hid_test_input_set_battery_charge_status),
67+
KUNIT_CASE(hid_test_input_get_battery_property),
68+
{ }
69+
};
70+
71+
static struct kunit_suite hid_input_test_suite = {
72+
.name = "hid_input",
73+
.test_cases = hid_input_tests,
74+
};
75+
76+
kunit_test_suite(hid_input_test_suite);
77+
78+
MODULE_DESCRIPTION("HID input KUnit tests");
79+
MODULE_LICENSE("GPL");
80+
MODULE_AUTHOR("José Expósito <jose.exposito89@gmail.com>");

drivers/hid/hid-input.c

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ static int hidinput_get_battery_property(struct power_supply *psy,
480480
if (dev->battery_status == HID_BATTERY_UNKNOWN)
481481
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
482482
else
483-
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
483+
val->intval = dev->battery_charge_status;
484484
break;
485485

486486
case POWER_SUPPLY_PROP_SCOPE:
@@ -548,6 +548,7 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
548548
dev->battery_max = max;
549549
dev->battery_report_type = report_type;
550550
dev->battery_report_id = field->report->id;
551+
dev->battery_charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
551552

552553
/*
553554
* Stylus is normally not connected to the device and thus we
@@ -614,6 +615,20 @@ static void hidinput_update_battery(struct hid_device *dev, int value)
614615
power_supply_changed(dev->battery);
615616
}
616617
}
618+
619+
static bool hidinput_set_battery_charge_status(struct hid_device *dev,
620+
unsigned int usage, int value)
621+
{
622+
switch (usage) {
623+
case HID_BAT_CHARGING:
624+
dev->battery_charge_status = value ?
625+
POWER_SUPPLY_STATUS_CHARGING :
626+
POWER_SUPPLY_STATUS_DISCHARGING;
627+
return true;
628+
}
629+
630+
return false;
631+
}
617632
#else /* !CONFIG_HID_BATTERY_STRENGTH */
618633
static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
619634
struct hid_field *field, bool is_percentage)
@@ -628,6 +643,12 @@ static void hidinput_cleanup_battery(struct hid_device *dev)
628643
static void hidinput_update_battery(struct hid_device *dev, int value)
629644
{
630645
}
646+
647+
static bool hidinput_set_battery_charge_status(struct hid_device *dev,
648+
unsigned int usage, int value)
649+
{
650+
return false;
651+
}
631652
#endif /* CONFIG_HID_BATTERY_STRENGTH */
632653

633654
static bool hidinput_field_in_collection(struct hid_device *device, struct hid_field *field,
@@ -1217,6 +1238,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
12171238
hidinput_setup_battery(device, HID_INPUT_REPORT, field, true);
12181239
usage->type = EV_PWR;
12191240
return;
1241+
case HID_BAT_CHARGING:
1242+
usage->type = EV_PWR;
1243+
return;
12201244
}
12211245
goto unknown;
12221246

@@ -1459,7 +1483,11 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
14591483
return;
14601484

14611485
if (usage->type == EV_PWR) {
1462-
hidinput_update_battery(hid, value);
1486+
bool handled = hidinput_set_battery_charge_status(hid, usage->hid, value);
1487+
1488+
if (!handled)
1489+
hidinput_update_battery(hid, value);
1490+
14631491
return;
14641492
}
14651493

@@ -2315,3 +2343,7 @@ void hidinput_disconnect(struct hid_device *hid)
23152343
cancel_work_sync(&hid->led_work);
23162344
}
23172345
EXPORT_SYMBOL_GPL(hidinput_disconnect);
2346+
2347+
#ifdef CONFIG_HID_KUNIT_TEST
2348+
#include "hid-input-test.c"
2349+
#endif

include/linux/hid.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ struct hid_item {
312312
#define HID_DG_LATENCYMODE 0x000d0060
313313

314314
#define HID_BAT_ABSOLUTESTATEOFCHARGE 0x00850065
315+
#define HID_BAT_CHARGING 0x00850044
315316

316317
#define HID_VD_ASUS_CUSTOM_MEDIA_KEYS 0xff310076
317318

@@ -611,6 +612,7 @@ struct hid_device { /* device report descriptor */
611612
__s32 battery_max;
612613
__s32 battery_report_type;
613614
__s32 battery_report_id;
615+
__s32 battery_charge_status;
614616
enum hid_battery_status battery_status;
615617
bool battery_avoid_query;
616618
ktime_t battery_ratelimit_time;

0 commit comments

Comments
 (0)