Skip to content

Commit

Permalink
XP-Pen Artist 15.6 Pro support
Browse files Browse the repository at this point in the history
  • Loading branch information
zan authored and Mel committed Aug 26, 2021
1 parent 4762230 commit 9a9947e
Show file tree
Hide file tree
Showing 5 changed files with 318 additions and 0 deletions.
1 change: 1 addition & 0 deletions hid-ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640 0x0094
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_A156P 0x090d
#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
Expand Down
54 changes: 54 additions & 0 deletions hid-uclogic-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include "compat.h"
#include <linux/version.h>
#include <asm/unaligned.h>

/* Driver data */
struct uclogic_drvdata {
Expand Down Expand Up @@ -458,6 +459,57 @@ static int uclogic_raw_event(struct hid_device *hdev,
report_id = data[0] = subreport->id;
continue;
} else {
/* A156P tilt compensation */
if (hdev->product == USB_DEVICE_ID_UGEE_XPPEN_TABLET_A156P &&
hdev->vendor == USB_VENDOR_ID_UGEE) {
/* All tangent lengths for pen angles 1-64
* degrees with a sensor height of 1.8mm
*/
const u16 tangents[] = {
3, 6, 9, 12, 15, 18, 21, 25, 28, 30, 33, 36,
39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70,
73, 76, 79, 82, 85, 88, 92, 95, 98, 102,
105, 109, 112, 116, 120, 124, 127, 131,
135, 140, 144, 148, 153, 158, 162, 167,
173, 178, 184, 189, 195, 202, 208, 215,
223, 231, 239, 247, 257, 266, 277
};
// sqrt(8) / 4 = 0.7071067811865476
const s32 discriminant = 707106781;
s8 tx = data[8];
s8 ty = data[9];
s8 abs_tilt;
s32 skew;

if (tx != 0 && ty != 0) {
abs_tilt = abs(tx);
skew = get_unaligned_le16(&data[2]) -
(tx / abs_tilt) * tangents[abs_tilt] *
discriminant / 10000000;
skew = clamp(skew, 0, 34419);
put_unaligned_le16(skew, &data[2]);

abs_tilt = abs(ty);
skew = get_unaligned_le16(&data[4]) -
(ty / abs_tilt) * tangents[abs_tilt] *
discriminant / 10000000;
skew = clamp(skew, 0, 19461);
put_unaligned_le16(skew, &data[4]);
} else if (tx != 0) {
abs_tilt = abs(tx);
skew = get_unaligned_le16(&data[2]) -
(tx / abs_tilt) * tangents[abs_tilt];
skew = clamp(skew, 0, 34419);
put_unaligned_le16(skew, &data[2]);
} else if (ty != 0) {
abs_tilt = abs(ty);
skew = get_unaligned_le16(&data[4]) -
(ty / abs_tilt) * tangents[abs_tilt];
skew = clamp(skew, 0, 19461);
put_unaligned_le16(skew, &data[4]);
}
}

return uclogic_raw_event_pen(drvdata, data, size);
}
}
Expand Down Expand Up @@ -534,6 +586,8 @@ static const struct hid_device_id uclogic_devices[] = {
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_A156P) },
{ }
};
MODULE_DEVICE_TABLE(hid, uclogic_devices);
Expand Down
153 changes: 153 additions & 0 deletions hid-uclogic-params.c
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,135 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
return rc;
}

/**
* uclogic_params_init_ugee_xppen_pro() - initialization procedure
* common to XP-Pen Pro series devices
*
* @hdev: The HID device of the tablet interface to initialize and get
* parameters from. Cannot be NULL.
* @params: Parameters to fill in (to be cleaned with
* uclogic_params_cleanup()). Not modified in case of error.
* Cannot be NULL.
* @interface: The device interface the control packet is sent to.
* @init_packet: Magic packet to send on usb to activate device.
* @packet_size: Size of the init packet.
* @rdesc_pen_arr: Pen report descriptor array.
* @rdesc_pen_size: Size of the pen array.
* @rdesc_frame_arr: Frame report descriptor array.
* @rdesc_frame_size: Size of the frame array.
*
* Returns:
* Zero, if successful. A negative errno code on error.
*/
static int uclogic_params_init_ugee_xppen_pro(struct hid_device *hdev,
struct uclogic_params *p, const uint8_t interface,
const u8 init_packet[], const size_t packet_size,
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 str_desc_len = 12;
struct usb_device *udev = hid_to_usb_dev(hdev);
u8 *buf = kmemdup(init_packet, packet_size, GFP_KERNEL);
s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
int actual_len, rc;
u16 resolution;

if (hdev == NULL || p == NULL)
return -EINVAL;

rc = usb_interrupt_msg(
udev,
usb_sndintpipe(udev, interface),
buf,
packet_size,
&actual_len,
USB_CTRL_SET_TIMEOUT);
kfree(buf);
if (rc == -EPIPE) {
hid_err(hdev,
"broken pipe sending init packet\n");
return rc;
} else if (rc < 0) {
hid_err(hdev, "failed sending init packet: %d\n", rc);
return rc;
} else if (actual_len != packet_size) {
hid_err(hdev,
"failed to transfer complete init packet, only %d bytes sent\n",
actual_len);
return -1;
}

rc = uclogic_params_get_str_desc(&buf, hdev, 100, str_desc_len);
if (rc != str_desc_len) {
if (rc == -EPIPE) {
hid_err(hdev,
"string descriptor with pen parameters not found\n");
} else if (rc < 0) {
hid_err(hdev,
"failed retrieving pen parameters: %d\n", rc);
} else {
hid_err(hdev,
"string descriptor with pen parameters has invalid length (got %d, expected %lu)\n",
rc, str_desc_len);
rc = -1;
}
kfree(buf);
return rc;
}

desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
get_unaligned_le16(buf + 2);
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
get_unaligned_le16(buf + 4);
/* buf + 6 is the number of pad buttons? Its 0x0008 */
desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
get_unaligned_le16(buf + 8);
resolution = get_unaligned_le16(buf + 10);
kfree(buf);
if (resolution == 0) {
hid_err(hdev, "resolution of 0 in descriptor string\n");
return -1;
}
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 / resolution;
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 / resolution;

hid_dbg(
hdev,
"Received parameters: X: %d Y: %d Pressure: %d Resolution: %u\n",
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM],
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM],
desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM],
resolution
);

p->pen.desc_ptr = uclogic_rdesc_template_apply(
rdesc_pen_arr,
rdesc_pen_size,
desc_params,
ARRAY_SIZE(desc_params)
);
p->pen.desc_size = rdesc_pen_size;
p->pen.id = 0x02;

rc = uclogic_params_frame_init_with_desc(
&p->frame_list[0],
rdesc_frame_arr,
rdesc_frame_size,
UCLOGIC_RDESC_V1_FRAME_ID
);
if (rc < 0) {
hid_err(hdev, "initializing frame params failed: %d\n", rc);
return rc;
}

p->pen.subreport_list[0].value = 0xf0;
p->pen.subreport_list[0].id = p->frame_list[0].id;

return 0;
}

/**
* uclogic_params_init() - initialize a tablet interface and discover its
* parameters.
Expand Down Expand Up @@ -1293,6 +1422,30 @@ int uclogic_params_init(struct uclogic_params *params,
uclogic_params_init_invalid(&p);
}

break;
case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_A156P):
static const u8 init_packet[] = {
0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const size_t packet_size = sizeof(init_packet);

/* Only use the uniform interface */
if (bInterfaceNumber != 2) {
uclogic_params_init_invalid(&p);
break;
}

rc = uclogic_params_init_ugee_xppen_pro(hdev, &p, 0x03, init_packet, packet_size,
uclogic_rdesc_xppen_a156p_pen_arr,
uclogic_rdesc_xppen_a156p_pen_size,
uclogic_rdesc_xppen_a156p_frame_arr,
uclogic_rdesc_xppen_a156p_frame_size);
if (rc != 0) {
hid_err(hdev, "a156p init failed: %d\n", rc);
goto cleanup;
}

break;
}

Expand Down
102 changes: 102 additions & 0 deletions hid-uclogic-rdesc.c
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,108 @@ const __u8 uclogic_rdesc_xppen_deco01_frame_arr[] = {
const size_t uclogic_rdesc_xppen_deco01_frame_size =
sizeof(uclogic_rdesc_xppen_deco01_frame_arr);

/* Report descriptor template for XP-Pen Artist 15.6 Pro pen */
const __u8 uclogic_rdesc_xppen_a156p_pen_arr[] = {
0x05, 0x0D, /* Usage Page (Digitizer), */
0x09, 0x02, /* Usage (Pen), */
0xA1, 0x01, /* Collection (Application), */
0x85, 0x02, /* Report ID (2), */
0x09, 0x20, /* Usage (Stylus), */
0xA0, /* Collection (Physical), */
0x14, /* Logical Minimum (0), */
0x25, 0x01, /* Logical Maximum (1), */
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), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x02, /* Report Count (2), */
0x81, 0x01, /* Input (Constant), */
0x09, 0x32, /* Usage (In Range), */
0x95, 0x01, /* Report Count (1), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x02, /* Report Count (2), */
0x81, 0x01, /* Input (Constant), */
0x75, 0x10, /* Report Size (16), */
0x95, 0x01, /* Report Count (1), */
0xA4, /* Push, */
0x05, 0x01, /* Usage Page (Desktop), */
0x55, 0xFD, /* Unit Exponent (-3), */
0x65, 0x13, /* Unit (Inch), */
0x34, /* Physical Minimum (0), */
0x09, 0x30, /* Usage (X), */
0x27, UCLOGIC_RDESC_PEN_PH(X_LM),
/* Logical Maximum (PLACEHOLDER), */
0x47, UCLOGIC_RDESC_PEN_PH(X_PM),
/* Physical Maximum (PLACEHOLDER), */
0x81, 0x02, /* Input (Variable), */
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), */
0x27, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM),
/* Logical Maximum (PLACEHOLDER), */
0x81, 0x02, /* Input (Variable), */
0xA4, /* Push, */
0x54, /* Unit Exponent (0), */
0x65, 0x14, /* Unit (Degrees), */
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, 0x02, /* Report Count (2), */
0x09, 0x3D, /* Usage (X Tilt), */
0x09, 0x3E, /* Usage (Y Tilt), */
0x81, 0x02, /* Input (Variable), */
0xB4, /* Pop, */
0xC0, /* End Collection, */
0xC0 /* End Collection */
};

const size_t uclogic_rdesc_xppen_a156p_pen_size =
sizeof(uclogic_rdesc_xppen_a156p_pen_arr);

/* Report descriptor template for XP-Pen Artist 15.6 Pro frame */
const __u8 uclogic_rdesc_xppen_a156p_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, 0x08, /* Usage Maximum (08h), */
0x95, 0x08, /* Report Count (8), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x20, /* Report Count (32), */
0x81, 0x01, /* Input (Constant), */
0x19, 0x09, /* Usage Minimum (09h), */
0x29, 0x0A, /* Usage Maximum (0Ah), */
0x95, 0x02, /* Report Count (2), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x16, /* Report Count (22), */
0x81, 0x01, /* Input (Constant), */
0xC0, /* End Collection, */
0xC0 /* End Collection */
};

const size_t uclogic_rdesc_xppen_a156p_frame_size =
sizeof(uclogic_rdesc_xppen_a156p_frame_arr);

/**
* uclogic_rdesc_template_apply() - apply report descriptor parameters to a
* report descriptor template, creating a report descriptor. Copies the
Expand Down
8 changes: 8 additions & 0 deletions hid-uclogic-rdesc.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,14 @@ extern const size_t uclogic_rdesc_xppen_deco01_frame_size;
extern const __u8 uclogic_rdesc_ugee_g5_frame_arr[];
extern const size_t uclogic_rdesc_ugee_g5_frame_size;

/* Report descriptor template for XP-Pen Artist 15.6 Pro pen */
extern const __u8 uclogic_rdesc_xppen_a156p_pen_arr[];
extern const size_t uclogic_rdesc_xppen_a156p_pen_size;

/* Report descriptor template for XP-Pen Artist 15.6 Pro frame */
extern const __u8 uclogic_rdesc_xppen_a156p_frame_arr[];
extern const size_t uclogic_rdesc_xppen_a156p_frame_size;

/* Report ID of Ugee G5 frame control reports */
#define UCLOGIC_RDESC_UGEE_G5_FRAME_ID 0x06

Expand Down

0 comments on commit 9a9947e

Please sign in to comment.