// SPDX-License-Identifier: GPL-2.0+ /* * HID driver for UC-Logic devices not fully compliant with HID standard * - tablet initialization and parameter retrieval * * Copyright (c) 2018 Nikolai Kondrashov
*/
/* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version.
*/
/** * uclogic_params_pen_inrange_to_str() - Convert a pen in-range reporting type * to a string. * @inrange: The in-range reporting type to convert. * * Return: * * The string representing the type, or * * %NULL if the type is unknown.
*/ staticconstchar *uclogic_params_pen_inrange_to_str( enum uclogic_params_pen_inrange inrange)
{ switch (inrange) { case UCLOGIC_PARAMS_PEN_INRANGE_NORMAL: return"normal"; case UCLOGIC_PARAMS_PEN_INRANGE_INVERTED: return"inverted"; case UCLOGIC_PARAMS_PEN_INRANGE_NONE: return"none"; default: return NULL;
}
}
/** * uclogic_params_pen_hid_dbg() - Dump tablet interface pen parameters * @hdev: The HID device the pen parameters describe. * @pen: The pen parameters to dump. * * Dump tablet interface pen parameters with hid_dbg(). The dump is indented * with a tab.
*/ staticvoid uclogic_params_pen_hid_dbg(conststruct hid_device *hdev, conststruct uclogic_params_pen *pen)
{
size_t i;
/** * uclogic_params_get_str_desc - retrieve a string descriptor from a HID * device interface, putting it into a kmalloc-allocated buffer as is, without * character encoding conversion. * * @pbuf: Location for the kmalloc-allocated buffer pointer containing * the retrieved descriptor. Not modified in case of error. * Can be NULL to have retrieved descriptor discarded. * @hdev: The HID device of the tablet interface to retrieve the string * descriptor from. Cannot be NULL. * @idx: Index of the string descriptor to request from the device. * @len: Length of the buffer to allocate and the data to retrieve. * * Returns: * number of bytes retrieved (<= len), * -EPIPE, if the descriptor was not found, or * another negative errno code in case of other error.
*/ staticint uclogic_params_get_str_desc(__u8 **pbuf, struct hid_device *hdev,
__u8 idx, size_t len)
{ int rc; struct usb_device *udev;
__u8 *buf = NULL;
/** * uclogic_params_pen_cleanup - free resources used by struct * uclogic_params_pen (tablet interface's pen input parameters). * Can be called repeatedly. * * @pen: Pen input parameters to cleanup. Cannot be NULL.
*/ staticvoid uclogic_params_pen_cleanup(struct uclogic_params_pen *pen)
{
kfree(pen->desc_ptr);
memset(pen, 0, sizeof(*pen));
}
/** * uclogic_params_pen_init_v1() - 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.
*/ staticint uclogic_params_pen_init_v1(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 */ constint len = 12;
s32 resolution; /* Pen report descriptor template parameters */
s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
__u8 *desc_ptr = NULL;
/** * uclogic_params_get_le24() - get a 24-bit little-endian number from a * buffer. * * @p: The pointer to the number buffer. * * Returns: * The retrieved number
*/ static s32 uclogic_params_get_le24(constvoid *p)
{ const __u8 *b = p; return b[0] | (b[1] << 8UL) | (b[2] << 16UL);
}
/** * uclogic_params_pen_init_v2() - initialize tablet interface pen * input and retrieve its parameters from the device, using v2 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. * @pparams_ptr: Location for a kmalloc'ed pointer to the retrieved raw * parameters, which could be used to identify the tablet * to some extent. Should be freed with kfree after use. * NULL, if not needed. Not modified in case of error. * Only set if *pfound is set to true. * @pparams_len: Location for the length of the retrieved raw * parameters. NULL, if not needed. Not modified in case * of error. Only set if *pfound is set to true. * @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.
*/ staticint uclogic_params_pen_init_v2(struct uclogic_params_pen *pen, bool *pfound,
__u8 **pparams_ptr,
size_t *pparams_len, struct hid_device *hdev)
{ int rc; bool found = false; /* Buffer for (part of) the parameter string descriptor */
__u8 *buf = NULL; /* Parameter string descriptor required length */ constint params_len_min = 18; /* Parameter string descriptor accepted length */ constint params_len_max = 32; /* Parameter string descriptor received length */ int params_len;
size_t i;
s32 resolution; /* Pen report descriptor template parameters */
s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
__u8 *desc_ptr = NULL;
/* * 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, 200, params_len_max); if (rc == -EPIPE) {
hid_dbg(hdev, "string descriptor with pen parameters not found, assuming not compatible\n"); goto finish;
} elseif (rc < 0) {
hid_err(hdev, "failed retrieving pen parameters: %d\n", rc); goto cleanup;
} elseif (rc < params_len_min) {
hid_dbg(hdev, "string descriptor with pen parameters is too short (got %d, expected at least %d), assuming not compatible\n",
rc, params_len_min); goto finish;
}
params_len = rc;
/* * Check it's not just a catch-all UTF-16LE-encoded ASCII * string (such as the model name) some tablets put into all * unknown string descriptors.
*/ for (i = 2;
i < params_len &&
(buf[i] >= 0x20 && buf[i] < 0x7f && buf[i + 1] == 0);
i += 2); if (i >= params_len) {
hid_dbg(hdev, "string descriptor with pen parameters seems to contain only text, assuming not compatible\n"); goto finish;
}
/** * uclogic_params_frame_cleanup - free resources used by struct * uclogic_params_frame (tablet interface's frame controls input parameters). * Can be called repeatedly. * * @frame: Frame controls input parameters to cleanup. Cannot be NULL.
*/ staticvoid uclogic_params_frame_cleanup(struct uclogic_params_frame *frame)
{
kfree(frame->desc_ptr);
memset(frame, 0, sizeof(*frame));
}
/** * uclogic_params_frame_init_with_desc() - initialize tablet's frame control * parameters with a static report descriptor. * * @frame: Pointer to the frame parameters to initialize (to be cleaned * up with uclogic_params_frame_cleanup()). Not modified in case * of error. Cannot be NULL. * @desc_ptr: Report descriptor pointer. Can be NULL, if desc_size is zero. * @desc_size: Report descriptor size. * @id: Report ID used for frame reports, if they should be tweaked, * zero if not. * * Returns: * Zero, if successful. A negative errno code on error.
*/ staticint uclogic_params_frame_init_with_desc( struct uclogic_params_frame *frame, const __u8 *desc_ptr,
size_t desc_size, unsignedint id)
{
__u8 *copy_desc_ptr;
/** * uclogic_params_frame_init_v1() - initialize v1 tablet interface frame * controls. * * @frame: Pointer to the frame parameters to initialize (to be cleaned * up with uclogic_params_frame_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.
*/ staticint uclogic_params_frame_init_v1(struct uclogic_params_frame *frame, bool *pfound, struct hid_device *hdev)
{ int rc; bool found = false; struct usb_device *usb_dev; char *str_buf = NULL; const size_t str_len = 16;
/** * uclogic_params_cleanup_event_hooks - free resources used by the list of raw * event hooks. * Can be called repeatedly. * * @params: Input parameters to cleanup. Cannot be NULL.
*/ staticvoid uclogic_params_cleanup_event_hooks(struct uclogic_params *params)
{ struct uclogic_raw_event_hook *curr, *n;
if (!params || !params->event_hooks) return;
list_for_each_entry_safe(curr, n, ¶ms->event_hooks->list, list) {
cancel_work_sync(&curr->work);
list_del(&curr->list);
kfree(curr->event);
kfree(curr);
}
/** * uclogic_params_cleanup - free resources used by struct uclogic_params * (tablet interface's parameters). * Can be called repeatedly. * * @params: Input parameters to cleanup. Cannot be NULL.
*/ void uclogic_params_cleanup(struct uclogic_params *params)
{ if (!params->invalid) {
size_t i;
kfree(params->desc_ptr);
uclogic_params_pen_cleanup(¶ms->pen); for (i = 0; i < ARRAY_SIZE(params->frame_list); i++)
uclogic_params_frame_cleanup(¶ms->frame_list[i]);
/** * uclogic_params_get_desc() - Get a replacement report descriptor for a * tablet's interface. * * @params: The parameters of a tablet interface to get report * descriptor for. Cannot be NULL. * @pdesc: Location for the resulting, kmalloc-allocated report * descriptor pointer, or for NULL, if there's no replacement * report descriptor. Not modified in case of error. Cannot be * NULL. * @psize: Location for the resulting report descriptor size, not set if * there's no replacement report descriptor. Not modified in case * of error. Cannot be NULL. * * Returns: * Zero, if successful. * -EINVAL, if invalid arguments are supplied. * -ENOMEM, if failed to allocate memory.
*/ int uclogic_params_get_desc(conststruct uclogic_params *params, const __u8 **pdesc, unsignedint *psize)
{ int rc = -ENOMEM; bool present = false; unsignedint size = 0;
__u8 *desc = NULL;
size_t i;
/** * uclogic_params_init_invalid() - initialize tablet interface parameters, * specifying the interface is invalid. * * @params: Parameters to initialize (to be cleaned with * uclogic_params_cleanup()). Cannot be NULL.
*/ staticvoid uclogic_params_init_invalid(struct uclogic_params *params)
{
params->invalid = true;
}
/** * uclogic_params_init_with_opt_desc() - initialize tablet interface * parameters with an optional replacement report descriptor. Only modify * report descriptor, if the original report descriptor matches the expected * size. * * @params: Parameters to initialize (to be cleaned with * uclogic_params_cleanup()). Not modified in case of * error. Cannot be NULL. * @hdev: The HID device of the tablet interface create the * parameters for. Cannot be NULL. * @orig_desc_size: Expected size of the original report descriptor to * be replaced. * @desc_ptr: Pointer to the replacement report descriptor. * Can be NULL, if desc_size is zero. * @desc_size: Size of the replacement report descriptor. * * Returns: * Zero, if successful. -EINVAL if an invalid argument was passed. * -ENOMEM, if failed to allocate memory.
*/ staticint uclogic_params_init_with_opt_desc(struct uclogic_params *params, struct hid_device *hdev, unsignedint orig_desc_size, const __u8 *desc_ptr, unsignedint desc_size)
{
__u8 *desc_copy_ptr = NULL; unsignedint desc_copy_size; int rc;
/** * uclogic_probe_interface() - some tablets, like the Parblo A610 PLUS V2 or * the XP-PEN Deco Mini 7, need to be initialized by sending them magic data. * * @hdev: The HID device of the tablet interface to initialize and get * parameters from. Cannot be NULL. * @magic_arr: The magic data that should be sent to probe the interface. * Cannot be NULL. * @magic_size: Size of the magic data. * @endpoint: Endpoint where the magic data should be sent. * * Returns: * Zero, if successful. A negative errno code on error.
*/ staticint uclogic_probe_interface(struct hid_device *hdev, const u8 *magic_arr,
size_t magic_size, int endpoint)
{ struct usb_device *udev; unsignedint pipe = 0; int sent;
u8 *buf = NULL; int rc = 0;
/** * uclogic_params_ugee_v2_init_frame_mouse() - initialize a UGEE v2 frame with a * mouse. * @p: Parameters to fill in, cannot be NULL. * * Returns: * Zero, if successful. A negative errno code on error.
*/ staticint uclogic_params_ugee_v2_init_frame_mouse(struct uclogic_params *p)
{ int rc = 0;
/** * uclogic_params_ugee_v2_has_battery() - check whether a UGEE v2 device has * battery or not. * @hdev: The HID device of the tablet interface. * * Returns: * True if the device has battery, false otherwise.
*/ staticbool uclogic_params_ugee_v2_has_battery(struct hid_device *hdev)
{ struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
if (drvdata->quirks & UCLOGIC_BATTERY_QUIRK) returntrue;
/* The XP-PEN Deco LW vendor, product and version are identical to the * Deco L. The only difference reported by their firmware is the product * name. Add a quirk to support battery reporting on the wireless * version.
*/ if (hdev->vendor == USB_VENDOR_ID_UGEE &&
hdev->product == USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) { struct usb_device *udev = hid_to_usb_dev(hdev);
if (strstarts(udev->product, "Deco LW")) returntrue;
}
returnfalse;
}
/** * uclogic_params_ugee_v2_init_battery() - initialize UGEE v2 battery reporting. * @hdev: The HID device of the tablet interface, cannot be NULL. * @p: Parameters to fill in, cannot be NULL. * * Returns: * Zero, if successful. A negative errno code on error.
*/ staticint uclogic_params_ugee_v2_init_battery(struct hid_device *hdev, struct uclogic_params *p)
{ int rc = 0;
if (!hdev || !p) return -EINVAL;
/* Some tablets contain invalid characters in hdev->uniq, throwing a * "hwmon: '<name>' is not a valid name attribute, please fix" error. * Use the device vendor and product IDs instead.
*/
snprintf(hdev->uniq, sizeof(hdev->uniq), "%x-%x", hdev->vendor,
hdev->product);
rc = uclogic_params_frame_init_with_desc(&p->frame_list[1],
uclogic_rdesc_ugee_v2_battery_template_arr,
uclogic_rdesc_ugee_v2_battery_template_size,
UCLOGIC_RDESC_UGEE_V2_BATTERY_ID); if (rc) return rc;
/** * uclogic_params_ugee_v2_reconnect_work() - When a wireless tablet looses * connection to the USB dongle and reconnects, either because of its physical * distance or because it was switches off and on using the frame's switch, * uclogic_probe_interface() needs to be called again to enable the tablet. * * @work: The work that triggered this function.
*/ staticvoid uclogic_params_ugee_v2_reconnect_work(struct work_struct *work)
{ struct uclogic_raw_event_hook *event_hook;
/** * uclogic_params_ugee_v2_init_event_hooks() - initialize the list of events * to be hooked for UGEE v2 devices. * @hdev: The HID device of the tablet interface to initialize and get * parameters from. * @p: Parameters to fill in, cannot be NULL. * * Returns: * Zero, if successful. A negative errno code on error.
*/ staticint uclogic_params_ugee_v2_init_event_hooks(struct hid_device *hdev, struct uclogic_params *p)
{ struct uclogic_raw_event_hook *event_hook; staticconst __u8 reconnect_event[] = { /* Event received on wireless tablet reconnection */
0x02, 0xF8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
if (!p) return -EINVAL;
/* The reconnection event is only received if the tablet has battery */ if (!uclogic_params_ugee_v2_has_battery(hdev)) return 0;
p->event_hooks = kzalloc(sizeof(*p->event_hooks), GFP_KERNEL); if (!p->event_hooks) return -ENOMEM;
INIT_LIST_HEAD(&p->event_hooks->list);
event_hook = kzalloc(sizeof(*event_hook), GFP_KERNEL); if (!event_hook) return -ENOMEM;
/** * uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by * discovering their parameters. * * These tables, internally designed as v2 to differentiate them from older * models, expect a payload of magic data in orther to be switched to the fully * functional mode and expose their parameters in a similar way to the * information present in uclogic_params_pen_init_v1() but with some * differences. * * @params: Parameters to fill in (to be cleaned with * uclogic_params_cleanup()). 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.
*/ staticint uclogic_params_ugee_v2_init(struct uclogic_params *params, struct hid_device *hdev)
{ int rc = 0; struct uclogic_drvdata *drvdata; struct usb_interface *iface;
__u8 bInterfaceNumber; constint str_desc_len = 12;
__u8 *str_desc = NULL;
__u8 *rdesc_pen = NULL;
s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; enum uclogic_params_frame_type frame_type; /* The resulting parameters (noop) */ struct uclogic_params p = {0, };
if (bInterfaceNumber == 0) {
rc = uclogic_params_ugee_v2_init_frame_mouse(&p); if (rc) goto cleanup;
goto output;
}
if (bInterfaceNumber != 2) {
uclogic_params_init_invalid(&p); goto output;
}
/* * Initialize the interface by sending magic data. * The specific data was discovered by sniffing the Windows driver * traffic.
*/
rc = uclogic_probe_interface(hdev, uclogic_ugee_v2_probe_arr,
uclogic_ugee_v2_probe_size,
uclogic_ugee_v2_probe_endpoint); if (rc) {
uclogic_params_init_invalid(&p); goto output;
}
/* * Read the string descriptor containing pen and frame parameters. * The specific string descriptor and data were discovered by sniffing * the Windows driver traffic.
*/
rc = uclogic_params_get_str_desc(&str_desc, hdev, 100, str_desc_len); if (rc != str_desc_len) {
hid_err(hdev, "failed retrieving pen and frame parameters: %d\n", rc);
uclogic_params_init_invalid(&p); goto output;
}
/* Initialize the frame interface */ if (drvdata->quirks & UCLOGIC_MOUSE_FRAME_QUIRK)
frame_type = UCLOGIC_PARAMS_FRAME_MOUSE;
switch (frame_type) { case UCLOGIC_PARAMS_FRAME_DIAL: case UCLOGIC_PARAMS_FRAME_MOUSE:
rc = uclogic_params_ugee_v2_init_frame_dial(&p, desc_params,
ARRAY_SIZE(desc_params)); break; case UCLOGIC_PARAMS_FRAME_BUTTONS: default:
rc = uclogic_params_ugee_v2_init_frame_buttons(&p, desc_params,
ARRAY_SIZE(desc_params)); break;
}
if (rc) goto cleanup;
/* Initialize the battery interface*/ if (uclogic_params_ugee_v2_has_battery(hdev)) {
rc = uclogic_params_ugee_v2_init_battery(hdev, &p); if (rc) {
hid_err(hdev, "error initializing battery: %d\n", rc); goto cleanup;
}
}
/* Create a list of raw events to be ignored */
rc = uclogic_params_ugee_v2_init_event_hooks(hdev, &p); if (rc) {
hid_err(hdev, "error initializing event hook list: %d\n", rc); goto cleanup;
}
/* * uclogic_params_init_ugee_xppen_pro_22r() - Initializes a UGEE XP-Pen Pro 22R tablet device. * * @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. * * Returns: * Zero, if successful. A negative errno code on error.
*/ staticint 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)
{ int rc = 0; struct usb_interface *iface;
__u8 bInterfaceNumber; constint str_desc_len = 12;
u8 *str_desc = NULL;
__u8 *rdesc_pen = NULL;
s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; enum uclogic_params_frame_type frame_type; /* The resulting parameters (noop) */ struct uclogic_params p = {0, };
/* * Initialize the interface by sending magic data. * This magic data is the same as other UGEE v2 tablets.
*/
rc = uclogic_probe_interface(hdev,
uclogic_ugee_v2_probe_arr,
uclogic_ugee_v2_probe_size,
uclogic_ugee_v2_probe_endpoint); if (rc) {
uclogic_params_init_invalid(&p); goto cleanup;
}
/** * Read the string descriptor containing pen and frame parameters. * These are slightly different than typical UGEE v2 devices.
*/
rc = uclogic_params_get_str_desc(&str_desc, hdev, 100, str_desc_len); if (rc != str_desc_len) {
rc = (rc < 0) ? rc : -EINVAL;
hid_err(hdev, "failed retrieving pen and frame parameters: %d\n", rc);
uclogic_params_init_invalid(&p); goto cleanup;
}
/** * uclogic_params_init() - initialize a tablet interface and discover its * parameters. * * @params: Parameters to fill in (to be cleaned with * uclogic_params_cleanup()). 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. Must be using the USB low-level * driver, i.e. be an actual USB tablet. * * Returns: * Zero, if successful. A negative errno code on error.
*/ int uclogic_params_init(struct uclogic_params *params, struct hid_device *hdev)
{ int rc; struct usb_device *udev;
__u8 bNumInterfaces; struct usb_interface *iface;
__u8 bInterfaceNumber; bool found; /* The resulting parameters (noop) */ struct uclogic_params p = {0, };
/* * Handle specific interfaces for specific tablets. * * Observe the following logic: * * If the interface is recognized as producing certain useful input: * Mark interface as valid. * Output interface parameters. * Else, if the interface is recognized as *not* producing any useful * input: * Mark interface as invalid. * Else: * Mark interface as valid. * Output noop parameters. * * Rule of thumb: it is better to disable a broken interface than let * it spew garbage input.
*/
switch (VID_PID(hdev->vendor, hdev->product)) { case VID_PID(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_UCLOGIC_TABLET_PF1209):
rc = WITH_OPT_DESC(PF1209_ORIG, pf1209_fixed); if (rc != 0) goto cleanup; break; case VID_PID(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U):
rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp4030u_fixed); if (rc != 0) goto cleanup; break; case VID_PID(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U): if (hdev->dev_rsize == UCLOGIC_RDESC_WP5540U_V2_ORIG_SIZE) { if (bInterfaceNumber == 0) { /* Try to probe v1 pen parameters */
rc = uclogic_params_pen_init_v1(&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");
}
} else {
uclogic_params_init_invalid(&p);
}
} else {
rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp5540u_fixed); if (rc != 0) goto cleanup;
} break; case VID_PID(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U):
rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp8060u_fixed); if (rc != 0) goto cleanup; break; case VID_PID(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_UCLOGIC_TABLET_WP1062):
rc = WITH_OPT_DESC(WP1062_ORIG, wp1062_fixed); if (rc != 0) goto cleanup; break; case VID_PID(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850): switch (bInterfaceNumber) { case 0:
rc = WITH_OPT_DESC(TWHL850_ORIG0, twhl850_fixed0); if (rc != 0) goto cleanup; break; case 1:
rc = WITH_OPT_DESC(TWHL850_ORIG1, twhl850_fixed1); if (rc != 0) goto cleanup; break; case 2:
rc = WITH_OPT_DESC(TWHL850_ORIG2, twhl850_fixed2); if (rc != 0) goto cleanup; break;
} break; case VID_PID(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60): /* * If it is not a three-interface version, which is known to * respond to initialization.
*/ if (bNumInterfaces != 3) { switch (bInterfaceNumber) { case 0:
rc = WITH_OPT_DESC(TWHA60_ORIG0,
twha60_fixed0); if (rc != 0) goto cleanup; break; case 1:
rc = WITH_OPT_DESC(TWHA60_ORIG1,
twha60_fixed1); if (rc != 0) goto cleanup; break;
} break;
}
fallthrough; case VID_PID(USB_VENDOR_ID_HUION,
USB_DEVICE_ID_HUION_TABLET): case VID_PID(USB_VENDOR_ID_HUION,
USB_DEVICE_ID_HUION_TABLET2): case VID_PID(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_HUION_TABLET): case VID_PID(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_YIYNOVA_TABLET): case VID_PID(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81): case VID_PID(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3): case VID_PID(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45): case VID_PID(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47):
rc = uclogic_params_huion_init(&p, hdev); if (rc != 0) goto cleanup; break; case VID_PID(USB_VENDOR_ID_UGTIZER,
USB_DEVICE_ID_UGTIZER_TABLET_GP0610): case VID_PID(USB_VENDOR_ID_UGTIZER,
USB_DEVICE_ID_UGTIZER_TABLET_GT5040): case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540): case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640): case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06): case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720): /* If this is the pen interface */ if (bInterfaceNumber == 1) { /* Probe v1 pen parameters */
rc = uclogic_params_pen_init_v1(&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);
}
} else {
uclogic_params_init_invalid(&p);
} break; case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01): /* If this is the pen and frame interface */ if (bInterfaceNumber == 1) { /* Probe v1 pen parameters */
rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev); if (rc != 0) {
hid_err(hdev, "pen probing failed: %d\n", rc); goto cleanup;
} /* Initialize frame parameters */
rc = uclogic_params_frame_init_with_desc(
&p.frame_list[0],
uclogic_rdesc_xppen_deco01_frame_arr,
uclogic_rdesc_xppen_deco01_frame_size,
0); if (rc != 0) goto cleanup;
} else {
uclogic_params_init_invalid(&p);
} break; case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_PARBLO_A610_PRO): case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01_V2): case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L): case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW): case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S): case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW):
rc = uclogic_params_ugee_v2_init(&p, hdev); if (rc != 0) goto cleanup; break; case VID_PID(USB_VENDOR_ID_TRUST,
USB_DEVICE_ID_TRUST_PANORA_TABLET): case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_TABLET_G5): /* Ignore non-pen interfaces */ if (bInterfaceNumber != 1) {
uclogic_params_init_invalid(&p); break;
}