From 037c1aaeb96fe5f778026f4c1ef28b26cf600bfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Sat, 29 Oct 2022 18:12:39 +0200 Subject: [PATCH 1/3] HID: input: do not query XP-PEN Deco LW battery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The XP-PEN Deco LW drawing tablet can be connected by USB cable or using a USB Bluetooth dongle. When it is connected using the dongle, there might be a small delay until the tablet is paired with the dongle. Fetching the device battery during this delay results in random battery percentage values. Add a quirk to avoid actively querying the battery percentage and wait for the device to report it on its own. Reported-by: Mia Kanashi Tested-by: Mia Kanashi Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 859aeb07542e3..d728a94c642eb 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -340,6 +340,7 @@ static enum power_supply_property hidinput_battery_props[] = { #define HID_BATTERY_QUIRK_PERCENT (1 << 0) /* always reports percent */ #define HID_BATTERY_QUIRK_FEATURE (1 << 1) /* ask for feature report */ #define HID_BATTERY_QUIRK_IGNORE (1 << 2) /* completely ignore the battery */ +#define HID_BATTERY_QUIRK_AVOID_QUERY (1 << 3) /* do not query the battery */ static const struct hid_device_id hid_battery_quirks[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, @@ -373,6 +374,8 @@ static const struct hid_device_id hid_battery_quirks[] = { HID_BATTERY_QUIRK_IGNORE }, { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN), HID_BATTERY_QUIRK_IGNORE }, + { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L), + HID_BATTERY_QUIRK_AVOID_QUERY }, { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15), HID_BATTERY_QUIRK_IGNORE }, { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15T_DR100), @@ -554,6 +557,9 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type, dev->battery_avoid_query = report_type == HID_INPUT_REPORT && field->physical == HID_DG_STYLUS; + if (quirks & HID_BATTERY_QUIRK_AVOID_QUERY) + dev->battery_avoid_query = true; + dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg); if (IS_ERR(dev->battery)) { error = PTR_ERR(dev->battery); From f9ce4db0ec2b6301f4264ba8627863e2632c922b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Sat, 29 Oct 2022 18:12:40 +0200 Subject: [PATCH 2/3] HID: uclogic: Add support for XP-PEN Deco LW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The XP-PEN Deco LW is a UGEE v2 device with a frame with 8 buttons. Its pen has 2 buttons, supports tilt and pressure. It can be connected by USB cable or using a USB Bluetooth dongle to use it in wireless mode. When it is connected using the dongle, the device battery is used to power it. Its vendor, product and version are identical to the Deco L. The only difference reported by its firmware is the product name. In order to add support for battery reporting, add a new HID descriptor and a quirk to detect the wireless version of the tablet. Link: https://github.com/DIGImend/digimend-kernel-drivers/issues/635 Tested-by: Mia Kanashi Tested-by: Andreas Grosse Tested-by: Mia Kanashi Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.c | 73 ++++++++++++++++++++++++++++++++ drivers/hid/hid-uclogic-rdesc.c | 34 +++++++++++++++ drivers/hid/hid-uclogic-rdesc.h | 7 +++ 3 files changed, 114 insertions(+) diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 34fa991e6267e..cd1233d7e2535 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -18,6 +18,7 @@ #include "usbhid/usbhid.h" #include "hid-ids.h" #include +#include #include /** @@ -1211,6 +1212,69 @@ static int uclogic_params_ugee_v2_init_frame_mouse(struct uclogic_params *p) return rc; } +/** + * uclogic_params_ugee_v2_has_battery() - check whether a UGEE v2 device has + * battery or not. + * @hdev: The HID device of the tablet interface. + * + * Returns: + * True if the device has battery, false otherwise. + */ +static bool uclogic_params_ugee_v2_has_battery(struct hid_device *hdev) +{ + /* The XP-PEN Deco LW vendor, product and version are identical to the + * Deco L. The only difference reported by their firmware is the product + * name. Add a quirk to support battery reporting on the wireless + * version. + */ + if (hdev->vendor == USB_VENDOR_ID_UGEE && + hdev->product == USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) { + struct usb_device *udev = hid_to_usb_dev(hdev); + + if (strstarts(udev->product, "Deco LW")) + return true; + } + + return false; +} + +/** + * uclogic_params_ugee_v2_init_battery() - initialize UGEE v2 battery reporting. + * @hdev: The HID device of the tablet interface, cannot be NULL. + * @p: Parameters to fill in, cannot be NULL. + * + * Returns: + * Zero, if successful. A negative errno code on error. + */ +static int uclogic_params_ugee_v2_init_battery(struct hid_device *hdev, + struct uclogic_params *p) +{ + int rc = 0; + + if (!hdev || !p) + return -EINVAL; + + /* Some tablets contain invalid characters in hdev->uniq, throwing a + * "hwmon: '' is not a valid name attribute, please fix" error. + * Use the device vendor and product IDs instead. + */ + snprintf(hdev->uniq, sizeof(hdev->uniq), "%x-%x", hdev->vendor, + hdev->product); + + rc = uclogic_params_frame_init_with_desc(&p->frame_list[1], + uclogic_rdesc_ugee_v2_battery_template_arr, + uclogic_rdesc_ugee_v2_battery_template_size, + UCLOGIC_RDESC_UGEE_V2_BATTERY_ID); + if (rc) + return rc; + + p->frame_list[1].suffix = "Battery"; + p->pen.subreport_list[1].value = 0xf2; + p->pen.subreport_list[1].id = UCLOGIC_RDESC_UGEE_V2_BATTERY_ID; + + return rc; +} + /** * uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by * discovering their parameters. @@ -1334,6 +1398,15 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params, if (rc) goto cleanup; + /* Initialize the battery interface*/ + if (uclogic_params_ugee_v2_has_battery(hdev)) { + rc = uclogic_params_ugee_v2_init_battery(hdev, &p); + if (rc) { + hid_err(hdev, "error initializing battery: %d\n", rc); + goto cleanup; + } + } + output: /* Output parameters */ memcpy(params, &p, sizeof(*params)); diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c index 4bd54c4fb5b0b..6524b4b61b25c 100644 --- a/drivers/hid/hid-uclogic-rdesc.c +++ b/drivers/hid/hid-uclogic-rdesc.c @@ -1035,6 +1035,40 @@ const __u8 uclogic_rdesc_ugee_v2_frame_mouse_template_arr[] = { const size_t uclogic_rdesc_ugee_v2_frame_mouse_template_size = sizeof(uclogic_rdesc_ugee_v2_frame_mouse_template_arr); +/* Fixed report descriptor template for UGEE v2 battery reports */ +const __u8 uclogic_rdesc_ugee_v2_battery_template_arr[] = { + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x07, /* Usage (Keypad), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, UCLOGIC_RDESC_UGEE_V2_BATTERY_ID, + /* Report ID, */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x02, /* Report Count (2), */ + 0x81, 0x01, /* Input (Constant), */ + 0x05, 0x84, /* Usage Page (Power Device), */ + 0x05, 0x85, /* Usage Page (Battery System), */ + 0x09, 0x65, /* Usage Page (AbsoluteStateOfCharge), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x01, /* Report Count (1), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x26, 0xff, 0x00, /* Logical Maximum (255), */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x01, /* Report Count (1), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x09, 0x44, /* Usage Page (Charging), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x07, /* Report Count (7), */ + 0x81, 0x01, /* Input (Constant), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x07, /* Report Count (7), */ + 0x81, 0x01, /* Input (Constant), */ + 0xC0 /* End Collection */ +}; +const size_t uclogic_rdesc_ugee_v2_battery_template_size = + sizeof(uclogic_rdesc_ugee_v2_battery_template_arr); + /* Fixed report descriptor for Ugee EX07 frame */ const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = { 0x05, 0x01, /* Usage Page (Desktop), */ diff --git a/drivers/hid/hid-uclogic-rdesc.h b/drivers/hid/hid-uclogic-rdesc.h index 0502a06564964..a1f78c07293ff 100644 --- a/drivers/hid/hid-uclogic-rdesc.h +++ b/drivers/hid/hid-uclogic-rdesc.h @@ -161,6 +161,9 @@ extern const size_t uclogic_rdesc_v2_frame_dial_size; /* Device ID byte offset in v2 frame dial reports */ #define UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE 0x4 +/* Report ID for tweaked UGEE v2 battery reports */ +#define UCLOGIC_RDESC_UGEE_V2_BATTERY_ID 0xba + /* Fixed report descriptor template for UGEE v2 pen reports */ extern const __u8 uclogic_rdesc_ugee_v2_pen_template_arr[]; extern const size_t uclogic_rdesc_ugee_v2_pen_template_size; @@ -177,6 +180,10 @@ extern const size_t uclogic_rdesc_ugee_v2_frame_dial_template_size; extern const __u8 uclogic_rdesc_ugee_v2_frame_mouse_template_arr[]; extern const size_t uclogic_rdesc_ugee_v2_frame_mouse_template_size; +/* Fixed report descriptor template for UGEE v2 battery reports */ +extern const __u8 uclogic_rdesc_ugee_v2_battery_template_arr[]; +extern const size_t uclogic_rdesc_ugee_v2_battery_template_size; + /* Fixed report descriptor for Ugee EX07 frame */ extern const __u8 uclogic_rdesc_ugee_ex07_frame_arr[]; extern const size_t uclogic_rdesc_ugee_ex07_frame_size; From af89dfde2a5f8b9d2489813f0ec575d0457ad902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Thu, 10 Nov 2022 18:49:55 +0100 Subject: [PATCH 3/3] HID: uclogic: Standardize test name prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 961bcdf956a4 ("drm/tests: Change "igt_" prefix to "drm_test_"") introduced a new naming convention for the KUnit tests present in the DRM subsystem: "drm_test__". This naming convention is very convenient because it allows to easily run all subsystem tests or all driver tests using kunit.py's wildcards. Follow the naming conventions used in the DRM subsystem adapted to the HID subsystem: "hid_test__". Signed-off-by: José Expósito Reviewed-by: Maíra Canal Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params-test.c | 4 ++-- drivers/hid/hid-uclogic-rdesc-test.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-uclogic-params-test.c b/drivers/hid/hid-uclogic-params-test.c index 57ef5d3e4b74c..bfa7ccb7d1e8b 100644 --- a/drivers/hid/hid-uclogic-params-test.c +++ b/drivers/hid/hid-uclogic-params-test.c @@ -136,7 +136,7 @@ static void uclogic_parse_ugee_v2_desc_case_desc(struct uclogic_parse_ugee_v2_de KUNIT_ARRAY_PARAM(uclogic_parse_ugee_v2_desc, uclogic_parse_ugee_v2_desc_cases, uclogic_parse_ugee_v2_desc_case_desc); -static void uclogic_parse_ugee_v2_desc_test(struct kunit *test) +static void hid_test_uclogic_parse_ugee_v2_desc(struct kunit *test) { int res; s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; @@ -175,7 +175,7 @@ static void uclogic_parse_ugee_v2_desc_test(struct kunit *test) } static struct kunit_case hid_uclogic_params_test_cases[] = { - KUNIT_CASE_PARAM(uclogic_parse_ugee_v2_desc_test, + KUNIT_CASE_PARAM(hid_test_uclogic_parse_ugee_v2_desc, uclogic_parse_ugee_v2_desc_gen_params), {} }; diff --git a/drivers/hid/hid-uclogic-rdesc-test.c b/drivers/hid/hid-uclogic-rdesc-test.c index 3971a0854c3e1..b429c541bf2f7 100644 --- a/drivers/hid/hid-uclogic-rdesc-test.c +++ b/drivers/hid/hid-uclogic-rdesc-test.c @@ -187,7 +187,7 @@ static void uclogic_template_case_desc(struct uclogic_template_case *t, KUNIT_ARRAY_PARAM(uclogic_template, uclogic_template_cases, uclogic_template_case_desc); -static void uclogic_template_test(struct kunit *test) +static void hid_test_uclogic_template(struct kunit *test) { __u8 *res; const struct uclogic_template_case *params = test->param_value; @@ -203,7 +203,7 @@ static void uclogic_template_test(struct kunit *test) } static struct kunit_case hid_uclogic_rdesc_test_cases[] = { - KUNIT_CASE_PARAM(uclogic_template_test, uclogic_template_gen_params), + KUNIT_CASE_PARAM(hid_test_uclogic_template, uclogic_template_gen_params), {} };