Merge branch 'for-6.1/uclogic' into for-linus

- Add UGEEv2 support (XP-PEN Deco Pro S and Parblo A610 PRO) (José
  Expósito)
This commit is contained in:
Benjamin Tissoires 2022-10-05 10:34:48 +01:00
commit 430257d832
10 changed files with 500 additions and 51 deletions

View File

@ -1261,7 +1261,7 @@ config HID_MCP2221
will be called hid-mcp2221.ko.
config HID_KUNIT_TEST
bool "KUnit tests for HID" if !KUNIT_ALL_TESTS
tristate "KUnit tests for HID" if !KUNIT_ALL_TESTS
depends on KUNIT=y
depends on HID_UCLOGIC
default KUNIT_ALL_TESTS

View File

@ -147,8 +147,10 @@ obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o
obj-$(CONFIG_HID_SENSOR_CUSTOM_SENSOR) += hid-sensor-custom.o
obj-$(CONFIG_HID_KUNIT_TEST) += hid-uclogic-rdesc.o \
hid-uclogic-test-objs := hid-uclogic-rdesc.o \
hid-uclogic-params.o \
hid-uclogic-rdesc-test.o
obj-$(CONFIG_HID_KUNIT_TEST) += hid-uclogic-test.o
obj-$(CONFIG_USB_HID) += usbhid/
obj-$(CONFIG_USB_MOUSE) += usbhid/

View File

@ -1282,10 +1282,12 @@
#define USB_DEVICE_ID_YIYNOVA_TABLET 0x004d
#define USB_VENDOR_ID_UGEE 0x28bd
#define USB_DEVICE_ID_UGEE_PARBLO_A610_PRO 0x1903
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540 0x0075
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640 0x0094
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L 0x0935
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S 0x0909
#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

View File

@ -153,6 +153,7 @@ static int uclogic_input_configured(struct hid_device *hdev,
suffix = "Pad";
break;
case HID_DG_PEN:
case HID_DG_DIGITIZER:
suffix = "Pen";
break;
case HID_CP_CONSUMER_CONTROL:
@ -509,6 +510,8 @@ static const struct hid_device_id uclogic_devices[] = {
USB_DEVICE_ID_UGTIZER_TABLET_GP0610) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER,
USB_DEVICE_ID_UGTIZER_TABLET_GT5040) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_PARBLO_A610_PRO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_TABLET_G5) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
@ -523,6 +526,8 @@ static const struct hid_device_id uclogic_devices[] = {
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) },
{ 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_S) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) },
{ }

View File

@ -0,0 +1,192 @@
// 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"
#include "./hid-uclogic-rdesc.h"
#define MAX_STR_DESC_SIZE 14
struct uclogic_parse_ugee_v2_desc_case {
const char *name;
int res;
const __u8 str_desc[MAX_STR_DESC_SIZE];
size_t str_desc_size;
const s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
enum uclogic_params_frame_type frame_type;
};
static struct uclogic_parse_ugee_v2_desc_case uclogic_parse_ugee_v2_desc_cases[] = {
{
.name = "invalid_str_desc",
.res = -EINVAL,
.str_desc = {},
.str_desc_size = 0,
.desc_params = {},
.frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS,
},
{
.name = "resolution_with_value_0",
.res = 0,
.str_desc = {
0x0E, 0x03,
0x70, 0xB2,
0x10, 0x77,
0x08,
0x00,
0xFF, 0x1F,
0x00, 0x00,
},
.str_desc_size = 12,
.desc_params = {
[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xB270,
[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0,
[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x7710,
[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0,
[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF,
[UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08,
},
.frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS,
},
/* XP-PEN Deco L str_desc: Frame with 8 buttons */
{
.name = "frame_type_buttons",
.res = 0,
.str_desc = {
0x0E, 0x03,
0x70, 0xB2,
0x10, 0x77,
0x08,
0x00,
0xFF, 0x1F,
0xD8, 0x13,
},
.str_desc_size = 12,
.desc_params = {
[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xB270,
[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0x2320,
[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x7710,
[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0x1770,
[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF,
[UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08,
},
.frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS,
},
/* PARBLO A610 PRO str_desc: Frame with 9 buttons and dial */
{
.name = "frame_type_dial",
.res = 0,
.str_desc = {
0x0E, 0x03,
0x96, 0xC7,
0xF9, 0x7C,
0x09,
0x01,
0xFF, 0x1F,
0xD8, 0x13,
},
.str_desc_size = 12,
.desc_params = {
[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xC796,
[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0x2749,
[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x7CF9,
[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0x1899,
[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF,
[UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x09,
},
.frame_type = UCLOGIC_PARAMS_FRAME_DIAL,
},
/* XP-PEN Deco Pro S str_desc: Frame with 8 buttons and mouse */
{
.name = "frame_type_mouse",
.res = 0,
.str_desc = {
0x0E, 0x03,
0xC8, 0xB3,
0x34, 0x65,
0x08,
0x02,
0xFF, 0x1F,
0xD8, 0x13,
},
.str_desc_size = 12,
.desc_params = {
[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xB3C8,
[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0x2363,
[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x6534,
[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0x13EC,
[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF,
[UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08,
},
.frame_type = UCLOGIC_PARAMS_FRAME_MOUSE,
},
};
static void uclogic_parse_ugee_v2_desc_case_desc(struct uclogic_parse_ugee_v2_desc_case *t,
char *desc)
{
strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
}
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)
{
int res;
s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
enum uclogic_params_frame_type frame_type;
const struct uclogic_parse_ugee_v2_desc_case *params = test->param_value;
res = uclogic_params_parse_ugee_v2_desc(params->str_desc,
params->str_desc_size,
desc_params,
ARRAY_SIZE(desc_params),
&frame_type);
KUNIT_ASSERT_EQ(test, res, params->res);
if (res)
return;
KUNIT_EXPECT_EQ(test,
params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM],
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM]);
KUNIT_EXPECT_EQ(test,
params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM],
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM]);
KUNIT_EXPECT_EQ(test,
params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM],
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM]);
KUNIT_EXPECT_EQ(test,
params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM],
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM]);
KUNIT_EXPECT_EQ(test,
params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM],
desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM]);
KUNIT_EXPECT_EQ(test,
params->desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM],
desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM]);
KUNIT_EXPECT_EQ(test, params->frame_type, frame_type);
}
static struct kunit_case hid_uclogic_params_test_cases[] = {
KUNIT_CASE_PARAM(uclogic_parse_ugee_v2_desc_test,
uclogic_parse_ugee_v2_desc_gen_params),
{}
};
static struct kunit_suite hid_uclogic_params_test_suite = {
.name = "hid_uclogic_params_test",
.test_cases = hid_uclogic_params_test_cases,
};
kunit_test_suite(hid_uclogic_params_test_suite);
MODULE_DESCRIPTION("KUnit tests for the UC-Logic driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("José Expósito <jose.exposito89@gmail.com>");

View File

@ -1056,6 +1056,161 @@ cleanup:
return rc;
}
/**
* uclogic_params_parse_ugee_v2_desc - parse the string descriptor containing
* pen and frame parameters returned by UGEE v2 devices.
*
* @str_desc: String descriptor, cannot be NULL.
* @str_desc_size: Size of the string descriptor.
* @desc_params: Output description params list.
* @desc_params_size: Size of the output description params list.
* @frame_type: Output frame type.
*
* Returns:
* Zero, if successful. A negative errno code on error.
*/
static int uclogic_params_parse_ugee_v2_desc(const __u8 *str_desc,
size_t str_desc_size,
s32 *desc_params,
size_t desc_params_size,
enum uclogic_params_frame_type *frame_type)
{
s32 pen_x_lm, pen_y_lm;
s32 pen_x_pm, pen_y_pm;
s32 pen_pressure_lm;
s32 frame_num_buttons;
s32 resolution;
/* Minimum descriptor length required, maximum seen so far is 14 */
const int min_str_desc_size = 12;
if (!str_desc || str_desc_size < min_str_desc_size)
return -EINVAL;
if (desc_params_size != UCLOGIC_RDESC_PH_ID_NUM)
return -EINVAL;
pen_x_lm = get_unaligned_le16(str_desc + 2);
pen_y_lm = get_unaligned_le16(str_desc + 4);
frame_num_buttons = str_desc[6];
*frame_type = str_desc[7];
pen_pressure_lm = get_unaligned_le16(str_desc + 8);
resolution = get_unaligned_le16(str_desc + 10);
if (resolution == 0) {
pen_x_pm = 0;
pen_y_pm = 0;
} else {
pen_x_pm = pen_x_lm * 1000 / resolution;
pen_y_pm = pen_y_lm * 1000 / resolution;
}
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = pen_x_lm;
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = pen_x_pm;
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = pen_y_lm;
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = pen_y_pm;
desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = pen_pressure_lm;
desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM] = frame_num_buttons;
return 0;
}
/**
* uclogic_params_ugee_v2_init_frame_buttons() - initialize a UGEE v2 frame with
* buttons.
* @p: Parameters to fill in, cannot be NULL.
* @desc_params: Device description params list.
* @desc_params_size: Size of the description params list.
*
* Returns:
* Zero, if successful. A negative errno code on error.
*/
static int uclogic_params_ugee_v2_init_frame_buttons(struct uclogic_params *p,
const s32 *desc_params,
size_t desc_params_size)
{
__u8 *rdesc_frame = NULL;
int rc = 0;
if (!p || desc_params_size != UCLOGIC_RDESC_PH_ID_NUM)
return -EINVAL;
rdesc_frame = uclogic_rdesc_template_apply(
uclogic_rdesc_ugee_v2_frame_btn_template_arr,
uclogic_rdesc_ugee_v2_frame_btn_template_size,
desc_params, UCLOGIC_RDESC_PH_ID_NUM);
if (!rdesc_frame)
return -ENOMEM;
rc = uclogic_params_frame_init_with_desc(&p->frame_list[0],
rdesc_frame,
uclogic_rdesc_ugee_v2_frame_btn_template_size,
UCLOGIC_RDESC_V1_FRAME_ID);
kfree(rdesc_frame);
return rc;
}
/**
* uclogic_params_ugee_v2_init_frame_dial() - initialize a UGEE v2 frame with a
* bitmap dial.
* @p: Parameters to fill in, cannot be NULL.
* @desc_params: Device description params list.
* @desc_params_size: Size of the description params list.
*
* Returns:
* Zero, if successful. A negative errno code on error.
*/
static int uclogic_params_ugee_v2_init_frame_dial(struct uclogic_params *p,
const s32 *desc_params,
size_t desc_params_size)
{
__u8 *rdesc_frame = NULL;
int rc = 0;
if (!p || desc_params_size != UCLOGIC_RDESC_PH_ID_NUM)
return -EINVAL;
rdesc_frame = uclogic_rdesc_template_apply(
uclogic_rdesc_ugee_v2_frame_dial_template_arr,
uclogic_rdesc_ugee_v2_frame_dial_template_size,
desc_params, UCLOGIC_RDESC_PH_ID_NUM);
if (!rdesc_frame)
return -ENOMEM;
rc = uclogic_params_frame_init_with_desc(&p->frame_list[0],
rdesc_frame,
uclogic_rdesc_ugee_v2_frame_dial_template_size,
UCLOGIC_RDESC_V1_FRAME_ID);
kfree(rdesc_frame);
if (rc)
return rc;
p->frame_list[0].bitmap_dial_byte = 7;
return 0;
}
/**
* uclogic_params_ugee_v2_init_frame_mouse() - initialize a UGEE v2 frame with a
* mouse.
* @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_frame_mouse(struct uclogic_params *p)
{
int rc = 0;
if (!p)
return -EINVAL;
rc = uclogic_params_frame_init_with_desc(&p->frame_list[1],
uclogic_rdesc_ugee_v2_frame_mouse_template_arr,
uclogic_rdesc_ugee_v2_frame_mouse_template_size,
UCLOGIC_RDESC_V1_FRAME_ID);
return rc;
}
/**
* uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by
* discovering their parameters.
@ -1084,9 +1239,8 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
const int str_desc_len = 12;
__u8 *str_desc = NULL;
__u8 *rdesc_pen = NULL;
__u8 *rdesc_frame = NULL;
s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
s32 resolution;
enum uclogic_params_frame_type frame_type;
__u8 magic_arr[] = {
0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@ -1100,6 +1254,15 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
iface = to_usb_interface(hdev->dev.parent);
bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
if (bInterfaceNumber == 0) {
rc = uclogic_params_ugee_v2_init_frame_mouse(&p);
if (rc)
goto cleanup;
goto output;
}
if (bInterfaceNumber != 2) {
uclogic_params_init_invalid(&p);
goto output;
@ -1128,25 +1291,13 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
goto output;
}
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
get_unaligned_le16(str_desc + 2);
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
get_unaligned_le16(str_desc + 4);
desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM] = str_desc[6];
desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
get_unaligned_le16(str_desc + 8);
resolution = get_unaligned_le16(str_desc + 10);
if (resolution == 0) {
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
} else {
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
resolution;
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
resolution;
}
rc = uclogic_params_parse_ugee_v2_desc(str_desc, str_desc_len,
desc_params,
ARRAY_SIZE(desc_params),
&frame_type);
if (rc)
goto cleanup;
kfree(str_desc);
str_desc = NULL;
@ -1167,24 +1318,21 @@ 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 */
rdesc_frame = uclogic_rdesc_template_apply(
uclogic_rdesc_ugee_v2_frame_btn_template_arr,
uclogic_rdesc_ugee_v2_frame_btn_template_size,
desc_params, ARRAY_SIZE(desc_params));
if (!rdesc_frame) {
rc = -ENOMEM;
goto cleanup;
switch (frame_type) {
case UCLOGIC_PARAMS_FRAME_DIAL:
case UCLOGIC_PARAMS_FRAME_MOUSE:
rc = uclogic_params_ugee_v2_init_frame_dial(&p, desc_params,
ARRAY_SIZE(desc_params));
break;
case UCLOGIC_PARAMS_FRAME_BUTTONS:
default:
rc = uclogic_params_ugee_v2_init_frame_buttons(&p, desc_params,
ARRAY_SIZE(desc_params));
break;
}
rc = uclogic_params_frame_init_with_desc(&p.frame_list[0],
rdesc_frame,
uclogic_rdesc_ugee_v2_frame_btn_template_size,
UCLOGIC_RDESC_V1_FRAME_ID);
kfree(rdesc_frame);
if (rc) {
uclogic_params_init_invalid(&p);
goto output;
}
if (rc)
goto cleanup;
output:
/* Output parameters */
@ -1432,8 +1580,12 @@ int uclogic_params_init(struct uclogic_params *params,
uclogic_params_init_invalid(&p);
}
break;
case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_PARBLO_A610_PRO):
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_S):
rc = uclogic_params_ugee_v2_init(&p, hdev);
if (rc != 0)
goto cleanup;
@ -1517,3 +1669,7 @@ cleanup:
uclogic_params_cleanup(&p);
return rc;
}
#ifdef CONFIG_HID_KUNIT_TEST
#include "hid-uclogic-params-test.c"
#endif

View File

@ -29,6 +29,16 @@ enum uclogic_params_pen_inrange {
UCLOGIC_PARAMS_PEN_INRANGE_NONE,
};
/* Types of frames */
enum uclogic_params_frame_type {
/* Frame with buttons */
UCLOGIC_PARAMS_FRAME_BUTTONS = 0,
/* Frame with buttons and a dial */
UCLOGIC_PARAMS_FRAME_DIAL,
/* Frame with buttons and a mouse (shaped as a dial + touchpad) */
UCLOGIC_PARAMS_FRAME_MOUSE,
};
/*
* Pen report's subreport data.
*/

View File

@ -97,7 +97,7 @@ static const __u8 template_params_none[] = {
static struct uclogic_template_case uclogic_template_cases[] = {
{
.name = "Empty template",
.name = "empty_template",
.template = template_empty,
.template_size = sizeof(template_empty),
.param_list = params_pen_all,
@ -105,7 +105,7 @@ static struct uclogic_template_case uclogic_template_cases[] = {
.expected = template_empty,
},
{
.name = "Template smaller than the placeholder",
.name = "template_smaller_than_the_placeholder",
.template = template_small,
.template_size = sizeof(template_small),
.param_list = params_pen_all,
@ -113,7 +113,7 @@ static struct uclogic_template_case uclogic_template_cases[] = {
.expected = template_small,
},
{
.name = "No placeholder",
.name = "no_placeholder",
.template = template_no_ph,
.template_size = sizeof(template_no_ph),
.param_list = params_pen_all,
@ -121,7 +121,7 @@ static struct uclogic_template_case uclogic_template_cases[] = {
.expected = template_no_ph,
},
{
.name = "Pen placeholder at the end, without ID",
.name = "pen_placeholder_at_the_end_without_id",
.template = template_pen_ph_end,
.template_size = sizeof(template_pen_ph_end),
.param_list = params_pen_all,
@ -129,7 +129,7 @@ static struct uclogic_template_case uclogic_template_cases[] = {
.expected = template_pen_ph_end,
},
{
.name = "Frame button placeholder at the end, without ID",
.name = "frame_button_placeholder_at_the_end_without_id",
.template = template_btn_ph_end,
.template_size = sizeof(template_btn_ph_end),
.param_list = params_frame_all,
@ -137,7 +137,7 @@ static struct uclogic_template_case uclogic_template_cases[] = {
.expected = template_btn_ph_end,
},
{
.name = "All params present in the pen template",
.name = "all_params_present_in_the_pen_template",
.template = template_pen_all_params,
.template_size = sizeof(template_pen_all_params),
.param_list = params_pen_all,
@ -145,7 +145,7 @@ static struct uclogic_template_case uclogic_template_cases[] = {
.expected = expected_pen_all_params,
},
{
.name = "All params present in the frame template",
.name = "all_params_present_in_the_frame_template",
.template = template_frame_all_params,
.template_size = sizeof(template_frame_all_params),
.param_list = params_frame_all,
@ -153,7 +153,7 @@ static struct uclogic_template_case uclogic_template_cases[] = {
.expected = expected_frame_all_params,
},
{
.name = "Some params present in the pen template (complete param list)",
.name = "some_params_present_in_the_pen_template_with_complete_param_list",
.template = template_pen_some_params,
.template_size = sizeof(template_pen_some_params),
.param_list = params_pen_all,
@ -161,7 +161,7 @@ static struct uclogic_template_case uclogic_template_cases[] = {
.expected = expected_pen_some_params,
},
{
.name = "Some params present in the pen template (incomplete param list)",
.name = "some_params_present_in_the_pen_template_with_incomplete_param_list",
.template = template_pen_some_params,
.template_size = sizeof(template_pen_some_params),
.param_list = params_pen_some,
@ -169,7 +169,7 @@ static struct uclogic_template_case uclogic_template_cases[] = {
.expected = expected_pen_some_params,
},
{
.name = "No params present in the template",
.name = "no_params_present_in_the_template",
.template = template_params_none,
.template_size = sizeof(template_params_none),
.param_list = params_pen_some,
@ -208,7 +208,7 @@ static struct kunit_case hid_uclogic_rdesc_test_cases[] = {
};
static struct kunit_suite hid_uclogic_rdesc_test_suite = {
.name = "hid-uclogic-rdesc-test",
.name = "hid_uclogic_rdesc_test",
.test_cases = hid_uclogic_rdesc_test_cases,
};

View File

@ -961,6 +961,80 @@ const __u8 uclogic_rdesc_ugee_v2_frame_btn_template_arr[] = {
const size_t uclogic_rdesc_ugee_v2_frame_btn_template_size =
sizeof(uclogic_rdesc_ugee_v2_frame_btn_template_arr);
/* Fixed report descriptor template for UGEE v2 frame reports (dial) */
const __u8 uclogic_rdesc_ugee_v2_frame_dial_template_arr[] = {
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x07, /* Usage (Keypad), */
0xA1, 0x01, /* Collection (Application), */
0x85, UCLOGIC_RDESC_V1_FRAME_ID,
/* Report ID, */
0x05, 0x0D, /* Usage Page (Digitizer), */
0x09, 0x39, /* Usage (Tablet Function Keys), */
0xA0, /* Collection (Physical), */
0x75, 0x01, /* Report Size (1), */
0x95, 0x08, /* Report Count (8), */
0x81, 0x01, /* Input (Constant), */
0x05, 0x09, /* Usage Page (Button), */
0x19, 0x01, /* Usage Minimum (01h), */
UCLOGIC_RDESC_FRAME_PH_BTN,
/* Usage Maximum (PLACEHOLDER), */
0x95, 0x0A, /* Report Count (10), */
0x14, /* Logical Minimum (0), */
0x25, 0x01, /* Logical Maximum (1), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x06, /* Report Count (6), */
0x81, 0x01, /* Input (Constant), */
0x75, 0x08, /* Report Size (8), */
0x95, 0x03, /* Report Count (3), */
0x81, 0x01, /* Input (Constant), */
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x38, /* Usage (Wheel), */
0x95, 0x01, /* Report Count (1), */
0x15, 0xFF, /* Logical Minimum (-1), */
0x25, 0x01, /* Logical Maximum (1), */
0x81, 0x06, /* Input (Variable, Relative), */
0x95, 0x02, /* Report Count (2), */
0x81, 0x01, /* Input (Constant), */
0xC0, /* End Collection, */
0xC0 /* End Collection */
};
const size_t uclogic_rdesc_ugee_v2_frame_dial_template_size =
sizeof(uclogic_rdesc_ugee_v2_frame_dial_template_arr);
/* Fixed report descriptor template for UGEE v2 frame reports (mouse) */
const __u8 uclogic_rdesc_ugee_v2_frame_mouse_template_arr[] = {
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x02, /* Usage (Mouse), */
0xA1, 0x01, /* Collection (Application), */
0x85, 0x01, /* Report ID (1), */
0x05, 0x01, /* Usage Page (Pointer), */
0xA0, /* Collection (Physical), */
0x75, 0x01, /* Report Size (1), */
0x95, 0x02, /* Report Count (2), */
0x05, 0x09, /* Usage Page (Button), */
0x19, 0x01, /* Usage Minimum (01h), */
0x29, 0x02, /* Usage Maximum (02h), */
0x14, /* Logical Minimum (0), */
0x25, 0x01, /* Logical Maximum (1), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x06, /* Report Count (6), */
0x81, 0x01, /* Input (Constant), */
0x05, 0x01, /* Usage Page (Generic Desktop), */
0x09, 0x30, /* Usage (X), */
0x09, 0x31, /* Usage (Y), */
0x75, 0x10, /* Report Size (16), */
0x95, 0x02, /* Report Count (2), */
0x16, 0x00, 0x80, /* Logical Minimum (-32768), */
0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
0x81, 0x06, /* Input (Variable, Relative), */
0x95, 0x01, /* Report Count (1), */
0x81, 0x01, /* Input (Constant), */
0xC0, /* End Collection, */
0xC0 /* End Collection */
};
const size_t uclogic_rdesc_ugee_v2_frame_mouse_template_size =
sizeof(uclogic_rdesc_ugee_v2_frame_mouse_template_arr);
/* Fixed report descriptor for Ugee EX07 frame */
const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = {
0x05, 0x01, /* Usage Page (Desktop), */
@ -1113,7 +1187,7 @@ __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr,
memcmp(p, pen_head, sizeof(pen_head)) == 0 &&
p[sizeof(pen_head)] < param_num) {
v = param_list[p[sizeof(pen_head)]];
put_unaligned(cpu_to_le32(v), (s32 *)p);
put_unaligned((__force u32)cpu_to_le32(v), (s32 *)p);
p += sizeof(pen_head) + 1;
} else if (memcmp(p, btn_head, sizeof(btn_head)) == 0 &&
p[sizeof(btn_head)] < param_num) {

View File

@ -169,6 +169,14 @@ extern const size_t uclogic_rdesc_ugee_v2_pen_template_size;
extern const __u8 uclogic_rdesc_ugee_v2_frame_btn_template_arr[];
extern const size_t uclogic_rdesc_ugee_v2_frame_btn_template_size;
/* Fixed report descriptor template for UGEE v2 frame reports (dial) */
extern const __u8 uclogic_rdesc_ugee_v2_frame_dial_template_arr[];
extern const size_t uclogic_rdesc_ugee_v2_frame_dial_template_size;
/* Fixed report descriptor template for UGEE v2 frame reports (mouse) */
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 for Ugee EX07 frame */
extern const __u8 uclogic_rdesc_ugee_ex07_frame_arr[];
extern const size_t uclogic_rdesc_ugee_ex07_frame_size;