in hid-uclogic-params.c [841:1140]
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, };
/* Check arguments */
if (params == NULL || hdev == NULL || !hid_is_usb(hdev)) {
rc = -EINVAL;
goto cleanup;
}
udev = hid_to_usb_dev(hdev);
bNumInterfaces = udev->config->desc.bNumInterfaces;
iface = to_usb_interface(hdev->dev.parent);
bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
/*
* Set replacement report descriptor if the original matches the
* specified size. Otherwise keep interface unchanged.
*/
#define WITH_OPT_DESC(_orig_desc_token, _new_desc_token) \
uclogic_params_init_with_opt_desc( \
&p, hdev, \
UCLOGIC_RDESC_##_orig_desc_token##_SIZE, \
uclogic_rdesc_##_new_desc_token##_arr, \
uclogic_rdesc_##_new_desc_token##_size)
#define VID_PID(_vid, _pid) \
(((__u32)(_vid) << 16) | ((__u32)(_pid) & U16_MAX))
/*
* 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_HS64):
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_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 {
/* TODO: Consider marking the interface invalid */
uclogic_params_init_with_pen_unused(&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,
uclogic_rdesc_xppen_deco01_frame_arr,
uclogic_rdesc_xppen_deco01_frame_size,
0);
if (rc != 0)
goto cleanup;
} else {
/* TODO: Consider marking the interface invalid */
uclogic_params_init_with_pen_unused(&p);
}
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;
}
rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
if (rc != 0) {
hid_err(hdev, "pen probing failed: %d\n", rc);
goto cleanup;
} else if (found) {
rc = uclogic_params_frame_init_with_desc(
&p.frame,
uclogic_rdesc_ugee_g5_frame_arr,
uclogic_rdesc_ugee_g5_frame_size,
UCLOGIC_RDESC_UGEE_G5_FRAME_ID);
if (rc != 0) {
hid_err(hdev,
"failed creating buttonpad parameters: %d\n",
rc);
goto cleanup;
}
p.frame.re_lsb =
UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB;
p.frame.dev_id_byte =
UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE;
} else {
hid_warn(hdev, "pen parameters not found");
uclogic_params_init_invalid(&p);
}
break;
case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_TABLET_EX07S):
/* Ignore non-pen interfaces */
if (bInterfaceNumber != 1) {
uclogic_params_init_invalid(&p);
break;
}
rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
if (rc != 0) {
hid_err(hdev, "pen probing failed: %d\n", rc);
goto cleanup;
} else if (found) {
rc = uclogic_params_frame_init_with_desc(
&p.frame,
uclogic_rdesc_ugee_ex07_buttonpad_arr,
uclogic_rdesc_ugee_ex07_buttonpad_size,
0);
if (rc != 0) {
hid_err(hdev,
"failed creating buttonpad parameters: %d\n",
rc);
goto cleanup;
}
} else {
hid_warn(hdev, "pen parameters not found");
uclogic_params_init_invalid(&p);
}
break;
}
#undef VID_PID
#undef WITH_OPT_DESC
/* Output parameters */
memcpy(params, &p, sizeof(*params));
memset(&p, 0, sizeof(p));
rc = 0;
cleanup:
uclogic_params_cleanup(&p);
return rc;
}