Skip to content

Commit 9a9947e

Browse files
zanMel
authored andcommitted
XP-Pen Artist 15.6 Pro support
1 parent 4762230 commit 9a9947e

File tree

5 files changed

+318
-0
lines changed

5 files changed

+318
-0
lines changed

hid-ids.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640 0x0094
5555
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042
5656
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078
57+
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_A156P 0x090d
5758
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
5859
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
5960
#define USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720 0x0055

hid-uclogic-core.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include "compat.h"
2626
#include <linux/version.h>
27+
#include <asm/unaligned.h>
2728

2829
/* Driver data */
2930
struct uclogic_drvdata {
@@ -458,6 +459,57 @@ static int uclogic_raw_event(struct hid_device *hdev,
458459
report_id = data[0] = subreport->id;
459460
continue;
460461
} else {
462+
/* A156P tilt compensation */
463+
if (hdev->product == USB_DEVICE_ID_UGEE_XPPEN_TABLET_A156P &&
464+
hdev->vendor == USB_VENDOR_ID_UGEE) {
465+
/* All tangent lengths for pen angles 1-64
466+
* degrees with a sensor height of 1.8mm
467+
*/
468+
const u16 tangents[] = {
469+
3, 6, 9, 12, 15, 18, 21, 25, 28, 30, 33, 36,
470+
39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70,
471+
73, 76, 79, 82, 85, 88, 92, 95, 98, 102,
472+
105, 109, 112, 116, 120, 124, 127, 131,
473+
135, 140, 144, 148, 153, 158, 162, 167,
474+
173, 178, 184, 189, 195, 202, 208, 215,
475+
223, 231, 239, 247, 257, 266, 277
476+
};
477+
// sqrt(8) / 4 = 0.7071067811865476
478+
const s32 discriminant = 707106781;
479+
s8 tx = data[8];
480+
s8 ty = data[9];
481+
s8 abs_tilt;
482+
s32 skew;
483+
484+
if (tx != 0 && ty != 0) {
485+
abs_tilt = abs(tx);
486+
skew = get_unaligned_le16(&data[2]) -
487+
(tx / abs_tilt) * tangents[abs_tilt] *
488+
discriminant / 10000000;
489+
skew = clamp(skew, 0, 34419);
490+
put_unaligned_le16(skew, &data[2]);
491+
492+
abs_tilt = abs(ty);
493+
skew = get_unaligned_le16(&data[4]) -
494+
(ty / abs_tilt) * tangents[abs_tilt] *
495+
discriminant / 10000000;
496+
skew = clamp(skew, 0, 19461);
497+
put_unaligned_le16(skew, &data[4]);
498+
} else if (tx != 0) {
499+
abs_tilt = abs(tx);
500+
skew = get_unaligned_le16(&data[2]) -
501+
(tx / abs_tilt) * tangents[abs_tilt];
502+
skew = clamp(skew, 0, 34419);
503+
put_unaligned_le16(skew, &data[2]);
504+
} else if (ty != 0) {
505+
abs_tilt = abs(ty);
506+
skew = get_unaligned_le16(&data[4]) -
507+
(ty / abs_tilt) * tangents[abs_tilt];
508+
skew = clamp(skew, 0, 19461);
509+
put_unaligned_le16(skew, &data[4]);
510+
}
511+
}
512+
461513
return uclogic_raw_event_pen(drvdata, data, size);
462514
}
463515
}
@@ -534,6 +586,8 @@ static const struct hid_device_id uclogic_devices[] = {
534586
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) },
535587
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
536588
USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) },
589+
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
590+
USB_DEVICE_ID_UGEE_XPPEN_TABLET_A156P) },
537591
{ }
538592
};
539593
MODULE_DEVICE_TABLE(hid, uclogic_devices);

hid-uclogic-params.c

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,135 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
998998
return rc;
999999
}
10001000

1001+
/**
1002+
* uclogic_params_init_ugee_xppen_pro() - initialization procedure
1003+
* common to XP-Pen Pro series devices
1004+
*
1005+
* @hdev: The HID device of the tablet interface to initialize and get
1006+
* parameters from. Cannot be NULL.
1007+
* @params: Parameters to fill in (to be cleaned with
1008+
* uclogic_params_cleanup()). Not modified in case of error.
1009+
* Cannot be NULL.
1010+
* @interface: The device interface the control packet is sent to.
1011+
* @init_packet: Magic packet to send on usb to activate device.
1012+
* @packet_size: Size of the init packet.
1013+
* @rdesc_pen_arr: Pen report descriptor array.
1014+
* @rdesc_pen_size: Size of the pen array.
1015+
* @rdesc_frame_arr: Frame report descriptor array.
1016+
* @rdesc_frame_size: Size of the frame array.
1017+
*
1018+
* Returns:
1019+
* Zero, if successful. A negative errno code on error.
1020+
*/
1021+
static int uclogic_params_init_ugee_xppen_pro(struct hid_device *hdev,
1022+
struct uclogic_params *p, const uint8_t interface,
1023+
const u8 init_packet[], const size_t packet_size,
1024+
const u8 rdesc_pen_arr[], const size_t rdesc_pen_size,
1025+
const u8 rdesc_frame_arr[], const size_t rdesc_frame_size)
1026+
{
1027+
const size_t str_desc_len = 12;
1028+
struct usb_device *udev = hid_to_usb_dev(hdev);
1029+
u8 *buf = kmemdup(init_packet, packet_size, GFP_KERNEL);
1030+
s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
1031+
int actual_len, rc;
1032+
u16 resolution;
1033+
1034+
if (hdev == NULL || p == NULL)
1035+
return -EINVAL;
1036+
1037+
rc = usb_interrupt_msg(
1038+
udev,
1039+
usb_sndintpipe(udev, interface),
1040+
buf,
1041+
packet_size,
1042+
&actual_len,
1043+
USB_CTRL_SET_TIMEOUT);
1044+
kfree(buf);
1045+
if (rc == -EPIPE) {
1046+
hid_err(hdev,
1047+
"broken pipe sending init packet\n");
1048+
return rc;
1049+
} else if (rc < 0) {
1050+
hid_err(hdev, "failed sending init packet: %d\n", rc);
1051+
return rc;
1052+
} else if (actual_len != packet_size) {
1053+
hid_err(hdev,
1054+
"failed to transfer complete init packet, only %d bytes sent\n",
1055+
actual_len);
1056+
return -1;
1057+
}
1058+
1059+
rc = uclogic_params_get_str_desc(&buf, hdev, 100, str_desc_len);
1060+
if (rc != str_desc_len) {
1061+
if (rc == -EPIPE) {
1062+
hid_err(hdev,
1063+
"string descriptor with pen parameters not found\n");
1064+
} else if (rc < 0) {
1065+
hid_err(hdev,
1066+
"failed retrieving pen parameters: %d\n", rc);
1067+
} else {
1068+
hid_err(hdev,
1069+
"string descriptor with pen parameters has invalid length (got %d, expected %lu)\n",
1070+
rc, str_desc_len);
1071+
rc = -1;
1072+
}
1073+
kfree(buf);
1074+
return rc;
1075+
}
1076+
1077+
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
1078+
get_unaligned_le16(buf + 2);
1079+
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
1080+
get_unaligned_le16(buf + 4);
1081+
/* buf + 6 is the number of pad buttons? Its 0x0008 */
1082+
desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
1083+
get_unaligned_le16(buf + 8);
1084+
resolution = get_unaligned_le16(buf + 10);
1085+
kfree(buf);
1086+
if (resolution == 0) {
1087+
hid_err(hdev, "resolution of 0 in descriptor string\n");
1088+
return -1;
1089+
}
1090+
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
1091+
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 / resolution;
1092+
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
1093+
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 / resolution;
1094+
1095+
hid_dbg(
1096+
hdev,
1097+
"Received parameters: X: %d Y: %d Pressure: %d Resolution: %u\n",
1098+
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM],
1099+
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM],
1100+
desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM],
1101+
resolution
1102+
);
1103+
1104+
p->pen.desc_ptr = uclogic_rdesc_template_apply(
1105+
rdesc_pen_arr,
1106+
rdesc_pen_size,
1107+
desc_params,
1108+
ARRAY_SIZE(desc_params)
1109+
);
1110+
p->pen.desc_size = rdesc_pen_size;
1111+
p->pen.id = 0x02;
1112+
1113+
rc = uclogic_params_frame_init_with_desc(
1114+
&p->frame_list[0],
1115+
rdesc_frame_arr,
1116+
rdesc_frame_size,
1117+
UCLOGIC_RDESC_V1_FRAME_ID
1118+
);
1119+
if (rc < 0) {
1120+
hid_err(hdev, "initializing frame params failed: %d\n", rc);
1121+
return rc;
1122+
}
1123+
1124+
p->pen.subreport_list[0].value = 0xf0;
1125+
p->pen.subreport_list[0].id = p->frame_list[0].id;
1126+
1127+
return 0;
1128+
}
1129+
10011130
/**
10021131
* uclogic_params_init() - initialize a tablet interface and discover its
10031132
* parameters.
@@ -1293,6 +1422,30 @@ int uclogic_params_init(struct uclogic_params *params,
12931422
uclogic_params_init_invalid(&p);
12941423
}
12951424

1425+
break;
1426+
case VID_PID(USB_VENDOR_ID_UGEE,
1427+
USB_DEVICE_ID_UGEE_XPPEN_TABLET_A156P):
1428+
static const u8 init_packet[] = {
1429+
0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1430+
};
1431+
const size_t packet_size = sizeof(init_packet);
1432+
1433+
/* Only use the uniform interface */
1434+
if (bInterfaceNumber != 2) {
1435+
uclogic_params_init_invalid(&p);
1436+
break;
1437+
}
1438+
1439+
rc = uclogic_params_init_ugee_xppen_pro(hdev, &p, 0x03, init_packet, packet_size,
1440+
uclogic_rdesc_xppen_a156p_pen_arr,
1441+
uclogic_rdesc_xppen_a156p_pen_size,
1442+
uclogic_rdesc_xppen_a156p_frame_arr,
1443+
uclogic_rdesc_xppen_a156p_frame_size);
1444+
if (rc != 0) {
1445+
hid_err(hdev, "a156p init failed: %d\n", rc);
1446+
goto cleanup;
1447+
}
1448+
12961449
break;
12971450
}
12981451

hid-uclogic-rdesc.c

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,108 @@ const __u8 uclogic_rdesc_xppen_deco01_frame_arr[] = {
975975
const size_t uclogic_rdesc_xppen_deco01_frame_size =
976976
sizeof(uclogic_rdesc_xppen_deco01_frame_arr);
977977

978+
/* Report descriptor template for XP-Pen Artist 15.6 Pro pen */
979+
const __u8 uclogic_rdesc_xppen_a156p_pen_arr[] = {
980+
0x05, 0x0D, /* Usage Page (Digitizer), */
981+
0x09, 0x02, /* Usage (Pen), */
982+
0xA1, 0x01, /* Collection (Application), */
983+
0x85, 0x02, /* Report ID (2), */
984+
0x09, 0x20, /* Usage (Stylus), */
985+
0xA0, /* Collection (Physical), */
986+
0x14, /* Logical Minimum (0), */
987+
0x25, 0x01, /* Logical Maximum (1), */
988+
0x09, 0x42, /* Usage (Tip Switch), */
989+
0x09, 0x44, /* Usage (Barrel Switch), */
990+
0x09, 0x46, /* Usage (Tablet Pick), */
991+
0x75, 0x01, /* Report Size (1), */
992+
0x95, 0x03, /* Report Count (3), */
993+
0x81, 0x02, /* Input (Variable), */
994+
0x95, 0x02, /* Report Count (2), */
995+
0x81, 0x01, /* Input (Constant), */
996+
0x09, 0x32, /* Usage (In Range), */
997+
0x95, 0x01, /* Report Count (1), */
998+
0x81, 0x02, /* Input (Variable), */
999+
0x95, 0x02, /* Report Count (2), */
1000+
0x81, 0x01, /* Input (Constant), */
1001+
0x75, 0x10, /* Report Size (16), */
1002+
0x95, 0x01, /* Report Count (1), */
1003+
0xA4, /* Push, */
1004+
0x05, 0x01, /* Usage Page (Desktop), */
1005+
0x55, 0xFD, /* Unit Exponent (-3), */
1006+
0x65, 0x13, /* Unit (Inch), */
1007+
0x34, /* Physical Minimum (0), */
1008+
0x09, 0x30, /* Usage (X), */
1009+
0x27, UCLOGIC_RDESC_PEN_PH(X_LM),
1010+
/* Logical Maximum (PLACEHOLDER), */
1011+
0x47, UCLOGIC_RDESC_PEN_PH(X_PM),
1012+
/* Physical Maximum (PLACEHOLDER), */
1013+
0x81, 0x02, /* Input (Variable), */
1014+
0x09, 0x31, /* Usage (Y), */
1015+
0x27, UCLOGIC_RDESC_PEN_PH(Y_LM),
1016+
/* Logical Maximum (PLACEHOLDER), */
1017+
0x47, UCLOGIC_RDESC_PEN_PH(Y_PM),
1018+
/* Physical Maximum (PLACEHOLDER), */
1019+
0x81, 0x02, /* Input (Variable), */
1020+
0xB4, /* Pop, */
1021+
0x09, 0x30, /* Usage (Tip Pressure), */
1022+
0x27, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM),
1023+
/* Logical Maximum (PLACEHOLDER), */
1024+
0x81, 0x02, /* Input (Variable), */
1025+
0xA4, /* Push, */
1026+
0x54, /* Unit Exponent (0), */
1027+
0x65, 0x14, /* Unit (Degrees), */
1028+
0x35, 0xC3, /* Physical Minimum (-61), */
1029+
0x45, 0x3C, /* Physical Maximum (60), */
1030+
0x15, 0xC3, /* Logical Minimum (-61), */
1031+
0x25, 0x3C, /* Logical Maximum (60), */
1032+
0x75, 0x08, /* Report Size (8), */
1033+
0x95, 0x02, /* Report Count (2), */
1034+
0x09, 0x3D, /* Usage (X Tilt), */
1035+
0x09, 0x3E, /* Usage (Y Tilt), */
1036+
0x81, 0x02, /* Input (Variable), */
1037+
0xB4, /* Pop, */
1038+
0xC0, /* End Collection, */
1039+
0xC0 /* End Collection */
1040+
};
1041+
1042+
const size_t uclogic_rdesc_xppen_a156p_pen_size =
1043+
sizeof(uclogic_rdesc_xppen_a156p_pen_arr);
1044+
1045+
/* Report descriptor template for XP-Pen Artist 15.6 Pro frame */
1046+
const __u8 uclogic_rdesc_xppen_a156p_frame_arr[] = {
1047+
0x05, 0x01, /* Usage Page (Desktop), */
1048+
0x09, 0x07, /* Usage (Keypad), */
1049+
0xA1, 0x01, /* Collection (Application), */
1050+
0x85, UCLOGIC_RDESC_V1_FRAME_ID,
1051+
/* Report ID (Virtual report), */
1052+
0x05, 0x0D, /* Usage Page (Digitizer), */
1053+
0x09, 0x39, /* Usage (Tablet Function Keys), */
1054+
0xA0, /* Collection (Physical), */
1055+
0x14, /* Logical Minimum (0), */
1056+
0x25, 0x01, /* Logical Maximum (1), */
1057+
0x75, 0x01, /* Report Size (1), */
1058+
0x95, 0x08, /* Report Count (8), */
1059+
0x81, 0x01, /* Input (Constant), */
1060+
0x05, 0x09, /* Usage Page (Button), */
1061+
0x19, 0x01, /* Usage Minimum (01h), */
1062+
0x29, 0x08, /* Usage Maximum (08h), */
1063+
0x95, 0x08, /* Report Count (8), */
1064+
0x81, 0x02, /* Input (Variable), */
1065+
0x95, 0x20, /* Report Count (32), */
1066+
0x81, 0x01, /* Input (Constant), */
1067+
0x19, 0x09, /* Usage Minimum (09h), */
1068+
0x29, 0x0A, /* Usage Maximum (0Ah), */
1069+
0x95, 0x02, /* Report Count (2), */
1070+
0x81, 0x02, /* Input (Variable), */
1071+
0x95, 0x16, /* Report Count (22), */
1072+
0x81, 0x01, /* Input (Constant), */
1073+
0xC0, /* End Collection, */
1074+
0xC0 /* End Collection */
1075+
};
1076+
1077+
const size_t uclogic_rdesc_xppen_a156p_frame_size =
1078+
sizeof(uclogic_rdesc_xppen_a156p_frame_arr);
1079+
9781080
/**
9791081
* uclogic_rdesc_template_apply() - apply report descriptor parameters to a
9801082
* report descriptor template, creating a report descriptor. Copies the

hid-uclogic-rdesc.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,14 @@ extern const size_t uclogic_rdesc_xppen_deco01_frame_size;
167167
extern const __u8 uclogic_rdesc_ugee_g5_frame_arr[];
168168
extern const size_t uclogic_rdesc_ugee_g5_frame_size;
169169

170+
/* Report descriptor template for XP-Pen Artist 15.6 Pro pen */
171+
extern const __u8 uclogic_rdesc_xppen_a156p_pen_arr[];
172+
extern const size_t uclogic_rdesc_xppen_a156p_pen_size;
173+
174+
/* Report descriptor template for XP-Pen Artist 15.6 Pro frame */
175+
extern const __u8 uclogic_rdesc_xppen_a156p_frame_arr[];
176+
extern const size_t uclogic_rdesc_xppen_a156p_frame_size;
177+
170178
/* Report ID of Ugee G5 frame control reports */
171179
#define UCLOGIC_RDESC_UGEE_G5_FRAME_ID 0x06
172180

0 commit comments

Comments
 (0)