mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-03-19 05:24:11 +00:00
Merge branch 'for-5.20/uclogic' into for-linus
- XP-PEN Deco L support (José Expósito)
This commit is contained in:
commit
a60885b6a9
9 changed files with 581 additions and 14 deletions
5
drivers/hid/.kunitconfig
Normal file
5
drivers/hid/.kunitconfig
Normal file
|
@ -0,0 +1,5 @@
|
|||
CONFIG_KUNIT=y
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_HID=y
|
||||
CONFIG_HID_UCLOGIC=y
|
||||
CONFIG_HID_KUNIT_TEST=y
|
|
@ -1306,6 +1306,22 @@ config HID_MCP2221
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called hid-mcp2221.ko.
|
||||
|
||||
config HID_KUNIT_TEST
|
||||
bool "KUnit tests for HID" if !KUNIT_ALL_TESTS
|
||||
depends on KUNIT=y
|
||||
depends on HID_UCLOGIC
|
||||
default KUNIT_ALL_TESTS
|
||||
help
|
||||
This builds unit tests for HID. This option is not useful for
|
||||
distributions or general kernels, but only for kernel
|
||||
developers working on HID and associated drivers.
|
||||
|
||||
For more information on KUnit and unit tests in general,
|
||||
please refer to the KUnit documentation in
|
||||
Documentation/dev-tools/kunit/.
|
||||
|
||||
If in doubt, say "N".
|
||||
|
||||
endmenu
|
||||
|
||||
endif # HID
|
||||
|
|
|
@ -144,6 +144,9 @@ 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-rdesc-test.o
|
||||
|
||||
obj-$(CONFIG_USB_HID) += usbhid/
|
||||
obj-$(CONFIG_USB_MOUSE) += usbhid/
|
||||
obj-$(CONFIG_USB_KBD) += usbhid/
|
||||
|
|
|
@ -1279,6 +1279,7 @@
|
|||
#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_STAR06 0x0078
|
||||
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
|
||||
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
|
||||
|
|
|
@ -521,6 +521,8 @@ static const struct hid_device_id uclogic_devices[] = {
|
|||
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
||||
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_STAR06) },
|
||||
{ }
|
||||
|
|
|
@ -238,7 +238,7 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
|
|||
const int len = 12;
|
||||
s32 resolution;
|
||||
/* Pen report descriptor template parameters */
|
||||
s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
|
||||
s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
|
||||
__u8 *desc_ptr = NULL;
|
||||
|
||||
/* Check arguments */
|
||||
|
@ -383,7 +383,7 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
|
|||
size_t i;
|
||||
s32 resolution;
|
||||
/* Pen report descriptor template parameters */
|
||||
s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
|
||||
s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
|
||||
__u8 *desc_ptr = NULL;
|
||||
|
||||
/* Check arguments */
|
||||
|
@ -1006,6 +1006,197 @@ cleanup:
|
|||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* uclogic_probe_interface() - some tablets, like the Parblo A610 PLUS V2 or
|
||||
* the XP-PEN Deco Mini 7, need to be initialized by sending them magic data.
|
||||
*
|
||||
* @hdev: The HID device of the tablet interface to initialize and get
|
||||
* parameters from. Cannot be NULL.
|
||||
* @magic_arr: The magic data that should be sent to probe the interface.
|
||||
* Cannot be NULL.
|
||||
* @magic_size: Size of the magic data.
|
||||
* @endpoint: Endpoint where the magic data should be sent.
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
struct usb_device *udev;
|
||||
unsigned int pipe = 0;
|
||||
int sent;
|
||||
u8 *buf = NULL;
|
||||
int rc = 0;
|
||||
|
||||
if (!hdev || !magic_arr) {
|
||||
rc = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
buf = kmemdup(magic_arr, magic_size, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
rc = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
udev = hid_to_usb_dev(hdev);
|
||||
pipe = usb_sndintpipe(udev, endpoint);
|
||||
|
||||
rc = usb_interrupt_msg(udev, pipe, buf, magic_size, &sent, 1000);
|
||||
if (rc || sent != magic_size) {
|
||||
hid_err(hdev, "Interface probing failed: %d\n", rc);
|
||||
rc = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
cleanup:
|
||||
kfree(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by
|
||||
* discovering their parameters.
|
||||
*
|
||||
* These tables, internally designed as v2 to differentiate them from older
|
||||
* models, expect a payload of magic data in orther to be switched to the fully
|
||||
* functional mode and expose their parameters in a similar way to the
|
||||
* information present in uclogic_params_pen_init_v1() but with some
|
||||
* differences.
|
||||
*
|
||||
* @params: Parameters to fill in (to be cleaned with
|
||||
* uclogic_params_cleanup()). Not modified in case of error.
|
||||
* Cannot be NULL.
|
||||
* @hdev: The HID device of the tablet interface to initialize and get
|
||||
* parameters from. Cannot be NULL.
|
||||
*
|
||||
* Returns:
|
||||
* Zero, if successful. A negative errno code on error.
|
||||
*/
|
||||
static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
|
||||
struct hid_device *hdev)
|
||||
{
|
||||
int rc = 0;
|
||||
struct usb_interface *iface;
|
||||
__u8 bInterfaceNumber;
|
||||
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;
|
||||
__u8 magic_arr[] = {
|
||||
0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
/* The resulting parameters (noop) */
|
||||
struct uclogic_params p = {0, };
|
||||
|
||||
if (!params || !hdev) {
|
||||
rc = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
iface = to_usb_interface(hdev->dev.parent);
|
||||
bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
|
||||
if (bInterfaceNumber != 2) {
|
||||
uclogic_params_init_invalid(&p);
|
||||
goto output;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the interface by sending magic data.
|
||||
* The specific data was discovered by sniffing the Windows driver
|
||||
* traffic.
|
||||
*/
|
||||
rc = uclogic_probe_interface(hdev, magic_arr, sizeof(magic_arr), 0x03);
|
||||
if (rc) {
|
||||
uclogic_params_init_invalid(&p);
|
||||
goto output;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the string descriptor containing pen and frame parameters.
|
||||
* The specific string descriptor and data were discovered by sniffing
|
||||
* the Windows driver traffic.
|
||||
*/
|
||||
rc = uclogic_params_get_str_desc(&str_desc, hdev, 100, str_desc_len);
|
||||
if (rc != str_desc_len) {
|
||||
hid_err(hdev, "failed retrieving pen and frame parameters: %d\n", rc);
|
||||
uclogic_params_init_invalid(&p);
|
||||
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;
|
||||
}
|
||||
kfree(str_desc);
|
||||
str_desc = NULL;
|
||||
|
||||
/* Initialize the pen interface */
|
||||
rdesc_pen = uclogic_rdesc_template_apply(
|
||||
uclogic_rdesc_ugee_v2_pen_template_arr,
|
||||
uclogic_rdesc_ugee_v2_pen_template_size,
|
||||
desc_params, ARRAY_SIZE(desc_params));
|
||||
if (!rdesc_pen) {
|
||||
rc = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
p.pen.desc_ptr = rdesc_pen;
|
||||
p.pen.desc_size = uclogic_rdesc_ugee_v2_pen_template_size;
|
||||
p.pen.id = 0x02;
|
||||
p.pen.subreport_list[0].value = 0xf0;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
output:
|
||||
/* Output parameters */
|
||||
memcpy(params, &p, sizeof(*params));
|
||||
memset(&p, 0, sizeof(p));
|
||||
rc = 0;
|
||||
cleanup:
|
||||
kfree(str_desc);
|
||||
uclogic_params_cleanup(&p);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* uclogic_params_init() - initialize a tablet interface and discover its
|
||||
* parameters.
|
||||
|
@ -1241,6 +1432,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_XPPEN_TABLET_DECO_L):
|
||||
rc = uclogic_params_ugee_v2_init(&p, hdev);
|
||||
if (rc != 0)
|
||||
goto cleanup;
|
||||
break;
|
||||
case VID_PID(USB_VENDOR_ID_TRUST,
|
||||
USB_DEVICE_ID_TRUST_PANORA_TABLET):
|
||||
case VID_PID(USB_VENDOR_ID_UGEE,
|
||||
|
|
219
drivers/hid/hid-uclogic-rdesc-test.c
Normal file
219
drivers/hid/hid-uclogic-rdesc-test.c
Normal file
|
@ -0,0 +1,219 @@
|
|||
// 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-rdesc.h"
|
||||
|
||||
struct uclogic_template_case {
|
||||
const char *name;
|
||||
const __u8 *template;
|
||||
size_t template_size;
|
||||
const s32 *param_list;
|
||||
size_t param_num;
|
||||
const __u8 *expected;
|
||||
};
|
||||
|
||||
static const s32 params_pen_all[UCLOGIC_RDESC_PH_ID_NUM] = {
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xAA,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0xBB,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0xCC,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0xDD,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0xEE,
|
||||
};
|
||||
|
||||
static const s32 params_pen_some[] = {
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xAA,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0xBB,
|
||||
};
|
||||
|
||||
static const s32 params_frame_all[UCLOGIC_RDESC_PH_ID_NUM] = {
|
||||
[UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0xFF,
|
||||
};
|
||||
|
||||
static const __u8 template_empty[] = { };
|
||||
static const __u8 template_small[] = { 0x00 };
|
||||
static const __u8 template_no_ph[] = { 0xAA, 0xFE, 0xAA, 0xED, 0x1D };
|
||||
|
||||
static const __u8 template_pen_ph_end[] = {
|
||||
0xAA, 0xBB, UCLOGIC_RDESC_PEN_PH_HEAD
|
||||
};
|
||||
|
||||
static const __u8 template_btn_ph_end[] = {
|
||||
0xAA, 0xBB, UCLOGIC_RDESC_FRAME_PH_BTN_HEAD
|
||||
};
|
||||
|
||||
static const __u8 template_pen_all_params[] = {
|
||||
UCLOGIC_RDESC_PEN_PH(X_LM),
|
||||
0x47, UCLOGIC_RDESC_PEN_PH(X_PM),
|
||||
0x27, UCLOGIC_RDESC_PEN_PH(Y_LM),
|
||||
UCLOGIC_RDESC_PEN_PH(Y_PM),
|
||||
0x00, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM),
|
||||
};
|
||||
|
||||
static const __u8 expected_pen_all_params[] = {
|
||||
0xAA, 0x00, 0x00, 0x00,
|
||||
0x47, 0xBB, 0x00, 0x00, 0x00,
|
||||
0x27, 0xCC, 0x00, 0x00, 0x00,
|
||||
0xDD, 0x00, 0x00, 0x00,
|
||||
0x00, 0xEE, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static const __u8 template_frame_all_params[] = {
|
||||
0x01, 0x02,
|
||||
UCLOGIC_RDESC_FRAME_PH_BTN,
|
||||
0x99,
|
||||
};
|
||||
|
||||
static const __u8 expected_frame_all_params[] = {
|
||||
0x01, 0x02,
|
||||
0x2A, 0xFF, 0x00,
|
||||
0x99,
|
||||
};
|
||||
|
||||
static const __u8 template_pen_some_params[] = {
|
||||
0x01, 0x02,
|
||||
UCLOGIC_RDESC_PEN_PH(X_LM),
|
||||
0x03, UCLOGIC_RDESC_PEN_PH(X_PM),
|
||||
0x04, 0x05,
|
||||
};
|
||||
|
||||
static const __u8 expected_pen_some_params[] = {
|
||||
0x01, 0x02,
|
||||
0xAA, 0x00, 0x00, 0x00,
|
||||
0x03, 0xBB, 0x00, 0x00, 0x00,
|
||||
0x04, 0x05,
|
||||
};
|
||||
|
||||
static const __u8 template_params_none[] = {
|
||||
0x27, UCLOGIC_RDESC_PEN_PH(Y_LM),
|
||||
UCLOGIC_RDESC_PEN_PH(Y_PM),
|
||||
0x00, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM),
|
||||
};
|
||||
|
||||
static struct uclogic_template_case uclogic_template_cases[] = {
|
||||
{
|
||||
.name = "Empty template",
|
||||
.template = template_empty,
|
||||
.template_size = sizeof(template_empty),
|
||||
.param_list = params_pen_all,
|
||||
.param_num = ARRAY_SIZE(params_pen_all),
|
||||
.expected = template_empty,
|
||||
},
|
||||
{
|
||||
.name = "Template smaller than the placeholder",
|
||||
.template = template_small,
|
||||
.template_size = sizeof(template_small),
|
||||
.param_list = params_pen_all,
|
||||
.param_num = ARRAY_SIZE(params_pen_all),
|
||||
.expected = template_small,
|
||||
},
|
||||
{
|
||||
.name = "No placeholder",
|
||||
.template = template_no_ph,
|
||||
.template_size = sizeof(template_no_ph),
|
||||
.param_list = params_pen_all,
|
||||
.param_num = ARRAY_SIZE(params_pen_all),
|
||||
.expected = template_no_ph,
|
||||
},
|
||||
{
|
||||
.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,
|
||||
.param_num = ARRAY_SIZE(params_pen_all),
|
||||
.expected = template_pen_ph_end,
|
||||
},
|
||||
{
|
||||
.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,
|
||||
.param_num = ARRAY_SIZE(params_frame_all),
|
||||
.expected = template_btn_ph_end,
|
||||
},
|
||||
{
|
||||
.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,
|
||||
.param_num = ARRAY_SIZE(params_pen_all),
|
||||
.expected = expected_pen_all_params,
|
||||
},
|
||||
{
|
||||
.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,
|
||||
.param_num = ARRAY_SIZE(params_frame_all),
|
||||
.expected = expected_frame_all_params,
|
||||
},
|
||||
{
|
||||
.name = "Some params present in the pen template (complete param list)",
|
||||
.template = template_pen_some_params,
|
||||
.template_size = sizeof(template_pen_some_params),
|
||||
.param_list = params_pen_all,
|
||||
.param_num = ARRAY_SIZE(params_pen_all),
|
||||
.expected = expected_pen_some_params,
|
||||
},
|
||||
{
|
||||
.name = "Some params present in the pen template (incomplete param list)",
|
||||
.template = template_pen_some_params,
|
||||
.template_size = sizeof(template_pen_some_params),
|
||||
.param_list = params_pen_some,
|
||||
.param_num = ARRAY_SIZE(params_pen_some),
|
||||
.expected = expected_pen_some_params,
|
||||
},
|
||||
{
|
||||
.name = "No params present in the template",
|
||||
.template = template_params_none,
|
||||
.template_size = sizeof(template_params_none),
|
||||
.param_list = params_pen_some,
|
||||
.param_num = ARRAY_SIZE(params_pen_some),
|
||||
.expected = template_params_none,
|
||||
},
|
||||
};
|
||||
|
||||
static void uclogic_template_case_desc(struct uclogic_template_case *t,
|
||||
char *desc)
|
||||
{
|
||||
strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
|
||||
}
|
||||
|
||||
KUNIT_ARRAY_PARAM(uclogic_template, uclogic_template_cases,
|
||||
uclogic_template_case_desc);
|
||||
|
||||
static void uclogic_template_test(struct kunit *test)
|
||||
{
|
||||
__u8 *res;
|
||||
const struct uclogic_template_case *params = test->param_value;
|
||||
|
||||
res = uclogic_rdesc_template_apply(params->template,
|
||||
params->template_size,
|
||||
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));
|
||||
kfree(res);
|
||||
}
|
||||
|
||||
static struct kunit_case hid_uclogic_rdesc_test_cases[] = {
|
||||
KUNIT_CASE_PARAM(uclogic_template_test, uclogic_template_gen_params),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite hid_uclogic_rdesc_test_suite = {
|
||||
.name = "hid-uclogic-rdesc-test",
|
||||
.test_cases = hid_uclogic_rdesc_test_cases,
|
||||
};
|
||||
|
||||
kunit_test_suite(hid_uclogic_rdesc_test_suite);
|
||||
|
||||
MODULE_DESCRIPTION("KUnit tests for the UC-Logic driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("José Expósito <jose.exposito89@gmail.com>");
|
|
@ -859,6 +859,108 @@ const __u8 uclogic_rdesc_v2_frame_dial_arr[] = {
|
|||
const size_t uclogic_rdesc_v2_frame_dial_size =
|
||||
sizeof(uclogic_rdesc_v2_frame_dial_arr);
|
||||
|
||||
/* Fixed report descriptor template for UGEE v2 pen reports */
|
||||
const __u8 uclogic_rdesc_ugee_v2_pen_template_arr[] = {
|
||||
0x05, 0x0d, /* Usage Page (Digitizers), */
|
||||
0x09, 0x01, /* Usage (Digitizer), */
|
||||
0xa1, 0x01, /* Collection (Application), */
|
||||
0x85, 0x02, /* Report ID (2), */
|
||||
0x09, 0x20, /* Usage (Stylus), */
|
||||
0xa1, 0x00, /* Collection (Physical), */
|
||||
0x09, 0x42, /* Usage (Tip Switch), */
|
||||
0x09, 0x44, /* Usage (Barrel Switch), */
|
||||
0x09, 0x46, /* Usage (Tablet Pick), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x95, 0x03, /* Report Count (3), */
|
||||
0x14, /* Logical Minimum (0), */
|
||||
0x25, 0x01, /* Logical Maximum (1), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x95, 0x02, /* Report Count (2), */
|
||||
0x81, 0x03, /* Input (Constant, Variable), */
|
||||
0x09, 0x32, /* Usage (In Range), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x95, 0x02, /* Report Count (2), */
|
||||
0x81, 0x03, /* Input (Constant, Variable), */
|
||||
0x75, 0x10, /* Report Size (16), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x35, 0x00, /* Physical Minimum (0), */
|
||||
0xa4, /* Push, */
|
||||
0x05, 0x01, /* Usage Page (Desktop), */
|
||||
0x09, 0x30, /* Usage (X), */
|
||||
0x65, 0x13, /* Unit (Inch), */
|
||||
0x55, 0x0d, /* Unit Exponent (-3), */
|
||||
0x27, UCLOGIC_RDESC_PEN_PH(X_LM),
|
||||
/* Logical Maximum (PLACEHOLDER), */
|
||||
0x47, UCLOGIC_RDESC_PEN_PH(X_PM),
|
||||
/* Physical Maximum (PLACEHOLDER), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x09, 0x31, /* Usage (Y), */
|
||||
0x27, UCLOGIC_RDESC_PEN_PH(Y_LM),
|
||||
/* Logical Maximum (PLACEHOLDER), */
|
||||
0x47, UCLOGIC_RDESC_PEN_PH(Y_PM),
|
||||
/* Physical Maximum (PLACEHOLDER), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0xb4, /* Pop, */
|
||||
0x09, 0x30, /* Usage (Tip Pressure), */
|
||||
0x45, 0x00, /* Physical Maximum (0), */
|
||||
0x27, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM),
|
||||
/* Logical Maximum (PLACEHOLDER), */
|
||||
0x75, 0x0D, /* Report Size (13), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x95, 0x03, /* Report Count (3), */
|
||||
0x81, 0x01, /* Input (Constant), */
|
||||
0x09, 0x3d, /* Usage (X Tilt), */
|
||||
0x35, 0xC3, /* Physical Minimum (-61), */
|
||||
0x45, 0x3C, /* Physical Maximum (60), */
|
||||
0x15, 0xC3, /* Logical Minimum (-61), */
|
||||
0x25, 0x3C, /* Logical Maximum (60), */
|
||||
0x75, 0x08, /* Report Size (8), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x09, 0x3e, /* Usage (Y Tilt), */
|
||||
0x35, 0xC3, /* Physical Minimum (-61), */
|
||||
0x45, 0x3C, /* Physical Maximum (60), */
|
||||
0x15, 0xC3, /* Logical Minimum (-61), */
|
||||
0x25, 0x3C, /* Logical Maximum (60), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0xc0, /* End Collection, */
|
||||
0xc0, /* End Collection */
|
||||
};
|
||||
const size_t uclogic_rdesc_ugee_v2_pen_template_size =
|
||||
sizeof(uclogic_rdesc_ugee_v2_pen_template_arr);
|
||||
|
||||
/* Fixed report descriptor template for UGEE v2 frame reports (buttons only) */
|
||||
const __u8 uclogic_rdesc_ugee_v2_frame_btn_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, 0x46, /* Report Count (70), */
|
||||
0x81, 0x01, /* Input (Constant), */
|
||||
0xC0, /* End Collection, */
|
||||
0xC0 /* End Collection */
|
||||
};
|
||||
const size_t uclogic_rdesc_ugee_v2_frame_btn_template_size =
|
||||
sizeof(uclogic_rdesc_ugee_v2_frame_btn_template_arr);
|
||||
|
||||
/* Fixed report descriptor for Ugee EX07 frame */
|
||||
const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = {
|
||||
0x05, 0x01, /* Usage Page (Desktop), */
|
||||
|
@ -979,7 +1081,7 @@ const size_t uclogic_rdesc_xppen_deco01_frame_size =
|
|||
* uclogic_rdesc_template_apply() - apply report descriptor parameters to a
|
||||
* report descriptor template, creating a report descriptor. Copies the
|
||||
* template over to the new report descriptor and replaces every occurrence of
|
||||
* UCLOGIC_RDESC_PH_HEAD, followed by an index byte, with the value from the
|
||||
* the template placeholders, followed by an index byte, with the value from the
|
||||
* parameter list at that index.
|
||||
*
|
||||
* @template_ptr: Pointer to the template buffer.
|
||||
|
@ -996,7 +1098,8 @@ __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr,
|
|||
const s32 *param_list,
|
||||
size_t param_num)
|
||||
{
|
||||
static const __u8 head[] = {UCLOGIC_RDESC_PH_HEAD};
|
||||
static const __u8 btn_head[] = {UCLOGIC_RDESC_FRAME_PH_BTN_HEAD};
|
||||
static const __u8 pen_head[] = {UCLOGIC_RDESC_PEN_PH_HEAD};
|
||||
__u8 *rdesc_ptr;
|
||||
__u8 *p;
|
||||
s32 v;
|
||||
|
@ -1005,12 +1108,19 @@ __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr,
|
|||
if (rdesc_ptr == NULL)
|
||||
return NULL;
|
||||
|
||||
for (p = rdesc_ptr; p + sizeof(head) < rdesc_ptr + template_size;) {
|
||||
if (memcmp(p, head, sizeof(head)) == 0 &&
|
||||
p[sizeof(head)] < param_num) {
|
||||
v = param_list[p[sizeof(head)]];
|
||||
for (p = rdesc_ptr; p + sizeof(btn_head) < rdesc_ptr + template_size;) {
|
||||
if (p + sizeof(pen_head) < rdesc_ptr + template_size &&
|
||||
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);
|
||||
p += sizeof(head) + 1;
|
||||
p += sizeof(pen_head) + 1;
|
||||
} else if (memcmp(p, btn_head, sizeof(btn_head)) == 0 &&
|
||||
p[sizeof(btn_head)] < param_num) {
|
||||
v = param_list[p[sizeof(btn_head)]];
|
||||
put_unaligned((__u8)0x2A, p); /* Usage Maximum */
|
||||
put_unaligned_le16((__force u16)cpu_to_le16(v), p + 1);
|
||||
p += sizeof(btn_head) + 1;
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
|
|
|
@ -81,7 +81,8 @@ extern __u8 uclogic_rdesc_twha60_fixed1_arr[];
|
|||
extern const size_t uclogic_rdesc_twha60_fixed1_size;
|
||||
|
||||
/* Report descriptor template placeholder head */
|
||||
#define UCLOGIC_RDESC_PH_HEAD 0xFE, 0xED, 0x1D
|
||||
#define UCLOGIC_RDESC_PEN_PH_HEAD 0xFE, 0xED, 0x1D
|
||||
#define UCLOGIC_RDESC_FRAME_PH_BTN_HEAD 0xFE, 0xED
|
||||
|
||||
/* Apply report descriptor parameters to a report descriptor template */
|
||||
extern __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr,
|
||||
|
@ -89,19 +90,24 @@ extern __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr,
|
|||
const s32 *param_list,
|
||||
size_t param_num);
|
||||
|
||||
/* Pen report descriptor template placeholder IDs */
|
||||
enum uclogic_rdesc_pen_ph_id {
|
||||
/* Report descriptor template placeholder IDs */
|
||||
enum uclogic_rdesc_ph_id {
|
||||
UCLOGIC_RDESC_PEN_PH_ID_X_LM,
|
||||
UCLOGIC_RDESC_PEN_PH_ID_X_PM,
|
||||
UCLOGIC_RDESC_PEN_PH_ID_Y_LM,
|
||||
UCLOGIC_RDESC_PEN_PH_ID_Y_PM,
|
||||
UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM,
|
||||
UCLOGIC_RDESC_PEN_PH_ID_NUM
|
||||
UCLOGIC_RDESC_FRAME_PH_ID_UM,
|
||||
UCLOGIC_RDESC_PH_ID_NUM
|
||||
};
|
||||
|
||||
/* Report descriptor pen template placeholder */
|
||||
#define UCLOGIC_RDESC_PEN_PH(_ID) \
|
||||
UCLOGIC_RDESC_PH_HEAD, UCLOGIC_RDESC_PEN_PH_ID_##_ID
|
||||
UCLOGIC_RDESC_PEN_PH_HEAD, UCLOGIC_RDESC_PEN_PH_ID_##_ID
|
||||
|
||||
/* Report descriptor frame buttons template placeholder */
|
||||
#define UCLOGIC_RDESC_FRAME_PH_BTN \
|
||||
UCLOGIC_RDESC_FRAME_PH_BTN_HEAD, UCLOGIC_RDESC_FRAME_PH_ID_UM
|
||||
|
||||
/* Report ID for v1 pen reports */
|
||||
#define UCLOGIC_RDESC_V1_PEN_ID 0x07
|
||||
|
@ -155,6 +161,14 @@ extern const size_t uclogic_rdesc_v2_frame_dial_size;
|
|||
/* Device ID byte offset in v2 frame dial reports */
|
||||
#define UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE 0x4
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Fixed report descriptor template for UGEE v2 frame reports (buttons only) */
|
||||
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 for Ugee EX07 frame */
|
||||
extern const __u8 uclogic_rdesc_ugee_ex07_frame_arr[];
|
||||
extern const size_t uclogic_rdesc_ugee_ex07_frame_size;
|
||||
|
|
Loading…
Add table
Reference in a new issue