diff --git a/hid-uclogic-params.c b/hid-uclogic-params.c index e4b7cebc..eeb3c6ed 100644 --- a/hid-uclogic-params.c +++ b/hid-uclogic-params.c @@ -233,6 +233,87 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen, return rc; } +/** + * uclogic_params_pen_init_mast10() - initialize tablet interface pen + * input and retrieve its parameters from the device, using v1 protocol. + * + * @pen: Pointer to the pen parameters to initialize (to be + * cleaned up with uclogic_params_pen_cleanup()). Not modified in + * case of error, or if parameters are not found. Cannot be NULL. + * @pfound: Location for a flag which is set to true if the parameters + * were found, and to false if not (e.g. device was + * incompatible). Not modified in case of error. Cannot be NULL. + * @hdev: The HID device of the tablet interface to initialize and get + * parameters from. Cannot be NULL. + * + * Returns: + * Zero, if successful. A negative errno code on error. + */ +static int uclogic_params_pen_init_mast10(struct uclogic_params_pen *pen, + bool *pfound, + struct hid_device *hdev) +{ + int rc; + bool found = false; + /* Buffer for (part of) the string descriptor */ + __u8 *buf = NULL; + /* Minimum descriptor length required, maximum seen so far is 18 */ + const int len = 12; + __u8 *desc_copy_ptr = NULL; + + /* Check arguments */ + if (pen == NULL || pfound == NULL || hdev == NULL) { + rc = -EINVAL; + goto cleanup; + } + + /* + * Read string descriptor containing pen input parameters. + * The specific string descriptor and data were discovered by sniffing + * the Windows driver traffic. + * NOTE: This enables fully-functional tablet mode. + */ + rc = uclogic_params_get_str_desc(&buf, hdev, 100, len); + if (rc == -EPIPE) { + hid_dbg(hdev, + "string descriptor with pen parameters not found, assuming not compatible\n"); + goto finish; + } else if (rc < 0) { + hid_err(hdev, "failed retrieving pen parameters: %d\n", rc); + goto cleanup; + } else if (rc != len) { + hid_dbg(hdev, + "string descriptor with pen parameters has invalid length (got %d, expected %d), assuming not compatible\n", + rc, len); + goto finish; + } + + kfree(buf); + buf = NULL; + + desc_copy_ptr = kmemdup(uclogic_rdesc_mast10_fixed0_arr, uclogic_rdesc_mast10_fixed0_size, GFP_KERNEL); + if (desc_copy_ptr == NULL) { + rc = -ENOMEM; + goto cleanup; + } + + /* + * Fill-in the parameters + */ + memset(pen, 0, sizeof(*pen)); + pen->desc_ptr = desc_copy_ptr; + desc_copy_ptr = NULL; + pen->desc_size = uclogic_rdesc_mast10_fixed0_size; + found = true; +finish: + *pfound = found; + rc = 0; +cleanup: + kfree(desc_copy_ptr); + kfree(buf); + return rc; +} + /** * uclogic_params_get_le24() - get a 24-bit little-endian number from a * buffer. @@ -989,6 +1070,19 @@ int uclogic_params_init(struct uclogic_params *params, USB_DEVICE_ID_HUION_TABLET): case VID_PID(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_YIYNOVA_TABLET): + if (hdev->dev_rsize == UCLOGIC_RDESC_MAST10_ORIG0_SIZE && + bInterfaceNumber == 0) { + rc = uclogic_params_pen_init_mast10(&p.pen, &found, hdev); + if (rc != 0) { + hid_err(hdev, "pen probing failed: %d\n", rc); + goto cleanup; + } + if (!found) { + hid_warn(hdev, "pen parameters not found"); + uclogic_params_init_invalid(&p); + } + break; + } case VID_PID(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81): case VID_PID(USB_VENDOR_ID_UCLOGIC, diff --git a/hid-uclogic-rdesc.c b/hid-uclogic-rdesc.c index 2c02b0de..e2926b7e 100644 --- a/hid-uclogic-rdesc.c +++ b/hid-uclogic-rdesc.c @@ -827,6 +827,57 @@ const __u8 uclogic_rdesc_xppen_deco01_frame_arr[] = { const size_t uclogic_rdesc_xppen_deco01_frame_size = sizeof(uclogic_rdesc_xppen_deco01_frame_arr); +/* Fixed Mast10 report descriptor, interface 0 (stylus) */ +__u8 uclogic_rdesc_mast10_fixed0_arr[] = { + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x02, /* Usage (Pen), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, 0x07, /* Report ID (7), */ + 0x09, 0x20, /* Usage (Stylus), */ + 0xA0, /* Collection (Physical), */ + 0x14, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x75, 0x01, /* Report Size (1), */ + 0x09, 0x42, /* Usage (Tip Switch), */ + 0x09, 0x44, /* Usage (Barrel Switch), */ + 0x09, 0x46, /* Usage (Tablet Pick), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x09, 0x32, /* Usage (In Range), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x75, 0x10, /* Report Size (16), */ + 0x95, 0x01, /* Report Count (1), */ + 0xA4, /* Push, */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x65, 0x13, /* Unit (Inch), */ + 0x55, 0xFD, /* Unit Exponent (-3), */ + 0x34, /* Physical Minimum (0), */ + 0x09, 0x30, /* Usage (X), */ + 0x26, 0xBE, 0x54, /* Logical Maximum (21694), */ + 0x46, 0x5D, 0x21, /* Physical Maximum (8541), */ + 0x81, 0x02, /* Input (Variable), */ + 0x09, 0x31, /* Usage (Y), */ + 0x26, 0xF6, 0x34, /* Logical Maximum (13558), */ + 0x46, 0xDA, 0x14, /* Physical Maximum (5338), */ + 0x81, 0x02, /* Input (Variable), */ + 0xB4, /* Pop, */ + 0x09, 0x30, /* Usage (Tip Pressure), */ + 0x26, 0xFF, 0x07, /* Logical Maximum (2047), */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x10, /* Report Size (16), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0xC0, /* End Collection, */ + 0xC0 /* End Collection */ +}; +const size_t uclogic_rdesc_mast10_fixed0_size = + sizeof(uclogic_rdesc_mast10_fixed0_arr); + /** * uclogic_rdesc_template_apply() - apply report descriptor parameters to a * report descriptor template, creating a report descriptor. Copies the diff --git a/hid-uclogic-rdesc.h b/hid-uclogic-rdesc.h index c5da5105..5c20aed3 100644 --- a/hid-uclogic-rdesc.h +++ b/hid-uclogic-rdesc.h @@ -152,4 +152,11 @@ extern const size_t uclogic_rdesc_ugee_g5_frame_size; /* Least-significant bit of Ugee G5 frame rotary encoder state */ #define UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB 38 +/* Size of the original descriptors of Mast10 tablet */ +#define UCLOGIC_RDESC_MAST10_ORIG0_SIZE 192 + +/* Fixed report descriptor for Mast10 tablet */ +extern __u8 uclogic_rdesc_mast10_fixed0_arr[]; +extern const size_t uclogic_rdesc_mast10_fixed0_size; + #endif /* _HID_UCLOGIC_RDESC_H */