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

- support for UcLogic XP-PEN Artist 24 Pro (Joshua Goins)
This commit is contained in:
Jiri Kosina 2025-12-02 14:44:41 +01:00
commit eb41c955b0
6 changed files with 194 additions and 11 deletions

View File

@ -1422,6 +1422,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

View File

@ -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);

View File

@ -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];
@ -1534,7 +1537,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.
@ -1545,15 +1548,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,
struct hid_device *hdev,
const u8 rdesc_frame_arr[],
const size_t rdesc_frame_size)
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,
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];
@ -1616,8 +1621,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;
@ -1625,7 +1630,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;
@ -1972,10 +1977,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;

View File

@ -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;
};
/*

View File

@ -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

View File

@ -214,4 +214,12 @@ extern const size_t uclogic_rdesc_ugee_g5_frame_size;
extern const __u8 uclogic_rdesc_xppen_artist_22r_pro_frame_arr[];
extern const size_t uclogic_rdesc_xppen_artist_22r_pro_frame_size;
/* Fixed report descriptor for XP-Pen Arist 24 Pro frame */
extern const __u8 uclogic_rdesc_xppen_artist_24_pro_pen_template_arr[];
extern const size_t uclogic_rdesc_xppen_artist_24_pro_pen_template_size;
/* Fixed report descriptor for XP-Pen Arist 24 Pro frame */
extern const __u8 uclogic_rdesc_xppen_artist_24_pro_frame_arr[];
extern const size_t uclogic_rdesc_xppen_artist_24_pro_frame_size;
#endif /* _HID_UCLOGIC_RDESC_H */