mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-30 15:44:13 +08:00
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:
commit
430257d832
@ -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
|
||||
|
@ -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/
|
||||
|
@ -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
|
||||
|
@ -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) },
|
||||
{ }
|
||||
|
192
drivers/hid/hid-uclogic-params-test.c
Normal file
192
drivers/hid/hid-uclogic-params-test.c
Normal 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>");
|
@ -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
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user