Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Joshua Goins <josh@redstrate.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>

authored by

Joshua Goins and committed by
Jiri Kosina
ee35448c 54ba6d9b

+194 -11
+1
drivers/hid/hid-ids.h
··· 1416 1416 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW 0x0933 1417 1417 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078 1418 1418 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_22R_PRO 0x091b 1419 + #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_24_PRO 0x092d 1419 1420 #define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074 1420 1421 #define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071 1421 1422 #define USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720 0x0055
+19
drivers/hid/hid-uclogic-core.c
··· 362 362 data[8] = pressure_low_byte; 363 363 data[9] = pressure_high_byte; 364 364 } 365 + if (size == 12 && pen->fragmented_hires2) { 366 + // 00 00 when on the left side, 01 00 in the right 367 + // we move these to the end of the x coord (u16) to create a correct x coord (u32) 368 + u8 lsb_low_byte = data[10]; 369 + u8 lsb_high_byte = data[11]; 370 + 371 + // shift everything right by 2 bytes, to make space for the moved lsb 372 + data[11] = data[9]; 373 + data[10] = data[8]; 374 + data[9] = data[7]; 375 + data[8] = data[6]; 376 + data[7] = data[5]; 377 + data[6] = data[4]; 378 + 379 + data[4] = lsb_low_byte; 380 + data[5] = lsb_high_byte; 381 + } 365 382 /* If we need to emulate in-range detection */ 366 383 if (pen->inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) { 367 384 /* Set in-range bit */ ··· 621 604 USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) }, 622 605 { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, 623 606 USB_DEVICE_ID_UGEE_XPPEN_TABLET_22R_PRO) }, 607 + { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, 608 + USB_DEVICE_ID_UGEE_XPPEN_TABLET_24_PRO) }, 624 609 { } 625 610 }; 626 611 MODULE_DEVICE_TABLE(hid, uclogic_devices);
+36 -11
drivers/hid/hid-uclogic-params.c
··· 1123 1123 return -EINVAL; 1124 1124 1125 1125 pen_x_lm = get_unaligned_le16(str_desc + 2); 1126 + if (str_desc_size > 12) 1127 + pen_x_lm += (u8)str_desc[12] << 16; 1128 + 1126 1129 pen_y_lm = get_unaligned_le16(str_desc + 4); 1127 1130 frame_num_buttons = str_desc[6]; 1128 1131 *frame_type = str_desc[7]; ··· 1535 1532 } 1536 1533 1537 1534 /* 1538 - * uclogic_params_init_ugee_xppen_pro_22r() - Initializes a UGEE XP-Pen Pro 22R tablet device. 1535 + * uclogic_params_init_ugee_xppen_pro() - Initializes a UGEE XP-Pen Pro tablet device. 1539 1536 * 1540 1537 * @hdev: The HID device of the tablet interface to initialize and get 1541 1538 * parameters from. Cannot be NULL. ··· 1546 1543 * Returns: 1547 1544 * Zero, if successful. A negative errno code on error. 1548 1545 */ 1549 - static int uclogic_params_init_ugee_xppen_pro_22r(struct uclogic_params *params, 1550 - struct hid_device *hdev, 1551 - const u8 rdesc_frame_arr[], 1552 - const size_t rdesc_frame_size) 1546 + static int uclogic_params_init_ugee_xppen_pro(struct uclogic_params *params, 1547 + struct hid_device *hdev, 1548 + const u8 rdesc_pen_arr[], 1549 + const size_t rdesc_pen_size, 1550 + const u8 rdesc_frame_arr[], 1551 + const size_t rdesc_frame_size, 1552 + size_t str_desc_len) 1553 1553 { 1554 1554 int rc = 0; 1555 1555 struct usb_interface *iface; 1556 1556 __u8 bInterfaceNumber; 1557 - const int str_desc_len = 12; 1558 1557 u8 *str_desc = NULL; 1559 1558 __u8 *rdesc_pen = NULL; 1560 1559 s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; ··· 1619 1614 1620 1615 /* Initialize the pen interface */ 1621 1616 rdesc_pen = uclogic_rdesc_template_apply( 1622 - uclogic_rdesc_ugee_v2_pen_template_arr, 1623 - uclogic_rdesc_ugee_v2_pen_template_size, 1617 + rdesc_pen_arr, 1618 + rdesc_pen_size, 1624 1619 desc_params, ARRAY_SIZE(desc_params)); 1625 1620 if (!rdesc_pen) { 1626 1621 rc = -ENOMEM; ··· 1628 1623 } 1629 1624 1630 1625 p.pen.desc_ptr = rdesc_pen; 1631 - p.pen.desc_size = uclogic_rdesc_ugee_v2_pen_template_size; 1626 + p.pen.desc_size = rdesc_pen_size; 1632 1627 p.pen.id = 0x02; 1633 1628 p.pen.subreport_list[0].value = 0xf0; 1634 1629 p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID; ··· 1975 1970 break; 1976 1971 case VID_PID(USB_VENDOR_ID_UGEE, 1977 1972 USB_DEVICE_ID_UGEE_XPPEN_TABLET_22R_PRO): 1978 - rc = uclogic_params_init_ugee_xppen_pro_22r(&p, 1973 + rc = uclogic_params_init_ugee_xppen_pro(&p, 1979 1974 hdev, 1975 + uclogic_rdesc_ugee_v2_pen_template_arr, 1976 + uclogic_rdesc_ugee_v2_pen_template_size, 1980 1977 uclogic_rdesc_xppen_artist_22r_pro_frame_arr, 1981 - uclogic_rdesc_xppen_artist_22r_pro_frame_size); 1978 + uclogic_rdesc_xppen_artist_22r_pro_frame_size, 1979 + 12); 1980 + if (rc != 0) 1981 + goto cleanup; 1982 + 1983 + break; 1984 + case VID_PID(USB_VENDOR_ID_UGEE, 1985 + USB_DEVICE_ID_UGEE_XPPEN_TABLET_24_PRO): 1986 + rc = uclogic_params_init_ugee_xppen_pro(&p, 1987 + hdev, 1988 + uclogic_rdesc_xppen_artist_24_pro_pen_template_arr, 1989 + uclogic_rdesc_xppen_artist_24_pro_pen_template_size, 1990 + uclogic_rdesc_xppen_artist_24_pro_frame_arr, 1991 + uclogic_rdesc_xppen_artist_24_pro_frame_size, 1992 + 14); 1993 + 1994 + // The 24 Pro has a fragmented X Coord. 1995 + p.pen.fragmented_hires2 = true; 1996 + 1982 1997 if (rc != 0) 1983 1998 goto cleanup; 1984 1999
+5
drivers/hid/hid-uclogic-params.h
··· 103 103 * Only valid if "id" is not zero. 104 104 */ 105 105 bool tilt_y_flipped; 106 + /* 107 + * True, if reports include fragmented high resolution X coords. 108 + * This moves bytes 10-11 to the LSB of the X coordinate. 109 + */ 110 + bool fragmented_hires2; 106 111 }; 107 112 108 113 /*
+125
drivers/hid/hid-uclogic-rdesc.c
··· 1237 1237 const size_t uclogic_rdesc_xppen_artist_22r_pro_frame_size = 1238 1238 sizeof(uclogic_rdesc_xppen_artist_22r_pro_frame_arr); 1239 1239 1240 + /* Fixed report descriptor template for XP-PEN 24 Pro reports 1241 + * Mostly identical to uclogic_rdesc_ugee_v2_pen_template_arr except that the X coordinate has to be 1242 + * 32-bits instead of 16-bits. 1243 + */ 1244 + const __u8 uclogic_rdesc_xppen_artist_24_pro_pen_template_arr[] = { 1245 + 0x05, 0x0d, /* Usage Page (Digitizers), */ 1246 + 0x09, 0x01, /* Usage (Digitizer), */ 1247 + 0xa1, 0x01, /* Collection (Application), */ 1248 + 0x85, 0x02, /* Report ID (2), */ 1249 + 0x09, 0x20, /* Usage (Stylus), */ 1250 + 0xa1, 0x00, /* Collection (Physical), */ 1251 + 0x09, 0x42, /* Usage (Tip Switch), */ 1252 + 0x09, 0x44, /* Usage (Barrel Switch), */ 1253 + 0x09, 0x46, /* Usage (Tablet Pick), */ 1254 + 0x75, 0x01, /* Report Size (1), */ 1255 + 0x95, 0x03, /* Report Count (3), */ 1256 + 0x14, /* Logical Minimum (0), */ 1257 + 0x25, 0x01, /* Logical Maximum (1), */ 1258 + 0x81, 0x02, /* Input (Variable), */ 1259 + 0x95, 0x02, /* Report Count (2), */ 1260 + 0x81, 0x03, /* Input (Constant, Variable), */ 1261 + 0x09, 0x32, /* Usage (In Range), */ 1262 + 0x95, 0x01, /* Report Count (1), */ 1263 + 0x81, 0x02, /* Input (Variable), */ 1264 + 0x95, 0x02, /* Report Count (2), */ 1265 + 0x81, 0x03, /* Input (Constant, Variable), */ 1266 + 0x75, 0x10, /* Report Size (16), */ 1267 + 0x95, 0x01, /* Report Count (1), */ 1268 + 0x35, 0x00, /* Physical Minimum (0), */ 1269 + 0xa4, /* Push, */ 1270 + 0x05, 0x01, /* Usage Page (Desktop), */ 1271 + 0x09, 0x30, /* Usage (X), */ 1272 + 0x65, 0x13, /* Unit (Inch), */ 1273 + 0x55, 0x0d, /* Unit Exponent (-3), */ 1274 + 0x27, UCLOGIC_RDESC_PEN_PH(X_LM), 1275 + /* Logical Maximum (PLACEHOLDER), */ 1276 + 0x47, UCLOGIC_RDESC_PEN_PH(X_PM), 1277 + /* Physical Maximum (PLACEHOLDER), */ 1278 + 0x75, 0x20, /* Report Size (32), */ 1279 + 0x81, 0x02, /* Input (Variable), */ 1280 + 0x75, 0x10, /* Report Size (16), */ 1281 + 0x09, 0x31, /* Usage (Y), */ 1282 + 0x27, UCLOGIC_RDESC_PEN_PH(Y_LM), 1283 + /* Logical Maximum (PLACEHOLDER), */ 1284 + 0x47, UCLOGIC_RDESC_PEN_PH(Y_PM), 1285 + /* Physical Maximum (PLACEHOLDER), */ 1286 + 0x81, 0x02, /* Input (Variable), */ 1287 + 0xb4, /* Pop, */ 1288 + 0x09, 0x30, /* Usage (Tip Pressure), */ 1289 + 0x45, 0x00, /* Physical Maximum (0), */ 1290 + 0x27, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), 1291 + /* Logical Maximum (PLACEHOLDER), */ 1292 + 0x75, 0x0D, /* Report Size (13), */ 1293 + 0x95, 0x01, /* Report Count (1), */ 1294 + 0x81, 0x02, /* Input (Variable), */ 1295 + 0x75, 0x01, /* Report Size (1), */ 1296 + 0x95, 0x03, /* Report Count (3), */ 1297 + 0x81, 0x01, /* Input (Constant), */ 1298 + 0x09, 0x3d, /* Usage (X Tilt), */ 1299 + 0x35, 0xC3, /* Physical Minimum (-61), */ 1300 + 0x45, 0x3C, /* Physical Maximum (60), */ 1301 + 0x15, 0xC3, /* Logical Minimum (-61), */ 1302 + 0x25, 0x3C, /* Logical Maximum (60), */ 1303 + 0x75, 0x08, /* Report Size (8), */ 1304 + 0x95, 0x01, /* Report Count (1), */ 1305 + 0x81, 0x02, /* Input (Variable), */ 1306 + 0x09, 0x3e, /* Usage (Y Tilt), */ 1307 + 0x35, 0xC3, /* Physical Minimum (-61), */ 1308 + 0x45, 0x3C, /* Physical Maximum (60), */ 1309 + 0x15, 0xC3, /* Logical Minimum (-61), */ 1310 + 0x25, 0x3C, /* Logical Maximum (60), */ 1311 + 0x81, 0x02, /* Input (Variable), */ 1312 + 0xc0, /* End Collection, */ 1313 + 0xc0, /* End Collection */ 1314 + }; 1315 + const size_t uclogic_rdesc_xppen_artist_24_pro_pen_template_size = 1316 + sizeof(uclogic_rdesc_xppen_artist_24_pro_pen_template_arr); 1317 + 1318 + /* Fixed report descriptor for XP-Pen Arist 24 Pro frame */ 1319 + const __u8 uclogic_rdesc_xppen_artist_24_pro_frame_arr[] = { 1320 + 0x05, 0x01, /* Usage Page (Desktop), */ 1321 + 0x09, 0x07, /* Usage (Keypad), */ 1322 + 0xA1, 0x01, /* Collection (Application), */ 1323 + 0x85, UCLOGIC_RDESC_V1_FRAME_ID, 1324 + /* Report ID (Virtual report), */ 1325 + 0x05, 0x0D, /* Usage Page (Digitizer), */ 1326 + 0x09, 0x39, /* Usage (Tablet Function Keys), */ 1327 + 0xA0, /* Collection (Physical), */ 1328 + 0x14, /* Logical Minimum (0), */ 1329 + 0x25, 0x01, /* Logical Maximum (1), */ 1330 + 0x75, 0x01, /* Report Size (1), */ 1331 + 0x95, 0x08, /* Report Count (8), */ 1332 + 0x81, 0x01, /* Input (Constant), */ 1333 + 0x05, 0x09, /* Usage Page (Button), */ 1334 + 0x19, 0x01, /* Usage Minimum (01h), */ 1335 + 0x29, 0x14, /* Usage Maximum (14h), */ 1336 + 0x95, 0x14, /* Report Count (20), */ 1337 + 0x81, 0x02, /* Input (Variable), */ 1338 + 0x95, 0x14, /* Report Count (20), */ 1339 + 0x81, 0x01, /* Input (Constant), */ 1340 + 0x05, 0x01, /* Usage Page (Desktop), */ 1341 + 0x09, 0x38, /* Usage (Wheel), */ 1342 + 0x75, 0x08, /* Report Size (8), */ 1343 + 0x95, 0x01, /* Report Count (1), */ 1344 + 0x15, 0xFF, /* Logical Minimum (-1), */ 1345 + 0x25, 0x08, /* Logical Maximum (8), */ 1346 + 0x81, 0x06, /* Input (Variable, Relative), */ 1347 + 0x05, 0x0C, /* Usage Page (Consumer Devices), */ 1348 + 0x0A, 0x38, 0x02, /* Usage (AC PAN), */ 1349 + 0x95, 0x01, /* Report Count (1), */ 1350 + 0x81, 0x06, /* Input (Variable, Relative), */ 1351 + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ 1352 + 0x75, 0x08, /* Report Size (8), */ 1353 + 0x95, 0x01, /* Report Count (1), */ 1354 + 0x81, 0x02, /* Input (Variable), */ 1355 + 0x75, 0x01, /* Report Size (1), */ 1356 + 0x95, 16, /* Report Count (16), */ 1357 + 0x81, 0x01, /* Input (Constant), */ 1358 + 0xC0, /* End Collection */ 1359 + 0xC0, /* End Collection */ 1360 + }; 1361 + 1362 + const size_t uclogic_rdesc_xppen_artist_24_pro_frame_size = 1363 + sizeof(uclogic_rdesc_xppen_artist_24_pro_frame_arr); 1364 + 1240 1365 /** 1241 1366 * uclogic_rdesc_template_apply() - apply report descriptor parameters to a 1242 1367 * report descriptor template, creating a report descriptor. Copies the
+8
drivers/hid/hid-uclogic-rdesc.h
··· 214 214 extern const __u8 uclogic_rdesc_xppen_artist_22r_pro_frame_arr[]; 215 215 extern const size_t uclogic_rdesc_xppen_artist_22r_pro_frame_size; 216 216 217 + /* Fixed report descriptor for XP-Pen Arist 24 Pro frame */ 218 + extern const __u8 uclogic_rdesc_xppen_artist_24_pro_pen_template_arr[]; 219 + extern const size_t uclogic_rdesc_xppen_artist_24_pro_pen_template_size; 220 + 221 + /* Fixed report descriptor for XP-Pen Arist 24 Pro frame */ 222 + extern const __u8 uclogic_rdesc_xppen_artist_24_pro_frame_arr[]; 223 + extern const size_t uclogic_rdesc_xppen_artist_24_pro_frame_size; 224 + 217 225 #endif /* _HID_UCLOGIC_RDESC_H */