mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-22 14:41:27 +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
|
To compile this driver as a module, choose M here: the module
|
||||||
will be called hid-mcp2221.ko.
|
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
|
endmenu
|
||||||
|
|
||||||
endif # HID
|
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_HUB) += hid-sensor-hub.o
|
||||||
obj-$(CONFIG_HID_SENSOR_CUSTOM_SENSOR) += hid-sensor-custom.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_HID) += usbhid/
|
||||||
obj-$(CONFIG_USB_MOUSE) += usbhid/
|
obj-$(CONFIG_USB_MOUSE) += usbhid/
|
||||||
obj-$(CONFIG_USB_KBD) += 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_G540 0x0075
|
||||||
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640 0x0094
|
#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_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_XPPEN_TABLET_STAR06 0x0078
|
||||||
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
|
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
|
||||||
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
|
#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) },
|
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
||||||
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) },
|
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,
|
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
||||||
USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) },
|
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;
|
const int len = 12;
|
||||||
s32 resolution;
|
s32 resolution;
|
||||||
/* Pen report descriptor template parameters */
|
/* 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;
|
__u8 *desc_ptr = NULL;
|
||||||
|
|
||||||
/* Check arguments */
|
/* Check arguments */
|
||||||
|
@ -383,7 +383,7 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
|
||||||
size_t i;
|
size_t i;
|
||||||
s32 resolution;
|
s32 resolution;
|
||||||
/* Pen report descriptor template parameters */
|
/* 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;
|
__u8 *desc_ptr = NULL;
|
||||||
|
|
||||||
/* Check arguments */
|
/* Check arguments */
|
||||||
|
@ -1006,6 +1006,197 @@ cleanup:
|
||||||
return rc;
|
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
|
* uclogic_params_init() - initialize a tablet interface and discover its
|
||||||
* parameters.
|
* parameters.
|
||||||
|
@ -1241,6 +1432,12 @@ int uclogic_params_init(struct uclogic_params *params,
|
||||||
uclogic_params_init_invalid(&p);
|
uclogic_params_init_invalid(&p);
|
||||||
}
|
}
|
||||||
break;
|
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,
|
case VID_PID(USB_VENDOR_ID_TRUST,
|
||||||
USB_DEVICE_ID_TRUST_PANORA_TABLET):
|
USB_DEVICE_ID_TRUST_PANORA_TABLET):
|
||||||
case VID_PID(USB_VENDOR_ID_UGEE,
|
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 =
|
const size_t uclogic_rdesc_v2_frame_dial_size =
|
||||||
sizeof(uclogic_rdesc_v2_frame_dial_arr);
|
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 */
|
/* Fixed report descriptor for Ugee EX07 frame */
|
||||||
const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = {
|
const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = {
|
||||||
0x05, 0x01, /* Usage Page (Desktop), */
|
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
|
* uclogic_rdesc_template_apply() - apply report descriptor parameters to a
|
||||||
* report descriptor template, creating a report descriptor. Copies the
|
* report descriptor template, creating a report descriptor. Copies the
|
||||||
* template over to the new report descriptor and replaces every occurrence of
|
* 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.
|
* parameter list at that index.
|
||||||
*
|
*
|
||||||
* @template_ptr: Pointer to the template buffer.
|
* @template_ptr: Pointer to the template buffer.
|
||||||
|
@ -996,7 +1098,8 @@ __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr,
|
||||||
const s32 *param_list,
|
const s32 *param_list,
|
||||||
size_t param_num)
|
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 *rdesc_ptr;
|
||||||
__u8 *p;
|
__u8 *p;
|
||||||
s32 v;
|
s32 v;
|
||||||
|
@ -1005,12 +1108,19 @@ __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr,
|
||||||
if (rdesc_ptr == NULL)
|
if (rdesc_ptr == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (p = rdesc_ptr; p + sizeof(head) < rdesc_ptr + template_size;) {
|
for (p = rdesc_ptr; p + sizeof(btn_head) < rdesc_ptr + template_size;) {
|
||||||
if (memcmp(p, head, sizeof(head)) == 0 &&
|
if (p + sizeof(pen_head) < rdesc_ptr + template_size &&
|
||||||
p[sizeof(head)] < param_num) {
|
memcmp(p, pen_head, sizeof(pen_head)) == 0 &&
|
||||||
v = param_list[p[sizeof(head)]];
|
p[sizeof(pen_head)] < param_num) {
|
||||||
|
v = param_list[p[sizeof(pen_head)]];
|
||||||
put_unaligned(cpu_to_le32(v), (s32 *)p);
|
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 {
|
} else {
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,8 @@ extern __u8 uclogic_rdesc_twha60_fixed1_arr[];
|
||||||
extern const size_t uclogic_rdesc_twha60_fixed1_size;
|
extern const size_t uclogic_rdesc_twha60_fixed1_size;
|
||||||
|
|
||||||
/* Report descriptor template placeholder head */
|
/* 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 */
|
/* Apply report descriptor parameters to a report descriptor template */
|
||||||
extern __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr,
|
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,
|
const s32 *param_list,
|
||||||
size_t param_num);
|
size_t param_num);
|
||||||
|
|
||||||
/* Pen report descriptor template placeholder IDs */
|
/* Report descriptor template placeholder IDs */
|
||||||
enum uclogic_rdesc_pen_ph_id {
|
enum uclogic_rdesc_ph_id {
|
||||||
UCLOGIC_RDESC_PEN_PH_ID_X_LM,
|
UCLOGIC_RDESC_PEN_PH_ID_X_LM,
|
||||||
UCLOGIC_RDESC_PEN_PH_ID_X_PM,
|
UCLOGIC_RDESC_PEN_PH_ID_X_PM,
|
||||||
UCLOGIC_RDESC_PEN_PH_ID_Y_LM,
|
UCLOGIC_RDESC_PEN_PH_ID_Y_LM,
|
||||||
UCLOGIC_RDESC_PEN_PH_ID_Y_PM,
|
UCLOGIC_RDESC_PEN_PH_ID_Y_PM,
|
||||||
UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM,
|
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 */
|
/* Report descriptor pen template placeholder */
|
||||||
#define UCLOGIC_RDESC_PEN_PH(_ID) \
|
#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 */
|
/* Report ID for v1 pen reports */
|
||||||
#define UCLOGIC_RDESC_V1_PEN_ID 0x07
|
#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 */
|
/* Device ID byte offset in v2 frame dial reports */
|
||||||
#define UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE 0x4
|
#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 */
|
/* Fixed report descriptor for Ugee EX07 frame */
|
||||||
extern const __u8 uclogic_rdesc_ugee_ex07_frame_arr[];
|
extern const __u8 uclogic_rdesc_ugee_ex07_frame_arr[];
|
||||||
extern const size_t uclogic_rdesc_ugee_ex07_frame_size;
|
extern const size_t uclogic_rdesc_ugee_ex07_frame_size;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue