^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * HID driver for UC-Logic devices not fully compliant with HID standard
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * - tablet initialization and parameter retrieval
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (c) 2018 Nikolai Kondrashov
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * This program is free software; you can redistribute it and/or modify it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * under the terms of the GNU General Public License as published by the Free
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Software Foundation; either version 2 of the License, or (at your option)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * any later version.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "hid-uclogic-params.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "hid-uclogic-rdesc.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "usbhid/usbhid.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "hid-ids.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/unaligned.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * Convert a pen in-range reporting type to a string.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * @inrange: The in-range reporting type to convert.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * Returns:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * The string representing the type, or NULL if the type is unknown.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) const char *uclogic_params_pen_inrange_to_str(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) enum uclogic_params_pen_inrange inrange)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) switch (inrange) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) case UCLOGIC_PARAMS_PEN_INRANGE_NORMAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) return "normal";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) case UCLOGIC_PARAMS_PEN_INRANGE_INVERTED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) return "inverted";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) case UCLOGIC_PARAMS_PEN_INRANGE_NONE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) return "none";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * uclogic_params_get_str_desc - retrieve a string descriptor from a HID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * device interface, putting it into a kmalloc-allocated buffer as is, without
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * character encoding conversion.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * @pbuf: Location for the kmalloc-allocated buffer pointer containing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * the retrieved descriptor. Not modified in case of error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * Can be NULL to have retrieved descriptor discarded.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * @hdev: The HID device of the tablet interface to retrieve the string
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * descriptor from. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * @idx: Index of the string descriptor to request from the device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * @len: Length of the buffer to allocate and the data to retrieve.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * Returns:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * number of bytes retrieved (<= len),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * -EPIPE, if the descriptor was not found, or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * another negative errno code in case of other error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static int uclogic_params_get_str_desc(__u8 **pbuf, struct hid_device *hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) __u8 idx, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct usb_device *udev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) __u8 *buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /* Check arguments */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (hdev == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) udev = hid_to_usb_dev(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) buf = kmalloc(len, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (buf == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) rc = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) (USB_DT_STRING << 8) + idx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) 0x0409, buf, len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) USB_CTRL_GET_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (rc == -EPIPE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) hid_dbg(hdev, "string descriptor #%hhu not found\n", idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) } else if (rc < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) hid_err(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) "failed retrieving string descriptor #%hhu: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) idx, rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (pbuf != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) *pbuf = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * uclogic_params_pen_cleanup - free resources used by struct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * uclogic_params_pen (tablet interface's pen input parameters).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * Can be called repeatedly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) * @pen: Pen input parameters to cleanup. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static void uclogic_params_pen_cleanup(struct uclogic_params_pen *pen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) kfree(pen->desc_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) memset(pen, 0, sizeof(*pen));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * uclogic_params_pen_init_v1() - initialize tablet interface pen
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * input and retrieve its parameters from the device, using v1 protocol.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * @pen: Pointer to the pen parameters to initialize (to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * cleaned up with uclogic_params_pen_cleanup()). Not modified in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * case of error, or if parameters are not found. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * @pfound: Location for a flag which is set to true if the parameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * were found, and to false if not (e.g. device was
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * incompatible). Not modified in case of error. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * @hdev: The HID device of the tablet interface to initialize and get
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * parameters from. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * Returns:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * Zero, if successful. A negative errno code on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) bool *pfound,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) struct hid_device *hdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) bool found = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /* Buffer for (part of) the string descriptor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) __u8 *buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) /* Minimum descriptor length required, maximum seen so far is 18 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) const int len = 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) s32 resolution;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) /* Pen report descriptor template parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) __u8 *desc_ptr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /* Check arguments */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (pen == NULL || pfound == NULL || hdev == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * Read string descriptor containing pen input parameters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * The specific string descriptor and data were discovered by sniffing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * the Windows driver traffic.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * NOTE: This enables fully-functional tablet mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) rc = uclogic_params_get_str_desc(&buf, hdev, 100, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) if (rc == -EPIPE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) hid_dbg(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) "string descriptor with pen parameters not found, assuming not compatible\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) goto finish;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) } else if (rc < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) hid_err(hdev, "failed retrieving pen parameters: %d\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) } else if (rc != len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) hid_dbg(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) "string descriptor with pen parameters has invalid length (got %d, expected %d), assuming not compatible\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) rc, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) goto finish;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * Fill report descriptor parameters from the string descriptor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) get_unaligned_le16(buf + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) get_unaligned_le16(buf + 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) get_unaligned_le16(buf + 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) resolution = get_unaligned_le16(buf + 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (resolution == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) resolution;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) resolution;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) * Generate pen report descriptor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) desc_ptr = uclogic_rdesc_template_apply(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) uclogic_rdesc_pen_v1_template_arr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) uclogic_rdesc_pen_v1_template_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) desc_params, ARRAY_SIZE(desc_params));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (desc_ptr == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * Fill-in the parameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) memset(pen, 0, sizeof(*pen));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) pen->desc_ptr = desc_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) desc_ptr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) pen->desc_size = uclogic_rdesc_pen_v1_template_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) pen->id = UCLOGIC_RDESC_PEN_V1_ID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_INVERTED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) finish:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) *pfound = found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) kfree(desc_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) * uclogic_params_get_le24() - get a 24-bit little-endian number from a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) * buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) * @p: The pointer to the number buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * Returns:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * The retrieved number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) static s32 uclogic_params_get_le24(const void *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) const __u8 *b = p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) return b[0] | (b[1] << 8UL) | (b[2] << 16UL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) * uclogic_params_pen_init_v2() - initialize tablet interface pen
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * input and retrieve its parameters from the device, using v2 protocol.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) * @pen: Pointer to the pen parameters to initialize (to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) * cleaned up with uclogic_params_pen_cleanup()). Not modified in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) * case of error, or if parameters are not found. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) * @pfound: Location for a flag which is set to true if the parameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) * were found, and to false if not (e.g. device was
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) * incompatible). Not modified in case of error. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) * @hdev: The HID device of the tablet interface to initialize and get
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) * parameters from. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) * Returns:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) * Zero, if successful. A negative errno code on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) bool *pfound,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) struct hid_device *hdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) bool found = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) /* Buffer for (part of) the string descriptor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) __u8 *buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) /* Descriptor length required */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) const int len = 18;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) s32 resolution;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) /* Pen report descriptor template parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) __u8 *desc_ptr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) /* Check arguments */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (pen == NULL || pfound == NULL || hdev == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) * Read string descriptor containing pen input parameters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) * The specific string descriptor and data were discovered by sniffing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) * the Windows driver traffic.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) * NOTE: This enables fully-functional tablet mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) rc = uclogic_params_get_str_desc(&buf, hdev, 200, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if (rc == -EPIPE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) hid_dbg(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) "string descriptor with pen parameters not found, assuming not compatible\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) goto finish;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) } else if (rc < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) hid_err(hdev, "failed retrieving pen parameters: %d\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) } else if (rc != len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) hid_dbg(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) "string descriptor with pen parameters has invalid length (got %d, expected %d), assuming not compatible\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) rc, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) goto finish;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) * Check it's not just a catch-all UTF-16LE-encoded ASCII
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) * string (such as the model name) some tablets put into all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) * unknown string descriptors.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) for (i = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) i < len &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) (buf[i] >= 0x20 && buf[i] < 0x7f && buf[i + 1] == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) i += 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (i >= len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) hid_dbg(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) "string descriptor with pen parameters seems to contain only text, assuming not compatible\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) goto finish;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) * Fill report descriptor parameters from the string descriptor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) uclogic_params_get_le24(buf + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) uclogic_params_get_le24(buf + 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) get_unaligned_le16(buf + 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) resolution = get_unaligned_le16(buf + 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) if (resolution == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) resolution;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) resolution;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) * Generate pen report descriptor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) desc_ptr = uclogic_rdesc_template_apply(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) uclogic_rdesc_pen_v2_template_arr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) uclogic_rdesc_pen_v2_template_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) desc_params, ARRAY_SIZE(desc_params));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) if (desc_ptr == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) * Fill-in the parameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) memset(pen, 0, sizeof(*pen));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) pen->desc_ptr = desc_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) desc_ptr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) pen->desc_size = uclogic_rdesc_pen_v2_template_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) pen->id = UCLOGIC_RDESC_PEN_V2_ID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) pen->fragmented_hires = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) finish:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) *pfound = found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) kfree(desc_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) * uclogic_params_frame_cleanup - free resources used by struct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) * uclogic_params_frame (tablet interface's frame controls input parameters).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) * Can be called repeatedly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) * @frame: Frame controls input parameters to cleanup. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) static void uclogic_params_frame_cleanup(struct uclogic_params_frame *frame)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) kfree(frame->desc_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) memset(frame, 0, sizeof(*frame));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) * uclogic_params_frame_init_with_desc() - initialize tablet's frame control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) * parameters with a static report descriptor.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) * @frame: Pointer to the frame parameters to initialize (to be cleaned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) * up with uclogic_params_frame_cleanup()). Not modified in case
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) * of error. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) * @desc_ptr: Report descriptor pointer. Can be NULL, if desc_size is zero.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) * @desc_size: Report descriptor size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) * @id: Report ID used for frame reports, if they should be tweaked,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) * zero if not.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) * Returns:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) * Zero, if successful. A negative errno code on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) static int uclogic_params_frame_init_with_desc(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) struct uclogic_params_frame *frame,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) const __u8 *desc_ptr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) size_t desc_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) unsigned int id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) __u8 *copy_desc_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) if (frame == NULL || (desc_ptr == NULL && desc_size != 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) copy_desc_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) if (copy_desc_ptr == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) memset(frame, 0, sizeof(*frame));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) frame->desc_ptr = copy_desc_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) frame->desc_size = desc_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) frame->id = id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) * uclogic_params_frame_init_v1_buttonpad() - initialize abstract buttonpad
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) * on a v1 tablet interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) * @frame: Pointer to the frame parameters to initialize (to be cleaned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) * up with uclogic_params_frame_cleanup()). Not modified in case
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) * of error, or if parameters are not found. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) * @pfound: Location for a flag which is set to true if the parameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) * were found, and to false if not (e.g. device was
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) * incompatible). Not modified in case of error. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) * @hdev: The HID device of the tablet interface to initialize and get
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) * parameters from. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) * Returns:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) * Zero, if successful. A negative errno code on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) static int uclogic_params_frame_init_v1_buttonpad(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) struct uclogic_params_frame *frame,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) bool *pfound,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) struct hid_device *hdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) bool found = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) struct usb_device *usb_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) char *str_buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) const size_t str_len = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) /* Check arguments */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) if (frame == NULL || pfound == NULL || hdev == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) usb_dev = hid_to_usb_dev(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) * Enable generic button mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) str_buf = kzalloc(str_len, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) if (str_buf == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) rc = usb_string(usb_dev, 123, str_buf, str_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) if (rc == -EPIPE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) hid_dbg(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) "generic button -enabling string descriptor not found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) } else if (rc < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) } else if (strncmp(str_buf, "HK On", rc) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) hid_dbg(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) "invalid response to enabling generic buttons: \"%s\"\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) str_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) hid_dbg(hdev, "generic buttons enabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) rc = uclogic_params_frame_init_with_desc(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) frame,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) uclogic_rdesc_buttonpad_v1_arr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) uclogic_rdesc_buttonpad_v1_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) UCLOGIC_RDESC_BUTTONPAD_V1_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (rc != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) *pfound = found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) kfree(str_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) * uclogic_params_cleanup - free resources used by struct uclogic_params
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) * (tablet interface's parameters).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) * Can be called repeatedly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) * @params: Input parameters to cleanup. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) void uclogic_params_cleanup(struct uclogic_params *params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) if (!params->invalid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) kfree(params->desc_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) if (!params->pen_unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) uclogic_params_pen_cleanup(¶ms->pen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) uclogic_params_frame_cleanup(¶ms->frame);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) memset(params, 0, sizeof(*params));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) * Get a replacement report descriptor for a tablet's interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) * @params: The parameters of a tablet interface to get report
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) * descriptor for. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) * @pdesc: Location for the resulting, kmalloc-allocated report
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) * descriptor pointer, or for NULL, if there's no replacement
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) * report descriptor. Not modified in case of error. Cannot be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) * NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) * @psize: Location for the resulting report descriptor size, not set if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) * there's no replacement report descriptor. Not modified in case
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) * of error. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) * Returns:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) * Zero, if successful.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) * -EINVAL, if invalid arguments are supplied.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) * -ENOMEM, if failed to allocate memory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) int uclogic_params_get_desc(const struct uclogic_params *params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) __u8 **pdesc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) unsigned int *psize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) bool common_present;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) bool pen_present;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) bool frame_present;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) unsigned int size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) __u8 *desc = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) /* Check arguments */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) if (params == NULL || pdesc == NULL || psize == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) common_present = (params->desc_ptr != NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) pen_present = (!params->pen_unused && params->pen.desc_ptr != NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) frame_present = (params->frame.desc_ptr != NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) if (common_present)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) size += params->desc_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) if (pen_present)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) size += params->pen.desc_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) if (frame_present)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) size += params->frame.desc_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) if (common_present || pen_present || frame_present) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) __u8 *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) desc = kmalloc(size, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) if (desc == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) p = desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) if (common_present) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) memcpy(p, params->desc_ptr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) params->desc_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) p += params->desc_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) if (pen_present) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) memcpy(p, params->pen.desc_ptr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) params->pen.desc_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) p += params->pen.desc_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) if (frame_present) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) memcpy(p, params->frame.desc_ptr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) params->frame.desc_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) p += params->frame.desc_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) WARN_ON(p != desc + size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) *psize = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) *pdesc = desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) * uclogic_params_init_invalid() - initialize tablet interface parameters,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) * specifying the interface is invalid.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) * @params: Parameters to initialize (to be cleaned with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) * uclogic_params_cleanup()). Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) static void uclogic_params_init_invalid(struct uclogic_params *params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) params->invalid = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) * uclogic_params_init_with_opt_desc() - initialize tablet interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) * parameters with an optional replacement report descriptor. Only modify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) * report descriptor, if the original report descriptor matches the expected
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) * size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) * @params: Parameters to initialize (to be cleaned with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) * uclogic_params_cleanup()). Not modified in case of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) * error. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) * @hdev: The HID device of the tablet interface create the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) * parameters for. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) * @orig_desc_size: Expected size of the original report descriptor to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) * be replaced.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) * @desc_ptr: Pointer to the replacement report descriptor.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) * Can be NULL, if desc_size is zero.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) * @desc_size: Size of the replacement report descriptor.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) * Returns:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) * Zero, if successful. -EINVAL if an invalid argument was passed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) * -ENOMEM, if failed to allocate memory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) static int uclogic_params_init_with_opt_desc(struct uclogic_params *params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) struct hid_device *hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) unsigned int orig_desc_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) __u8 *desc_ptr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) unsigned int desc_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) __u8 *desc_copy_ptr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) unsigned int desc_copy_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) /* Check arguments */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) if (params == NULL || hdev == NULL ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) (desc_ptr == NULL && desc_size != 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) /* Replace report descriptor, if it matches */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) if (hdev->dev_rsize == orig_desc_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) hid_dbg(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) "device report descriptor matches the expected size, replacing\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) desc_copy_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) if (desc_copy_ptr == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) desc_copy_size = desc_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) hid_dbg(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) "device report descriptor doesn't match the expected size (%u != %u), preserving\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) hdev->dev_rsize, orig_desc_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) desc_copy_ptr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) desc_copy_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) /* Output parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) memset(params, 0, sizeof(*params));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) params->desc_ptr = desc_copy_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) desc_copy_ptr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) params->desc_size = desc_copy_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) kfree(desc_copy_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) * uclogic_params_init_with_pen_unused() - initialize tablet interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) * parameters preserving original reports and generic HID processing, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) * disabling pen usage.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) * @params: Parameters to initialize (to be cleaned with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) * uclogic_params_cleanup()). Not modified in case of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) * error. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) static void uclogic_params_init_with_pen_unused(struct uclogic_params *params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) memset(params, 0, sizeof(*params));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) params->pen_unused = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) * uclogic_params_init() - initialize a Huion tablet interface and discover
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) * its parameters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) * @params: Parameters to fill in (to be cleaned with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) * uclogic_params_cleanup()). Not modified in case of error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) * Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) * @hdev: The HID device of the tablet interface to initialize and get
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) * parameters from. Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) * Returns:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) * Zero, if successful. A negative errno code on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) static int uclogic_params_huion_init(struct uclogic_params *params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) struct hid_device *hdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) struct usb_device *udev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) struct usb_interface *iface;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) __u8 bInterfaceNumber;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) bool found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) /* The resulting parameters (noop) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) struct uclogic_params p = {0, };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) static const char transition_ver[] = "HUION_T153_160607";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) char *ver_ptr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) const size_t ver_len = sizeof(transition_ver) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) /* Check arguments */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) if (params == NULL || hdev == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) udev = hid_to_usb_dev(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) iface = to_usb_interface(hdev->dev.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) /* If it's not a pen interface */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) if (bInterfaceNumber != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) /* TODO: Consider marking the interface invalid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) uclogic_params_init_with_pen_unused(&p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) goto output;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) /* Try to get firmware version */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) ver_ptr = kzalloc(ver_len, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) if (ver_ptr == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) rc = usb_string(udev, 201, ver_ptr, ver_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) if (rc == -EPIPE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) *ver_ptr = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) } else if (rc < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) hid_err(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) "failed retrieving Huion firmware version: %d\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) /* If this is a transition firmware */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) if (strcmp(ver_ptr, transition_ver) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) hid_dbg(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) "transition firmware detected, not probing pen v2 parameters\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) /* Try to probe v2 pen parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) rc = uclogic_params_pen_init_v2(&p.pen, &found, hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) if (rc != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) hid_err(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) "failed probing pen v2 parameters: %d\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) } else if (found) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) hid_dbg(hdev, "pen v2 parameters found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) /* Create v2 buttonpad parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) rc = uclogic_params_frame_init_with_desc(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) &p.frame,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) uclogic_rdesc_buttonpad_v2_arr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) uclogic_rdesc_buttonpad_v2_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) UCLOGIC_RDESC_BUTTONPAD_V2_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) if (rc != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) hid_err(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) "failed creating v2 buttonpad parameters: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) /* Set bitmask marking frame reports in pen reports */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) p.pen_frame_flag = 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) goto output;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) hid_dbg(hdev, "pen v2 parameters not found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) /* Try to probe v1 pen parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) if (rc != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) hid_err(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) "failed probing pen v1 parameters: %d\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) } else if (found) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) hid_dbg(hdev, "pen v1 parameters found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) /* Try to probe v1 buttonpad */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) rc = uclogic_params_frame_init_v1_buttonpad(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) &p.frame,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) &found, hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) if (rc != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) hid_err(hdev, "v1 buttonpad probing failed: %d\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) hid_dbg(hdev, "buttonpad v1 parameters%s found\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) (found ? "" : " not"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) if (found) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) /* Set bitmask marking frame reports */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) p.pen_frame_flag = 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) goto output;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) hid_dbg(hdev, "pen v1 parameters not found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) uclogic_params_init_invalid(&p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) output:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) /* Output parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) memcpy(params, &p, sizeof(*params));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) memset(&p, 0, sizeof(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) kfree(ver_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) uclogic_params_cleanup(&p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) * uclogic_params_init() - initialize a tablet interface and discover its
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) * parameters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) * @params: Parameters to fill in (to be cleaned with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) * uclogic_params_cleanup()). Not modified in case of error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) * Cannot be NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) * @hdev: The HID device of the tablet interface to initialize and get
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) * parameters from. Cannot be NULL. Must be using the USB low-level
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) * driver, i.e. be an actual USB tablet.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) * Returns:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) * Zero, if successful. A negative errno code on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) int uclogic_params_init(struct uclogic_params *params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) struct hid_device *hdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) struct usb_device *udev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) __u8 bNumInterfaces;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) struct usb_interface *iface;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) __u8 bInterfaceNumber;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) bool found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) /* The resulting parameters (noop) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) struct uclogic_params p = {0, };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) /* Check arguments */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) if (params == NULL || hdev == NULL || !hid_is_usb(hdev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) udev = hid_to_usb_dev(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) bNumInterfaces = udev->config->desc.bNumInterfaces;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) iface = to_usb_interface(hdev->dev.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) * Set replacement report descriptor if the original matches the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) * specified size. Otherwise keep interface unchanged.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) #define WITH_OPT_DESC(_orig_desc_token, _new_desc_token) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) uclogic_params_init_with_opt_desc( \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) &p, hdev, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) UCLOGIC_RDESC_##_orig_desc_token##_SIZE, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) uclogic_rdesc_##_new_desc_token##_arr, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) uclogic_rdesc_##_new_desc_token##_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) #define VID_PID(_vid, _pid) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) (((__u32)(_vid) << 16) | ((__u32)(_pid) & U16_MAX))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) * Handle specific interfaces for specific tablets.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) * Observe the following logic:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) * If the interface is recognized as producing certain useful input:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) * Mark interface as valid.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) * Output interface parameters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) * Else, if the interface is recognized as *not* producing any useful
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) * input:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) * Mark interface as invalid.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) * Else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) * Mark interface as valid.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) * Output noop parameters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) * Rule of thumb: it is better to disable a broken interface than let
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) * it spew garbage input.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) switch (VID_PID(hdev->vendor, hdev->product)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) case VID_PID(USB_VENDOR_ID_UCLOGIC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) USB_DEVICE_ID_UCLOGIC_TABLET_PF1209):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) rc = WITH_OPT_DESC(PF1209_ORIG, pf1209_fixed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) if (rc != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) case VID_PID(USB_VENDOR_ID_UCLOGIC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp4030u_fixed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) if (rc != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) case VID_PID(USB_VENDOR_ID_UCLOGIC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) if (hdev->dev_rsize == UCLOGIC_RDESC_WP5540U_V2_ORIG_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) if (bInterfaceNumber == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) /* Try to probe v1 pen parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) rc = uclogic_params_pen_init_v1(&p.pen,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) &found, hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) if (rc != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) hid_err(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) "pen probing failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) if (!found) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) hid_warn(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) "pen parameters not found");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) uclogic_params_init_invalid(&p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp5540u_fixed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) if (rc != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) case VID_PID(USB_VENDOR_ID_UCLOGIC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp8060u_fixed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) if (rc != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) case VID_PID(USB_VENDOR_ID_UCLOGIC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) USB_DEVICE_ID_UCLOGIC_TABLET_WP1062):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) rc = WITH_OPT_DESC(WP1062_ORIG, wp1062_fixed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) if (rc != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) case VID_PID(USB_VENDOR_ID_UCLOGIC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) switch (bInterfaceNumber) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) rc = WITH_OPT_DESC(TWHL850_ORIG0, twhl850_fixed0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) if (rc != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) rc = WITH_OPT_DESC(TWHL850_ORIG1, twhl850_fixed1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) if (rc != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) rc = WITH_OPT_DESC(TWHL850_ORIG2, twhl850_fixed2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) if (rc != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) case VID_PID(USB_VENDOR_ID_UCLOGIC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) * If it is not a three-interface version, which is known to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) * respond to initialization.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) if (bNumInterfaces != 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) switch (bInterfaceNumber) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) rc = WITH_OPT_DESC(TWHA60_ORIG0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) twha60_fixed0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) if (rc != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) rc = WITH_OPT_DESC(TWHA60_ORIG1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) twha60_fixed1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) if (rc != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) case VID_PID(USB_VENDOR_ID_HUION,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) USB_DEVICE_ID_HUION_TABLET):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) case VID_PID(USB_VENDOR_ID_HUION,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) USB_DEVICE_ID_HUION_HS64):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) case VID_PID(USB_VENDOR_ID_UCLOGIC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) USB_DEVICE_ID_HUION_TABLET):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) case VID_PID(USB_VENDOR_ID_UCLOGIC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) USB_DEVICE_ID_YIYNOVA_TABLET):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) case VID_PID(USB_VENDOR_ID_UCLOGIC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) case VID_PID(USB_VENDOR_ID_UCLOGIC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) case VID_PID(USB_VENDOR_ID_UCLOGIC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) case VID_PID(USB_VENDOR_ID_UCLOGIC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) rc = uclogic_params_huion_init(&p, hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) if (rc != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) case VID_PID(USB_VENDOR_ID_UGTIZER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) USB_DEVICE_ID_UGTIZER_TABLET_GP0610):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) case VID_PID(USB_VENDOR_ID_UGTIZER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) USB_DEVICE_ID_UGTIZER_TABLET_GT5040):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) case VID_PID(USB_VENDOR_ID_UGEE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) case VID_PID(USB_VENDOR_ID_UGEE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) case VID_PID(USB_VENDOR_ID_UGEE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) /* If this is the pen interface */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) if (bInterfaceNumber == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) /* Probe v1 pen parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) if (rc != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) hid_err(hdev, "pen probing failed: %d\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) if (!found) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) hid_warn(hdev, "pen parameters not found");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) uclogic_params_init_invalid(&p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) /* TODO: Consider marking the interface invalid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) uclogic_params_init_with_pen_unused(&p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) case VID_PID(USB_VENDOR_ID_UGEE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) /* If this is the pen and frame interface */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) if (bInterfaceNumber == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) /* Probe v1 pen parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) if (rc != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) hid_err(hdev, "pen probing failed: %d\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) /* Initialize frame parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) rc = uclogic_params_frame_init_with_desc(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) &p.frame,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) uclogic_rdesc_xppen_deco01_frame_arr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) uclogic_rdesc_xppen_deco01_frame_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) if (rc != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) /* TODO: Consider marking the interface invalid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) uclogic_params_init_with_pen_unused(&p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) case VID_PID(USB_VENDOR_ID_UGEE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) USB_DEVICE_ID_UGEE_TABLET_G5):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) /* Ignore non-pen interfaces */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) if (bInterfaceNumber != 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) uclogic_params_init_invalid(&p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) if (rc != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) hid_err(hdev, "pen probing failed: %d\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) } else if (found) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) rc = uclogic_params_frame_init_with_desc(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) &p.frame,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) uclogic_rdesc_ugee_g5_frame_arr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) uclogic_rdesc_ugee_g5_frame_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) UCLOGIC_RDESC_UGEE_G5_FRAME_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) if (rc != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) hid_err(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) "failed creating buttonpad parameters: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) p.frame.re_lsb =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) p.frame.dev_id_byte =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) hid_warn(hdev, "pen parameters not found");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) uclogic_params_init_invalid(&p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) case VID_PID(USB_VENDOR_ID_UGEE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) USB_DEVICE_ID_UGEE_TABLET_EX07S):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) /* Ignore non-pen interfaces */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) if (bInterfaceNumber != 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) uclogic_params_init_invalid(&p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) if (rc != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) hid_err(hdev, "pen probing failed: %d\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) } else if (found) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) rc = uclogic_params_frame_init_with_desc(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) &p.frame,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) uclogic_rdesc_ugee_ex07_buttonpad_arr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) uclogic_rdesc_ugee_ex07_buttonpad_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) if (rc != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) hid_err(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) "failed creating buttonpad parameters: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) hid_warn(hdev, "pen parameters not found");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) uclogic_params_init_invalid(&p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) #undef VID_PID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) #undef WITH_OPT_DESC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) /* Output parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) memcpy(params, &p, sizeof(*params));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) memset(&p, 0, sizeof(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) uclogic_params_cleanup(&p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) }