Commit 430257d8 authored by Benjamin Tissoires's avatar Benjamin Tissoires
Browse files

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

- Add UGEEv2 support (XP-PEN Deco Pro S and Parblo A610 PRO) (José
  Expósito)
parents d7ae8ff9 7495fb7e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+3 −1
Original line number Diff line number Diff line
@@ -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/
+2 −0
Original line number Diff line number Diff line
@@ -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
+5 −0
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
// 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>");
Loading