Commit ee35448c authored by Joshua Goins's avatar Joshua Goins Committed by Jiri Kosina
Browse files

HID: uclogic: Add support for the XP-PEN Artist 24 Pro



The tablet is similar to the 22R Pro, but with a few annoying
differences. Its descriptors are bigger because of the tablet's split
coordinate system, I guess it's just that large. Thankfully, this is
easy enough to support as all we have to do is shift bytes around.

To help code re-use, I changed the signature of
uclogic_params_init_ugee_xppen_pro to accept a pen descriptor so we
didn't create yet-another initialization function.

I have been testing this locally for a month or so and it works great,
and also corroborated this with a few other testers. Since this touches
my 22R Pro code, I have tested and checked that it didn't regress that
device.

Signed-off-by: default avatarJoshua Goins <josh@redstrate.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.com>
parent 54ba6d9b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1416,6 +1416,7 @@
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW	0x0933
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06	0x0078
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_22R_PRO	0x091b
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_24_PRO	0x092d
#define USB_DEVICE_ID_UGEE_TABLET_G5		0x0074
#define USB_DEVICE_ID_UGEE_TABLET_EX07S		0x0071
#define USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720	0x0055
+19 −0
Original line number Diff line number Diff line
@@ -362,6 +362,23 @@ static int uclogic_raw_event_pen(struct uclogic_drvdata *drvdata,
		data[8] = pressure_low_byte;
		data[9] = pressure_high_byte;
	}
	if (size == 12 && pen->fragmented_hires2) {
		// 00 00 when on the left side, 01 00 in the right
		// we move these to the end of the x coord (u16) to create a correct x coord (u32)
		u8 lsb_low_byte = data[10];
		u8 lsb_high_byte = data[11];

		// shift everything right by 2 bytes, to make space for the moved lsb
		data[11] = data[9];
		data[10] = data[8];
		data[9] = data[7];
		data[8] = data[6];
		data[7] = data[5];
		data[6] = data[4];

		data[4] = lsb_low_byte;
		data[5] = lsb_high_byte;
	}
	/* If we need to emulate in-range detection */
	if (pen->inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) {
		/* Set in-range bit */
@@ -604,6 +621,8 @@ static const struct hid_device_id uclogic_devices[] = {
				USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
				USB_DEVICE_ID_UGEE_XPPEN_TABLET_22R_PRO) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
				USB_DEVICE_ID_UGEE_XPPEN_TABLET_24_PRO) },
	{ }
};
MODULE_DEVICE_TABLE(hid, uclogic_devices);
+36 −11
Original line number Diff line number Diff line
@@ -1123,6 +1123,9 @@ static int uclogic_params_parse_ugee_v2_desc(const __u8 *str_desc,
		return -EINVAL;

	pen_x_lm = get_unaligned_le16(str_desc + 2);
	if (str_desc_size > 12)
		pen_x_lm += (u8)str_desc[12] << 16;

	pen_y_lm = get_unaligned_le16(str_desc + 4);
	frame_num_buttons = str_desc[6];
	*frame_type = str_desc[7];
@@ -1532,7 +1535,7 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
}

/*
 * uclogic_params_init_ugee_xppen_pro_22r() - Initializes a UGEE XP-Pen Pro 22R tablet device.
 * uclogic_params_init_ugee_xppen_pro() - Initializes a UGEE XP-Pen Pro tablet device.
 *
 * @hdev:	The HID device of the tablet interface to initialize and get
 *		parameters from. Cannot be NULL.
@@ -1543,15 +1546,17 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
 * Returns:
 *	Zero, if successful. A negative errno code on error.
 */
static int uclogic_params_init_ugee_xppen_pro_22r(struct uclogic_params *params,
static int uclogic_params_init_ugee_xppen_pro(struct uclogic_params *params,
					     struct hid_device *hdev,
					     const u8 rdesc_pen_arr[],
					     const size_t rdesc_pen_size,
					     const u8 rdesc_frame_arr[],
						  const size_t rdesc_frame_size)
					     const size_t rdesc_frame_size,
					     size_t str_desc_len)
{
	int rc = 0;
	struct usb_interface *iface;
	__u8 bInterfaceNumber;
	const int str_desc_len = 12;
	u8 *str_desc = NULL;
	__u8 *rdesc_pen = NULL;
	s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
@@ -1614,8 +1619,8 @@ static int uclogic_params_init_ugee_xppen_pro_22r(struct uclogic_params *params,

	/* Initialize the pen interface */
	rdesc_pen = uclogic_rdesc_template_apply(
				uclogic_rdesc_ugee_v2_pen_template_arr,
				uclogic_rdesc_ugee_v2_pen_template_size,
				rdesc_pen_arr,
				rdesc_pen_size,
				desc_params, ARRAY_SIZE(desc_params));
	if (!rdesc_pen) {
		rc = -ENOMEM;
@@ -1623,7 +1628,7 @@ static int uclogic_params_init_ugee_xppen_pro_22r(struct uclogic_params *params,
	}

	p.pen.desc_ptr = rdesc_pen;
	p.pen.desc_size = uclogic_rdesc_ugee_v2_pen_template_size;
	p.pen.desc_size = rdesc_pen_size;
	p.pen.id = 0x02;
	p.pen.subreport_list[0].value = 0xf0;
	p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID;
@@ -1970,10 +1975,30 @@ int uclogic_params_init(struct uclogic_params *params,
		break;
	case VID_PID(USB_VENDOR_ID_UGEE,
			USB_DEVICE_ID_UGEE_XPPEN_TABLET_22R_PRO):
		rc = uclogic_params_init_ugee_xppen_pro_22r(&p,
		rc = uclogic_params_init_ugee_xppen_pro(&p,
			hdev,
			uclogic_rdesc_ugee_v2_pen_template_arr,
			uclogic_rdesc_ugee_v2_pen_template_size,
			uclogic_rdesc_xppen_artist_22r_pro_frame_arr,
			uclogic_rdesc_xppen_artist_22r_pro_frame_size);
			uclogic_rdesc_xppen_artist_22r_pro_frame_size,
			12);
		if (rc != 0)
			goto cleanup;

		break;
	case VID_PID(USB_VENDOR_ID_UGEE,
			USB_DEVICE_ID_UGEE_XPPEN_TABLET_24_PRO):
		rc = uclogic_params_init_ugee_xppen_pro(&p,
			hdev,
			uclogic_rdesc_xppen_artist_24_pro_pen_template_arr,
			uclogic_rdesc_xppen_artist_24_pro_pen_template_size,
			uclogic_rdesc_xppen_artist_24_pro_frame_arr,
			uclogic_rdesc_xppen_artist_24_pro_frame_size,
			14);

		// The 24 Pro has a fragmented X Coord.
		p.pen.fragmented_hires2 = true;

		if (rc != 0)
			goto cleanup;

+5 −0
Original line number Diff line number Diff line
@@ -103,6 +103,11 @@ struct uclogic_params_pen {
	 * Only valid if "id" is not zero.
	 */
	bool tilt_y_flipped;
	/*
	 * True, if reports include fragmented high resolution X coords.
	 * This moves bytes 10-11 to the LSB of the X coordinate.
	 */
	bool fragmented_hires2;
};

/*
+125 −0
Original line number Diff line number Diff line
@@ -1237,6 +1237,131 @@ const __u8 uclogic_rdesc_xppen_artist_22r_pro_frame_arr[] = {
const size_t uclogic_rdesc_xppen_artist_22r_pro_frame_size =
				sizeof(uclogic_rdesc_xppen_artist_22r_pro_frame_arr);

/* Fixed report descriptor template for XP-PEN 24 Pro reports
 * Mostly identical to uclogic_rdesc_ugee_v2_pen_template_arr except that the X coordinate has to be
 * 32-bits instead of 16-bits.
 */
const __u8 uclogic_rdesc_xppen_artist_24_pro_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), */
	0x75, 0x20,         /*          Report Size (32),               */
	0x81, 0x02,         /*          Input (Variable),               */
	0x75, 0x10,         /*          Report Size (16),               */
	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_xppen_artist_24_pro_pen_template_size =
			sizeof(uclogic_rdesc_xppen_artist_24_pro_pen_template_arr);

/* Fixed report descriptor for XP-Pen Arist 24 Pro frame */
const __u8 uclogic_rdesc_xppen_artist_24_pro_frame_arr[] = {
	0x05, 0x01,         /*  Usage Page (Desktop),                       */
	0x09, 0x07,         /*  Usage (Keypad),                             */
	0xA1, 0x01,         /*  Collection (Application),                   */
	0x85, UCLOGIC_RDESC_V1_FRAME_ID,
	/*      Report ID (Virtual report),             */
	0x05, 0x0D,         /*     Usage Page (Digitizer),                  */
	0x09, 0x39,         /*      Usage (Tablet Function Keys),           */
	0xA0,               /*      Collection (Physical),                  */
	0x14,               /*          Logical Minimum (0),                */
	0x25, 0x01,         /*          Logical Maximum (1),                */
	0x75, 0x01,         /*          Report Size (1),                    */
	0x95, 0x08,         /*          Report Count (8),                   */
	0x81, 0x01,         /*          Input (Constant),                   */
	0x05, 0x09,         /*          Usage Page (Button),                */
	0x19, 0x01,         /*          Usage Minimum (01h),                */
	0x29, 0x14,         /*          Usage Maximum (14h),                */
	0x95, 0x14,         /*          Report Count (20),                  */
	0x81, 0x02,         /*          Input (Variable),                   */
	0x95, 0x14,         /*          Report Count (20),                  */
	0x81, 0x01,         /*          Input (Constant),                   */
	0x05, 0x01,         /*          Usage Page (Desktop),               */
	0x09, 0x38,         /*          Usage (Wheel),                      */
	0x75, 0x08,         /*          Report Size (8),                    */
	0x95, 0x01,         /*          Report Count (1),                   */
	0x15, 0xFF,         /*          Logical Minimum (-1),               */
	0x25, 0x08,         /*          Logical Maximum (8),                */
	0x81, 0x06,         /*          Input (Variable, Relative),         */
	0x05, 0x0C,         /*          Usage Page (Consumer Devices),      */
	0x0A, 0x38, 0x02,   /*          Usage (AC PAN),                     */
	0x95, 0x01,         /*          Report Count (1),                   */
	0x81, 0x06,         /*          Input (Variable, Relative),         */
	0x26, 0xFF, 0x00,   /*          Logical Maximum (255),              */
	0x75, 0x08,         /*          Report Size (8),                    */
	0x95, 0x01,         /*          Report Count (1),                   */
	0x81, 0x02,         /*          Input (Variable),                   */
	0x75, 0x01,         /*          Report Size (1),                    */
	0x95, 16,           /*          Report Count (16),                  */
	0x81, 0x01,         /*          Input (Constant),                   */
	0xC0,               /*      End Collection                          */
	0xC0,               /*  End Collection                              */
};

const size_t uclogic_rdesc_xppen_artist_24_pro_frame_size =
				sizeof(uclogic_rdesc_xppen_artist_24_pro_frame_arr);

/**
 * uclogic_rdesc_template_apply() - apply report descriptor parameters to a
 * report descriptor template, creating a report descriptor. Copies the
Loading