summaryrefslogtreecommitdiff
path: root/drivers/hid
diff options
context:
space:
mode:
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>2023-02-22 10:41:39 +0100
committerBenjamin Tissoires <benjamin.tissoires@redhat.com>2023-02-22 10:41:39 +0100
commita738688177dcdffe8064dc5ecac6ec4431b6b951 (patch)
treeab8ba3d7cc1db1d0c9e064bdba208879e659dc1b /drivers/hid
parentb838d36fa73c1584d814f08c3a6d4b9582418a02 (diff)
parentf5379a01d6617c887db4ba81732250725ac0bec5 (diff)
Merge branch 'for-6.3/uclogic' into for-linus
UClogic assorted fixes and new devices support (José Expósito)
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-ids.h2
-rw-r--r--drivers/hid/hid-input.c4
-rw-r--r--drivers/hid/hid-uclogic-core-test.c105
-rw-r--r--drivers/hid/hid-uclogic-core.c61
-rw-r--r--drivers/hid/hid-uclogic-params-test.c16
-rw-r--r--drivers/hid/hid-uclogic-params.c124
-rw-r--r--drivers/hid/hid-uclogic-params.h40
-rw-r--r--drivers/hid/hid-uclogic-rdesc-test.c3
-rw-r--r--drivers/hid/hid-uclogic-rdesc.c6
-rw-r--r--drivers/hid/hid-uclogic-rdesc.h5
10 files changed, 339 insertions, 27 deletions
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 61e2b463e876..63545cd307e5 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -1304,7 +1304,9 @@
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01_V2 0x0905
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L 0x0935
+#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW 0x0934
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S 0x0909
+#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW 0x0933
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 743e518b9836..7fc967964dd8 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -378,6 +378,10 @@ static const struct hid_device_id hid_battery_quirks[] = {
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_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW),
+ HID_BATTERY_QUIRK_AVOID_QUERY },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW),
+ 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),
diff --git a/drivers/hid/hid-uclogic-core-test.c b/drivers/hid/hid-uclogic-core-test.c
new file mode 100644
index 000000000000..2bb916226a38
--- /dev/null
+++ b/drivers/hid/hid-uclogic-core-test.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * HID driver for UC-Logic devices not fully compliant with HID standard
+ *
+ * Copyright (c) 2022 José Expósito <jose.exposito89@gmail.com>
+ */
+
+#include <kunit/test.h>
+#include "./hid-uclogic-params.h"
+
+#define MAX_EVENT_SIZE 12
+
+struct uclogic_raw_event_hook_test {
+ u8 event[MAX_EVENT_SIZE];
+ size_t size;
+ bool expected;
+};
+
+static struct uclogic_raw_event_hook_test hook_events[] = {
+ {
+ .event = { 0xA1, 0xB2, 0xC3, 0xD4 },
+ .size = 4,
+ },
+ {
+ .event = { 0x1F, 0x2E, 0x3D, 0x4C, 0x5B, 0x6A },
+ .size = 6,
+ },
+};
+
+static struct uclogic_raw_event_hook_test test_events[] = {
+ {
+ .event = { 0xA1, 0xB2, 0xC3, 0xD4 },
+ .size = 4,
+ .expected = true,
+ },
+ {
+ .event = { 0x1F, 0x2E, 0x3D, 0x4C, 0x5B, 0x6A },
+ .size = 6,
+ .expected = true,
+ },
+ {
+ .event = { 0xA1, 0xB2, 0xC3 },
+ .size = 3,
+ .expected = false,
+ },
+ {
+ .event = { 0xA1, 0xB2, 0xC3, 0xD4, 0x00 },
+ .size = 5,
+ .expected = false,
+ },
+ {
+ .event = { 0x2E, 0x3D, 0x4C, 0x5B, 0x6A, 0x1F },
+ .size = 6,
+ .expected = false,
+ },
+};
+
+static void hid_test_uclogic_exec_event_hook_test(struct kunit *test)
+{
+ struct uclogic_params p = {0, };
+ struct uclogic_raw_event_hook *filter;
+ bool res;
+ int n;
+
+ /* Initialize the list of events to hook */
+ p.event_hooks = kunit_kzalloc(test, sizeof(*p.event_hooks), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, p.event_hooks);
+ INIT_LIST_HEAD(&p.event_hooks->list);
+
+ for (n = 0; n < ARRAY_SIZE(hook_events); n++) {
+ filter = kunit_kzalloc(test, sizeof(*filter), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filter);
+
+ filter->size = hook_events[n].size;
+ filter->event = kunit_kzalloc(test, filter->size, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filter->event);
+ memcpy(filter->event, &hook_events[n].event[0], filter->size);
+
+ list_add_tail(&filter->list, &p.event_hooks->list);
+ }
+
+ /* Test uclogic_exec_event_hook() */
+ for (n = 0; n < ARRAY_SIZE(test_events); n++) {
+ res = uclogic_exec_event_hook(&p, &test_events[n].event[0],
+ test_events[n].size);
+ KUNIT_ASSERT_EQ(test, res, test_events[n].expected);
+ }
+}
+
+static struct kunit_case hid_uclogic_core_test_cases[] = {
+ KUNIT_CASE(hid_test_uclogic_exec_event_hook_test),
+ {}
+};
+
+static struct kunit_suite hid_uclogic_core_test_suite = {
+ .name = "hid_uclogic_core_test",
+ .test_cases = hid_uclogic_core_test_cases,
+};
+
+kunit_test_suite(hid_uclogic_core_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests for the UC-Logic driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("José Expósito <jose.exposito89@gmail.com>");
diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c
index cfbbc39807a6..f67835f9ed4c 100644
--- a/drivers/hid/hid-uclogic-core.c
+++ b/drivers/hid/hid-uclogic-core.c
@@ -22,25 +22,6 @@
#include "hid-ids.h"
-/* Driver data */
-struct uclogic_drvdata {
- /* Interface parameters */
- struct uclogic_params params;
- /* Pointer to the replacement report descriptor. NULL if none. */
- __u8 *desc_ptr;
- /*
- * Size of the replacement report descriptor.
- * Only valid if desc_ptr is not NULL
- */
- unsigned int desc_size;
- /* Pen input device */
- struct input_dev *pen_input;
- /* In-range timer */
- struct timer_list inrange_timer;
- /* Last rotary encoder state, or U8_MAX for none */
- u8 re_state;
-};
-
/**
* uclogic_inrange_timeout - handle pen in-range state timeout.
* Emulate input events normally generated when pen goes out of range for
@@ -202,6 +183,7 @@ static int uclogic_probe(struct hid_device *hdev,
}
timer_setup(&drvdata->inrange_timer, uclogic_inrange_timeout, 0);
drvdata->re_state = U8_MAX;
+ drvdata->quirks = id->driver_data;
hid_set_drvdata(hdev, drvdata);
/* Initialize the device and retrieve interface parameters */
@@ -268,6 +250,34 @@ static int uclogic_resume(struct hid_device *hdev)
#endif
/**
+ * uclogic_exec_event_hook - if the received event is hooked schedules the
+ * associated work.
+ *
+ * @p: Tablet interface report parameters.
+ * @event: Raw event.
+ * @size: The size of event.
+ *
+ * Returns:
+ * Whether the event was hooked or not.
+ */
+static bool uclogic_exec_event_hook(struct uclogic_params *p, u8 *event, int size)
+{
+ struct uclogic_raw_event_hook *curr;
+
+ if (!p->event_hooks)
+ return false;
+
+ list_for_each_entry(curr, &p->event_hooks->list, list) {
+ if (curr->size == size && memcmp(curr->event, event, size) == 0) {
+ schedule_work(&curr->work);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
* uclogic_raw_event_pen - handle raw pen events (pen HID reports).
*
* @drvdata: Driver data.
@@ -425,6 +435,9 @@ static int uclogic_raw_event(struct hid_device *hdev,
if (report->type != HID_INPUT_REPORT)
return 0;
+ if (uclogic_exec_event_hook(params, data, size))
+ return 0;
+
while (true) {
/* Tweak pen reports, if necessary */
if ((report_id == params->pen.id) && (size >= 2)) {
@@ -530,8 +543,14 @@ static const struct hid_device_id uclogic_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
+ USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW),
+ .driver_data = UCLOGIC_MOUSE_FRAME_QUIRK | UCLOGIC_BATTERY_QUIRK },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
+ USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW),
+ .driver_data = UCLOGIC_MOUSE_FRAME_QUIRK | UCLOGIC_BATTERY_QUIRK },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) },
{ }
};
@@ -556,3 +575,7 @@ module_hid_driver(uclogic_driver);
MODULE_AUTHOR("Martin Rusko");
MODULE_AUTHOR("Nikolai Kondrashov");
MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_HID_KUNIT_TEST
+#include "hid-uclogic-core-test.c"
+#endif
diff --git a/drivers/hid/hid-uclogic-params-test.c b/drivers/hid/hid-uclogic-params-test.c
index bfa7ccb7d1e8..678f50cbb160 100644
--- a/drivers/hid/hid-uclogic-params-test.c
+++ b/drivers/hid/hid-uclogic-params-test.c
@@ -174,9 +174,25 @@ static void hid_test_uclogic_parse_ugee_v2_desc(struct kunit *test)
KUNIT_EXPECT_EQ(test, params->frame_type, frame_type);
}
+static void hid_test_uclogic_params_cleanup_event_hooks(struct kunit *test)
+{
+ int res, n;
+ struct uclogic_params p = {0, };
+
+ res = uclogic_params_ugee_v2_init_event_hooks(NULL, &p);
+ KUNIT_ASSERT_EQ(test, res, 0);
+
+ /* Check that the function can be called repeatedly */
+ for (n = 0; n < 4; n++) {
+ uclogic_params_cleanup_event_hooks(&p);
+ KUNIT_EXPECT_PTR_EQ(test, p.event_hooks, NULL);
+ }
+}
+
static struct kunit_case hid_uclogic_params_test_cases[] = {
KUNIT_CASE_PARAM(hid_test_uclogic_parse_ugee_v2_desc,
uclogic_parse_ugee_v2_desc_gen_params),
+ KUNIT_CASE(hid_test_uclogic_params_cleanup_event_hooks),
{}
};
diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c
index 3c5eea3df328..9859dad36495 100644
--- a/drivers/hid/hid-uclogic-params.c
+++ b/drivers/hid/hid-uclogic-params.c
@@ -616,6 +616,31 @@ cleanup:
}
/**
+ * uclogic_params_cleanup_event_hooks - free resources used by the list of raw
+ * event hooks.
+ * Can be called repeatedly.
+ *
+ * @params: Input parameters to cleanup. Cannot be NULL.
+ */
+static void uclogic_params_cleanup_event_hooks(struct uclogic_params *params)
+{
+ struct uclogic_raw_event_hook *curr, *n;
+
+ if (!params || !params->event_hooks)
+ return;
+
+ list_for_each_entry_safe(curr, n, &params->event_hooks->list, list) {
+ cancel_work_sync(&curr->work);
+ list_del(&curr->list);
+ kfree(curr->event);
+ kfree(curr);
+ }
+
+ kfree(params->event_hooks);
+ params->event_hooks = NULL;
+}
+
+/**
* uclogic_params_cleanup - free resources used by struct uclogic_params
* (tablet interface's parameters).
* Can be called repeatedly.
@@ -631,6 +656,7 @@ void uclogic_params_cleanup(struct uclogic_params *params)
for (i = 0; i < ARRAY_SIZE(params->frame_list); i++)
uclogic_params_frame_cleanup(&params->frame_list[i]);
+ uclogic_params_cleanup_event_hooks(params);
memset(params, 0, sizeof(*params));
}
}
@@ -1021,8 +1047,8 @@ cleanup:
* Returns:
* Zero, if successful. A negative errno code on error.
*/
-static int uclogic_probe_interface(struct hid_device *hdev, u8 *magic_arr,
- int magic_size, int endpoint)
+static int uclogic_probe_interface(struct hid_device *hdev, const u8 *magic_arr,
+ size_t magic_size, int endpoint)
{
struct usb_device *udev;
unsigned int pipe = 0;
@@ -1222,6 +1248,11 @@ static int uclogic_params_ugee_v2_init_frame_mouse(struct uclogic_params *p)
*/
static bool uclogic_params_ugee_v2_has_battery(struct hid_device *hdev)
{
+ struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
+
+ if (drvdata->quirks & UCLOGIC_BATTERY_QUIRK)
+ return true;
+
/* 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
@@ -1276,6 +1307,72 @@ static int uclogic_params_ugee_v2_init_battery(struct hid_device *hdev,
}
/**
+ * uclogic_params_ugee_v2_reconnect_work() - When a wireless tablet looses
+ * connection to the USB dongle and reconnects, either because of its physical
+ * distance or because it was switches off and on using the frame's switch,
+ * uclogic_probe_interface() needs to be called again to enable the tablet.
+ *
+ * @work: The work that triggered this function.
+ */
+static void uclogic_params_ugee_v2_reconnect_work(struct work_struct *work)
+{
+ struct uclogic_raw_event_hook *event_hook;
+
+ event_hook = container_of(work, struct uclogic_raw_event_hook, work);
+ uclogic_probe_interface(event_hook->hdev, uclogic_ugee_v2_probe_arr,
+ uclogic_ugee_v2_probe_size,
+ uclogic_ugee_v2_probe_endpoint);
+}
+
+/**
+ * uclogic_params_ugee_v2_init_event_hooks() - initialize the list of events
+ * to be hooked for UGEE v2 devices.
+ * @hdev: The HID device of the tablet interface to initialize and get
+ * parameters from.
+ * @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_event_hooks(struct hid_device *hdev,
+ struct uclogic_params *p)
+{
+ struct uclogic_raw_event_hook *event_hook;
+ __u8 reconnect_event[] = {
+ /* Event received on wireless tablet reconnection */
+ 0x02, 0xF8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ if (!p)
+ return -EINVAL;
+
+ /* The reconnection event is only received if the tablet has battery */
+ if (!uclogic_params_ugee_v2_has_battery(hdev))
+ return 0;
+
+ p->event_hooks = kzalloc(sizeof(*p->event_hooks), GFP_KERNEL);
+ if (!p->event_hooks)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&p->event_hooks->list);
+
+ event_hook = kzalloc(sizeof(*event_hook), GFP_KERNEL);
+ if (!event_hook)
+ return -ENOMEM;
+
+ INIT_WORK(&event_hook->work, uclogic_params_ugee_v2_reconnect_work);
+ event_hook->hdev = hdev;
+ event_hook->size = ARRAY_SIZE(reconnect_event);
+ event_hook->event = kmemdup(reconnect_event, event_hook->size, GFP_KERNEL);
+ if (!event_hook->event)
+ return -ENOMEM;
+
+ list_add_tail(&event_hook->list, &p->event_hooks->list);
+
+ return 0;
+}
+
+/**
* uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by
* discovering their parameters.
*
@@ -1298,6 +1395,7 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
struct hid_device *hdev)
{
int rc = 0;
+ struct uclogic_drvdata *drvdata;
struct usb_interface *iface;
__u8 bInterfaceNumber;
const int str_desc_len = 12;
@@ -1305,9 +1403,6 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
__u8 *rdesc_pen = NULL;
s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
enum uclogic_params_frame_type frame_type;
- __u8 magic_arr[] = {
- 0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
/* The resulting parameters (noop) */
struct uclogic_params p = {0, };
@@ -1316,6 +1411,7 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
goto cleanup;
}
+ drvdata = hid_get_drvdata(hdev);
iface = to_usb_interface(hdev->dev.parent);
bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
@@ -1337,7 +1433,9 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
* The specific data was discovered by sniffing the Windows driver
* traffic.
*/
- rc = uclogic_probe_interface(hdev, magic_arr, sizeof(magic_arr), 0x03);
+ rc = uclogic_probe_interface(hdev, uclogic_ugee_v2_probe_arr,
+ uclogic_ugee_v2_probe_size,
+ uclogic_ugee_v2_probe_endpoint);
if (rc) {
uclogic_params_init_invalid(&p);
goto output;
@@ -1382,6 +1480,9 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID;
/* Initialize the frame interface */
+ if (drvdata->quirks & UCLOGIC_MOUSE_FRAME_QUIRK)
+ frame_type = UCLOGIC_PARAMS_FRAME_MOUSE;
+
switch (frame_type) {
case UCLOGIC_PARAMS_FRAME_DIAL:
case UCLOGIC_PARAMS_FRAME_MOUSE:
@@ -1407,6 +1508,13 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
}
}
+ /* Create a list of raw events to be ignored */
+ rc = uclogic_params_ugee_v2_init_event_hooks(hdev, &p);
+ if (rc) {
+ hid_err(hdev, "error initializing event hook list: %d\n", rc);
+ goto cleanup;
+ }
+
output:
/* Output parameters */
memcpy(params, &p, sizeof(*params));
@@ -1660,7 +1768,11 @@ int uclogic_params_init(struct uclogic_params *params,
case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L):
case VID_PID(USB_VENDOR_ID_UGEE,
+ USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW):
+ case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S):
+ case VID_PID(USB_VENDOR_ID_UGEE,
+ USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW):
rc = uclogic_params_ugee_v2_init(&p, hdev);
if (rc != 0)
goto cleanup;
diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h
index a97477c02ff8..d6ffadb2f601 100644
--- a/drivers/hid/hid-uclogic-params.h
+++ b/drivers/hid/hid-uclogic-params.h
@@ -18,6 +18,10 @@
#include <linux/usb.h>
#include <linux/hid.h>
+#include <linux/list.h>
+
+#define UCLOGIC_MOUSE_FRAME_QUIRK BIT(0)
+#define UCLOGIC_BATTERY_QUIRK BIT(1)
/* Types of pen in-range reporting */
enum uclogic_params_pen_inrange {
@@ -174,6 +178,17 @@ struct uclogic_params_frame {
};
/*
+ * List of works to be performed when a certain raw event is received.
+ */
+struct uclogic_raw_event_hook {
+ struct hid_device *hdev;
+ __u8 *event;
+ size_t size;
+ struct work_struct work;
+ struct list_head list;
+};
+
+/*
* Tablet interface report parameters.
*
* Must use declarative (descriptive) language, not imperative, to simplify
@@ -213,6 +228,31 @@ struct uclogic_params {
* parts. Only valid, if "invalid" is false.
*/
struct uclogic_params_frame frame_list[3];
+ /*
+ * List of event hooks.
+ */
+ struct uclogic_raw_event_hook *event_hooks;
+};
+
+/* Driver data */
+struct uclogic_drvdata {
+ /* Interface parameters */
+ struct uclogic_params params;
+ /* Pointer to the replacement report descriptor. NULL if none. */
+ __u8 *desc_ptr;
+ /*
+ * Size of the replacement report descriptor.
+ * Only valid if desc_ptr is not NULL
+ */
+ unsigned int desc_size;
+ /* Pen input device */
+ struct input_dev *pen_input;
+ /* In-range timer */
+ struct timer_list inrange_timer;
+ /* Last rotary encoder state, or U8_MAX for none */
+ u8 re_state;
+ /* Device quirks */
+ unsigned long quirks;
};
/* Initialize a tablet interface and discover its parameters */
diff --git a/drivers/hid/hid-uclogic-rdesc-test.c b/drivers/hid/hid-uclogic-rdesc-test.c
index b429c541bf2f..90bf4e586e01 100644
--- a/drivers/hid/hid-uclogic-rdesc-test.c
+++ b/drivers/hid/hid-uclogic-rdesc-test.c
@@ -197,8 +197,7 @@ static void hid_test_uclogic_template(struct kunit *test)
params->param_list,
params->param_num);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res);
- KUNIT_EXPECT_EQ(test, 0,
- memcmp(res, params->expected, params->template_size));
+ KUNIT_EXPECT_MEMEQ(test, res, params->expected, params->template_size);
kfree(res);
}
diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c
index fb40775f5f5b..b6dfdf6356a6 100644
--- a/drivers/hid/hid-uclogic-rdesc.c
+++ b/drivers/hid/hid-uclogic-rdesc.c
@@ -859,6 +859,12 @@ const __u8 uclogic_rdesc_v2_frame_dial_arr[] = {
const size_t uclogic_rdesc_v2_frame_dial_size =
sizeof(uclogic_rdesc_v2_frame_dial_arr);
+const __u8 uclogic_ugee_v2_probe_arr[] = {
+ 0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+const size_t uclogic_ugee_v2_probe_size = sizeof(uclogic_ugee_v2_probe_arr);
+const int uclogic_ugee_v2_probe_endpoint = 0x03;
+
/* Fixed report descriptor template for UGEE v2 pen reports */
const __u8 uclogic_rdesc_ugee_v2_pen_template_arr[] = {
0x05, 0x0d, /* Usage Page (Digitizers), */
diff --git a/drivers/hid/hid-uclogic-rdesc.h b/drivers/hid/hid-uclogic-rdesc.h
index a1f78c07293f..906d068f50a9 100644
--- a/drivers/hid/hid-uclogic-rdesc.h
+++ b/drivers/hid/hid-uclogic-rdesc.h
@@ -164,6 +164,11 @@ extern const size_t uclogic_rdesc_v2_frame_dial_size;
/* Report ID for tweaked UGEE v2 battery reports */
#define UCLOGIC_RDESC_UGEE_V2_BATTERY_ID 0xba
+/* Magic data expected by UGEEv2 devices on probe */
+extern const __u8 uclogic_ugee_v2_probe_arr[];
+extern const size_t uclogic_ugee_v2_probe_size;
+extern const int uclogic_ugee_v2_probe_endpoint;
+
/* 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;