Loading drivers/hid/hid-input.c +6 −0 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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), Loading Loading @@ -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); Loading drivers/hid/hid-uclogic-params-test.c +2 −2 Original line number Diff line number Diff line Loading @@ -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]; Loading Loading @@ -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), {} }; Loading drivers/hid/hid-uclogic-params.c +73 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "usbhid/usbhid.h" #include "hid-ids.h" #include <linux/ctype.h> #include <linux/string.h> #include <asm/unaligned.h> /** Loading Loading @@ -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: '<name>' 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. Loading Loading @@ -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)); Loading drivers/hid/hid-uclogic-rdesc-test.c +2 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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), {} }; Loading drivers/hid/hid-uclogic-rdesc.c +34 −0 Original line number Diff line number Diff line Loading @@ -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), */ Loading Loading
drivers/hid/hid-input.c +6 −0 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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), Loading Loading @@ -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); Loading
drivers/hid/hid-uclogic-params-test.c +2 −2 Original line number Diff line number Diff line Loading @@ -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]; Loading Loading @@ -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), {} }; Loading
drivers/hid/hid-uclogic-params.c +73 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "usbhid/usbhid.h" #include "hid-ids.h" #include <linux/ctype.h> #include <linux/string.h> #include <asm/unaligned.h> /** Loading Loading @@ -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: '<name>' 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. Loading Loading @@ -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)); Loading
drivers/hid/hid-uclogic-rdesc-test.c +2 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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), {} }; Loading
drivers/hid/hid-uclogic-rdesc.c +34 −0 Original line number Diff line number Diff line Loading @@ -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), */ Loading