Commit a092986f authored by José Expósito's avatar José Expósito Committed by Jiri Kosina
Browse files

HID: uclogic: Parse the UGEE v2 frame type



The string descriptor returned by UGEE v2 devices contains a byte
indicating the device frame type.

The values discovered so far are:

 - 0: Frame with buttons, present in the XP-PEN Deco L.
 - 1: Frame with buttons and dial, present in the PARBLO A610 PRO.
 - 2: Frame with buttons and a mouse, shaped as a dial + touchpad.
      Present in the XP-PEN Deco Pro S.

Parse the frame type and add KUnit tests.

Tested-by: default avatarJouke Witteveen <j.witteveen@gmail.com>
Signed-off-by: default avatarJosé Expósito <jose.exposito89@gmail.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 86402296
Loading
Loading
Loading
Loading
+34 −1
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
 */

#include <kunit/test.h>
#include "./hid-uclogic-params.h"
#include "./hid-uclogic-rdesc.h"

#define MAX_STR_DESC_SIZE 14
@@ -17,6 +18,7 @@ struct uclogic_parse_ugee_v2_desc_case {
	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[] = {
@@ -26,6 +28,7 @@ static struct uclogic_parse_ugee_v2_desc_case uclogic_parse_ugee_v2_desc_cases[]
		.str_desc = {},
		.str_desc_size = 0,
		.desc_params = {},
		.frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS,
	},
	{
		.name = "resolution_with_value_0",
@@ -48,6 +51,7 @@ static struct uclogic_parse_ugee_v2_desc_case uclogic_parse_ugee_v2_desc_cases[]
			[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 */
	{
@@ -71,6 +75,7 @@ static struct uclogic_parse_ugee_v2_desc_case uclogic_parse_ugee_v2_desc_cases[]
			[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 */
	{
@@ -94,6 +99,31 @@ static struct uclogic_parse_ugee_v2_desc_case uclogic_parse_ugee_v2_desc_cases[]
			[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,
	},
};

@@ -110,12 +140,14 @@ 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));
						ARRAY_SIZE(desc_params),
						&frame_type);
	KUNIT_ASSERT_EQ(test, res, params->res);

	if (res)
@@ -139,6 +171,7 @@ static void uclogic_parse_ugee_v2_desc_test(struct kunit *test)
	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[] = {
+15 −4
Original line number Diff line number Diff line
@@ -1064,6 +1064,7 @@ static int uclogic_probe_interface(struct hid_device *hdev, u8 *magic_arr,
 * @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.
@@ -1071,7 +1072,8 @@ static int uclogic_probe_interface(struct hid_device *hdev, u8 *magic_arr,
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)
					     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;
@@ -1091,6 +1093,7 @@ static int uclogic_params_parse_ugee_v2_desc(const __u8 *str_desc,
	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);
@@ -1176,6 +1179,7 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
	__u8 *str_desc = NULL;
	__u8 *rdesc_pen = NULL;
	s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
	enum uclogic_params_frame_type frame_type;
	__u8 magic_arr[] = {
		0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	};
@@ -1219,7 +1223,8 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,

	rc = uclogic_params_parse_ugee_v2_desc(str_desc, str_desc_len,
					       desc_params,
					       ARRAY_SIZE(desc_params));
					       ARRAY_SIZE(desc_params),
					       &frame_type);
	if (rc)
		goto cleanup;

@@ -1243,8 +1248,14 @@ 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 */
	switch (frame_type) {
	case UCLOGIC_PARAMS_FRAME_BUTTONS:
	default:
		rc = uclogic_params_ugee_v2_init_frame_buttons(&p, desc_params,
							       ARRAY_SIZE(desc_params));
		break;
	}

	if (rc)
		goto cleanup;

+10 −0
Original line number Diff line number Diff line
@@ -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.
 */