Skip to content

Commit a738688

Browse files
committed
Merge branch 'for-6.3/uclogic' into for-linus
UClogic assorted fixes and new devices support (José Expósito)
2 parents b838d36 + f5379a0 commit a738688

10 files changed

+339
-27
lines changed

drivers/hid/hid-ids.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,7 +1304,9 @@
13041304
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042
13051305
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01_V2 0x0905
13061306
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L 0x0935
1307+
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW 0x0934
13071308
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S 0x0909
1309+
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW 0x0933
13081310
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078
13091311
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
13101312
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071

drivers/hid/hid-input.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,10 @@ static const struct hid_device_id hid_battery_quirks[] = {
378378
HID_BATTERY_QUIRK_IGNORE },
379379
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L),
380380
HID_BATTERY_QUIRK_AVOID_QUERY },
381+
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW),
382+
HID_BATTERY_QUIRK_AVOID_QUERY },
383+
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW),
384+
HID_BATTERY_QUIRK_AVOID_QUERY },
381385
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15),
382386
HID_BATTERY_QUIRK_IGNORE },
383387
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15T_DR100),

drivers/hid/hid-uclogic-core-test.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// SPDX-License-Identifier: GPL-2.0+
2+
3+
/*
4+
* HID driver for UC-Logic devices not fully compliant with HID standard
5+
*
6+
* Copyright (c) 2022 José Expósito <[email protected]>
7+
*/
8+
9+
#include <kunit/test.h>
10+
#include "./hid-uclogic-params.h"
11+
12+
#define MAX_EVENT_SIZE 12
13+
14+
struct uclogic_raw_event_hook_test {
15+
u8 event[MAX_EVENT_SIZE];
16+
size_t size;
17+
bool expected;
18+
};
19+
20+
static struct uclogic_raw_event_hook_test hook_events[] = {
21+
{
22+
.event = { 0xA1, 0xB2, 0xC3, 0xD4 },
23+
.size = 4,
24+
},
25+
{
26+
.event = { 0x1F, 0x2E, 0x3D, 0x4C, 0x5B, 0x6A },
27+
.size = 6,
28+
},
29+
};
30+
31+
static struct uclogic_raw_event_hook_test test_events[] = {
32+
{
33+
.event = { 0xA1, 0xB2, 0xC3, 0xD4 },
34+
.size = 4,
35+
.expected = true,
36+
},
37+
{
38+
.event = { 0x1F, 0x2E, 0x3D, 0x4C, 0x5B, 0x6A },
39+
.size = 6,
40+
.expected = true,
41+
},
42+
{
43+
.event = { 0xA1, 0xB2, 0xC3 },
44+
.size = 3,
45+
.expected = false,
46+
},
47+
{
48+
.event = { 0xA1, 0xB2, 0xC3, 0xD4, 0x00 },
49+
.size = 5,
50+
.expected = false,
51+
},
52+
{
53+
.event = { 0x2E, 0x3D, 0x4C, 0x5B, 0x6A, 0x1F },
54+
.size = 6,
55+
.expected = false,
56+
},
57+
};
58+
59+
static void hid_test_uclogic_exec_event_hook_test(struct kunit *test)
60+
{
61+
struct uclogic_params p = {0, };
62+
struct uclogic_raw_event_hook *filter;
63+
bool res;
64+
int n;
65+
66+
/* Initialize the list of events to hook */
67+
p.event_hooks = kunit_kzalloc(test, sizeof(*p.event_hooks), GFP_KERNEL);
68+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, p.event_hooks);
69+
INIT_LIST_HEAD(&p.event_hooks->list);
70+
71+
for (n = 0; n < ARRAY_SIZE(hook_events); n++) {
72+
filter = kunit_kzalloc(test, sizeof(*filter), GFP_KERNEL);
73+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filter);
74+
75+
filter->size = hook_events[n].size;
76+
filter->event = kunit_kzalloc(test, filter->size, GFP_KERNEL);
77+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filter->event);
78+
memcpy(filter->event, &hook_events[n].event[0], filter->size);
79+
80+
list_add_tail(&filter->list, &p.event_hooks->list);
81+
}
82+
83+
/* Test uclogic_exec_event_hook() */
84+
for (n = 0; n < ARRAY_SIZE(test_events); n++) {
85+
res = uclogic_exec_event_hook(&p, &test_events[n].event[0],
86+
test_events[n].size);
87+
KUNIT_ASSERT_EQ(test, res, test_events[n].expected);
88+
}
89+
}
90+
91+
static struct kunit_case hid_uclogic_core_test_cases[] = {
92+
KUNIT_CASE(hid_test_uclogic_exec_event_hook_test),
93+
{}
94+
};
95+
96+
static struct kunit_suite hid_uclogic_core_test_suite = {
97+
.name = "hid_uclogic_core_test",
98+
.test_cases = hid_uclogic_core_test_cases,
99+
};
100+
101+
kunit_test_suite(hid_uclogic_core_test_suite);
102+
103+
MODULE_DESCRIPTION("KUnit tests for the UC-Logic driver");
104+
MODULE_LICENSE("GPL");
105+
MODULE_AUTHOR("José Expósito <[email protected]>");

drivers/hid/hid-uclogic-core.c

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,6 @@
2222

2323
#include "hid-ids.h"
2424

25-
/* Driver data */
26-
struct uclogic_drvdata {
27-
/* Interface parameters */
28-
struct uclogic_params params;
29-
/* Pointer to the replacement report descriptor. NULL if none. */
30-
__u8 *desc_ptr;
31-
/*
32-
* Size of the replacement report descriptor.
33-
* Only valid if desc_ptr is not NULL
34-
*/
35-
unsigned int desc_size;
36-
/* Pen input device */
37-
struct input_dev *pen_input;
38-
/* In-range timer */
39-
struct timer_list inrange_timer;
40-
/* Last rotary encoder state, or U8_MAX for none */
41-
u8 re_state;
42-
};
43-
4425
/**
4526
* uclogic_inrange_timeout - handle pen in-range state timeout.
4627
* Emulate input events normally generated when pen goes out of range for
@@ -202,6 +183,7 @@ static int uclogic_probe(struct hid_device *hdev,
202183
}
203184
timer_setup(&drvdata->inrange_timer, uclogic_inrange_timeout, 0);
204185
drvdata->re_state = U8_MAX;
186+
drvdata->quirks = id->driver_data;
205187
hid_set_drvdata(hdev, drvdata);
206188

207189
/* Initialize the device and retrieve interface parameters */
@@ -267,6 +249,34 @@ static int uclogic_resume(struct hid_device *hdev)
267249
}
268250
#endif
269251

252+
/**
253+
* uclogic_exec_event_hook - if the received event is hooked schedules the
254+
* associated work.
255+
*
256+
* @p: Tablet interface report parameters.
257+
* @event: Raw event.
258+
* @size: The size of event.
259+
*
260+
* Returns:
261+
* Whether the event was hooked or not.
262+
*/
263+
static bool uclogic_exec_event_hook(struct uclogic_params *p, u8 *event, int size)
264+
{
265+
struct uclogic_raw_event_hook *curr;
266+
267+
if (!p->event_hooks)
268+
return false;
269+
270+
list_for_each_entry(curr, &p->event_hooks->list, list) {
271+
if (curr->size == size && memcmp(curr->event, event, size) == 0) {
272+
schedule_work(&curr->work);
273+
return true;
274+
}
275+
}
276+
277+
return false;
278+
}
279+
270280
/**
271281
* uclogic_raw_event_pen - handle raw pen events (pen HID reports).
272282
*
@@ -425,6 +435,9 @@ static int uclogic_raw_event(struct hid_device *hdev,
425435
if (report->type != HID_INPUT_REPORT)
426436
return 0;
427437

438+
if (uclogic_exec_event_hook(params, data, size))
439+
return 0;
440+
428441
while (true) {
429442
/* Tweak pen reports, if necessary */
430443
if ((report_id == params->pen.id) && (size >= 2)) {
@@ -529,8 +542,14 @@ static const struct hid_device_id uclogic_devices[] = {
529542
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01_V2) },
530543
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
531544
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) },
545+
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
546+
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW),
547+
.driver_data = UCLOGIC_MOUSE_FRAME_QUIRK | UCLOGIC_BATTERY_QUIRK },
532548
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
533549
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S) },
550+
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
551+
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW),
552+
.driver_data = UCLOGIC_MOUSE_FRAME_QUIRK | UCLOGIC_BATTERY_QUIRK },
534553
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
535554
USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) },
536555
{ }
@@ -556,3 +575,7 @@ module_hid_driver(uclogic_driver);
556575
MODULE_AUTHOR("Martin Rusko");
557576
MODULE_AUTHOR("Nikolai Kondrashov");
558577
MODULE_LICENSE("GPL");
578+
579+
#ifdef CONFIG_HID_KUNIT_TEST
580+
#include "hid-uclogic-core-test.c"
581+
#endif

drivers/hid/hid-uclogic-params-test.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,25 @@ static void hid_test_uclogic_parse_ugee_v2_desc(struct kunit *test)
174174
KUNIT_EXPECT_EQ(test, params->frame_type, frame_type);
175175
}
176176

177+
static void hid_test_uclogic_params_cleanup_event_hooks(struct kunit *test)
178+
{
179+
int res, n;
180+
struct uclogic_params p = {0, };
181+
182+
res = uclogic_params_ugee_v2_init_event_hooks(NULL, &p);
183+
KUNIT_ASSERT_EQ(test, res, 0);
184+
185+
/* Check that the function can be called repeatedly */
186+
for (n = 0; n < 4; n++) {
187+
uclogic_params_cleanup_event_hooks(&p);
188+
KUNIT_EXPECT_PTR_EQ(test, p.event_hooks, NULL);
189+
}
190+
}
191+
177192
static struct kunit_case hid_uclogic_params_test_cases[] = {
178193
KUNIT_CASE_PARAM(hid_test_uclogic_parse_ugee_v2_desc,
179194
uclogic_parse_ugee_v2_desc_gen_params),
195+
KUNIT_CASE(hid_test_uclogic_params_cleanup_event_hooks),
180196
{}
181197
};
182198

0 commit comments

Comments
 (0)