Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  *  HID driver for UC-Logic devices not fully compliant with HID standard
0004  *  - tablet initialization and parameter retrieval
0005  *
0006  *  Copyright (c) 2018 Nikolai Kondrashov
0007  */
0008 
0009 /*
0010  * This program is free software; you can redistribute it and/or modify it
0011  * under the terms of the GNU General Public License as published by the Free
0012  * Software Foundation; either version 2 of the License, or (at your option)
0013  * any later version.
0014  */
0015 
0016 #include "hid-uclogic-params.h"
0017 #include "hid-uclogic-rdesc.h"
0018 #include "usbhid/usbhid.h"
0019 #include "hid-ids.h"
0020 #include <linux/ctype.h>
0021 #include <asm/unaligned.h>
0022 
0023 /**
0024  * uclogic_params_pen_inrange_to_str() - Convert a pen in-range reporting type
0025  *                                       to a string.
0026  * @inrange:    The in-range reporting type to convert.
0027  *
0028  * Return:
0029  * * The string representing the type, or
0030  * * %NULL if the type is unknown.
0031  */
0032 static const char *uclogic_params_pen_inrange_to_str(
0033                 enum uclogic_params_pen_inrange inrange)
0034 {
0035     switch (inrange) {
0036     case UCLOGIC_PARAMS_PEN_INRANGE_NORMAL:
0037         return "normal";
0038     case UCLOGIC_PARAMS_PEN_INRANGE_INVERTED:
0039         return "inverted";
0040     case UCLOGIC_PARAMS_PEN_INRANGE_NONE:
0041         return "none";
0042     default:
0043         return NULL;
0044     }
0045 }
0046 
0047 /**
0048  * uclogic_params_pen_hid_dbg() - Dump tablet interface pen parameters
0049  * @hdev:   The HID device the pen parameters describe.
0050  * @pen:    The pen parameters to dump.
0051  *
0052  * Dump tablet interface pen parameters with hid_dbg(). The dump is indented
0053  * with a tab.
0054  */
0055 static void uclogic_params_pen_hid_dbg(const struct hid_device *hdev,
0056                     const struct uclogic_params_pen *pen)
0057 {
0058     size_t i;
0059 
0060     hid_dbg(hdev, "\t.usage_invalid = %s\n",
0061         (pen->usage_invalid ? "true" : "false"));
0062     hid_dbg(hdev, "\t.desc_ptr = %p\n", pen->desc_ptr);
0063     hid_dbg(hdev, "\t.desc_size = %u\n", pen->desc_size);
0064     hid_dbg(hdev, "\t.id = %u\n", pen->id);
0065     hid_dbg(hdev, "\t.subreport_list = {\n");
0066     for (i = 0; i < ARRAY_SIZE(pen->subreport_list); i++) {
0067         hid_dbg(hdev, "\t\t{0x%02hhx, %hhu}%s\n",
0068             pen->subreport_list[i].value,
0069             pen->subreport_list[i].id,
0070             i < (ARRAY_SIZE(pen->subreport_list) - 1) ? "," : "");
0071     }
0072     hid_dbg(hdev, "\t}\n");
0073     hid_dbg(hdev, "\t.inrange = %s\n",
0074         uclogic_params_pen_inrange_to_str(pen->inrange));
0075     hid_dbg(hdev, "\t.fragmented_hires = %s\n",
0076         (pen->fragmented_hires ? "true" : "false"));
0077     hid_dbg(hdev, "\t.tilt_y_flipped = %s\n",
0078         (pen->tilt_y_flipped ? "true" : "false"));
0079 }
0080 
0081 /**
0082  * uclogic_params_frame_hid_dbg() - Dump tablet interface frame parameters
0083  * @hdev:   The HID device the pen parameters describe.
0084  * @frame:  The frame parameters to dump.
0085  *
0086  * Dump tablet interface frame parameters with hid_dbg(). The dump is
0087  * indented with two tabs.
0088  */
0089 static void uclogic_params_frame_hid_dbg(
0090                 const struct hid_device *hdev,
0091                 const struct uclogic_params_frame *frame)
0092 {
0093     hid_dbg(hdev, "\t\t.desc_ptr = %p\n", frame->desc_ptr);
0094     hid_dbg(hdev, "\t\t.desc_size = %u\n", frame->desc_size);
0095     hid_dbg(hdev, "\t\t.id = %u\n", frame->id);
0096     hid_dbg(hdev, "\t\t.suffix = %s\n", frame->suffix);
0097     hid_dbg(hdev, "\t\t.re_lsb = %u\n", frame->re_lsb);
0098     hid_dbg(hdev, "\t\t.dev_id_byte = %u\n", frame->dev_id_byte);
0099     hid_dbg(hdev, "\t\t.touch_byte = %u\n", frame->touch_byte);
0100     hid_dbg(hdev, "\t\t.touch_max = %hhd\n", frame->touch_max);
0101     hid_dbg(hdev, "\t\t.touch_flip_at = %hhd\n",
0102         frame->touch_flip_at);
0103     hid_dbg(hdev, "\t\t.bitmap_dial_byte = %u\n",
0104         frame->bitmap_dial_byte);
0105 }
0106 
0107 /**
0108  * uclogic_params_hid_dbg() - Dump tablet interface parameters
0109  * @hdev:   The HID device the parameters describe.
0110  * @params: The parameters to dump.
0111  *
0112  * Dump tablet interface parameters with hid_dbg().
0113  */
0114 void uclogic_params_hid_dbg(const struct hid_device *hdev,
0115                 const struct uclogic_params *params)
0116 {
0117     size_t i;
0118 
0119     hid_dbg(hdev, ".invalid = %s\n",
0120         params->invalid ? "true" : "false");
0121     hid_dbg(hdev, ".desc_ptr = %p\n", params->desc_ptr);
0122     hid_dbg(hdev, ".desc_size = %u\n", params->desc_size);
0123     hid_dbg(hdev, ".pen = {\n");
0124     uclogic_params_pen_hid_dbg(hdev, &params->pen);
0125     hid_dbg(hdev, "\t}\n");
0126     hid_dbg(hdev, ".frame_list = {\n");
0127     for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
0128         hid_dbg(hdev, "\t{\n");
0129         uclogic_params_frame_hid_dbg(hdev, &params->frame_list[i]);
0130         hid_dbg(hdev, "\t}%s\n",
0131             i < (ARRAY_SIZE(params->frame_list) - 1) ? "," : "");
0132     }
0133     hid_dbg(hdev, "}\n");
0134 }
0135 
0136 /**
0137  * uclogic_params_get_str_desc - retrieve a string descriptor from a HID
0138  * device interface, putting it into a kmalloc-allocated buffer as is, without
0139  * character encoding conversion.
0140  *
0141  * @pbuf:   Location for the kmalloc-allocated buffer pointer containing
0142  *      the retrieved descriptor. Not modified in case of error.
0143  *      Can be NULL to have retrieved descriptor discarded.
0144  * @hdev:   The HID device of the tablet interface to retrieve the string
0145  *      descriptor from. Cannot be NULL.
0146  * @idx:    Index of the string descriptor to request from the device.
0147  * @len:    Length of the buffer to allocate and the data to retrieve.
0148  *
0149  * Returns:
0150  *  number of bytes retrieved (<= len),
0151  *  -EPIPE, if the descriptor was not found, or
0152  *  another negative errno code in case of other error.
0153  */
0154 static int uclogic_params_get_str_desc(__u8 **pbuf, struct hid_device *hdev,
0155                     __u8 idx, size_t len)
0156 {
0157     int rc;
0158     struct usb_device *udev;
0159     __u8 *buf = NULL;
0160 
0161     /* Check arguments */
0162     if (hdev == NULL) {
0163         rc = -EINVAL;
0164         goto cleanup;
0165     }
0166 
0167     udev = hid_to_usb_dev(hdev);
0168 
0169     buf = kmalloc(len, GFP_KERNEL);
0170     if (buf == NULL) {
0171         rc = -ENOMEM;
0172         goto cleanup;
0173     }
0174 
0175     rc = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
0176                 USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
0177                 (USB_DT_STRING << 8) + idx,
0178                 0x0409, buf, len,
0179                 USB_CTRL_GET_TIMEOUT);
0180     if (rc == -EPIPE) {
0181         hid_dbg(hdev, "string descriptor #%hhu not found\n", idx);
0182         goto cleanup;
0183     } else if (rc < 0) {
0184         hid_err(hdev,
0185             "failed retrieving string descriptor #%u: %d\n",
0186             idx, rc);
0187         goto cleanup;
0188     }
0189 
0190     if (pbuf != NULL) {
0191         *pbuf = buf;
0192         buf = NULL;
0193     }
0194 
0195 cleanup:
0196     kfree(buf);
0197     return rc;
0198 }
0199 
0200 /**
0201  * uclogic_params_pen_cleanup - free resources used by struct
0202  * uclogic_params_pen (tablet interface's pen input parameters).
0203  * Can be called repeatedly.
0204  *
0205  * @pen:    Pen input parameters to cleanup. Cannot be NULL.
0206  */
0207 static void uclogic_params_pen_cleanup(struct uclogic_params_pen *pen)
0208 {
0209     kfree(pen->desc_ptr);
0210     memset(pen, 0, sizeof(*pen));
0211 }
0212 
0213 /**
0214  * uclogic_params_pen_init_v1() - initialize tablet interface pen
0215  * input and retrieve its parameters from the device, using v1 protocol.
0216  *
0217  * @pen:    Pointer to the pen parameters to initialize (to be
0218  *      cleaned up with uclogic_params_pen_cleanup()). Not modified in
0219  *      case of error, or if parameters are not found. Cannot be NULL.
0220  * @pfound: Location for a flag which is set to true if the parameters
0221  *      were found, and to false if not (e.g. device was
0222  *      incompatible). Not modified in case of error. Cannot be NULL.
0223  * @hdev:   The HID device of the tablet interface to initialize and get
0224  *      parameters from. Cannot be NULL.
0225  *
0226  * Returns:
0227  *  Zero, if successful. A negative errno code on error.
0228  */
0229 static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
0230                       bool *pfound,
0231                       struct hid_device *hdev)
0232 {
0233     int rc;
0234     bool found = false;
0235     /* Buffer for (part of) the string descriptor */
0236     __u8 *buf = NULL;
0237     /* Minimum descriptor length required, maximum seen so far is 18 */
0238     const int len = 12;
0239     s32 resolution;
0240     /* Pen report descriptor template parameters */
0241     s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
0242     __u8 *desc_ptr = NULL;
0243 
0244     /* Check arguments */
0245     if (pen == NULL || pfound == NULL || hdev == NULL) {
0246         rc = -EINVAL;
0247         goto cleanup;
0248     }
0249 
0250     /*
0251      * Read string descriptor containing pen input parameters.
0252      * The specific string descriptor and data were discovered by sniffing
0253      * the Windows driver traffic.
0254      * NOTE: This enables fully-functional tablet mode.
0255      */
0256     rc = uclogic_params_get_str_desc(&buf, hdev, 100, len);
0257     if (rc == -EPIPE) {
0258         hid_dbg(hdev,
0259             "string descriptor with pen parameters not found, assuming not compatible\n");
0260         goto finish;
0261     } else if (rc < 0) {
0262         hid_err(hdev, "failed retrieving pen parameters: %d\n", rc);
0263         goto cleanup;
0264     } else if (rc != len) {
0265         hid_dbg(hdev,
0266             "string descriptor with pen parameters has invalid length (got %d, expected %d), assuming not compatible\n",
0267             rc, len);
0268         goto finish;
0269     }
0270 
0271     /*
0272      * Fill report descriptor parameters from the string descriptor
0273      */
0274     desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
0275         get_unaligned_le16(buf + 2);
0276     desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
0277         get_unaligned_le16(buf + 4);
0278     desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
0279         get_unaligned_le16(buf + 8);
0280     resolution = get_unaligned_le16(buf + 10);
0281     if (resolution == 0) {
0282         desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
0283         desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
0284     } else {
0285         desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
0286             desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
0287             resolution;
0288         desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
0289             desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
0290             resolution;
0291     }
0292     kfree(buf);
0293     buf = NULL;
0294 
0295     /*
0296      * Generate pen report descriptor
0297      */
0298     desc_ptr = uclogic_rdesc_template_apply(
0299                 uclogic_rdesc_v1_pen_template_arr,
0300                 uclogic_rdesc_v1_pen_template_size,
0301                 desc_params, ARRAY_SIZE(desc_params));
0302     if (desc_ptr == NULL) {
0303         rc = -ENOMEM;
0304         goto cleanup;
0305     }
0306 
0307     /*
0308      * Fill-in the parameters
0309      */
0310     memset(pen, 0, sizeof(*pen));
0311     pen->desc_ptr = desc_ptr;
0312     desc_ptr = NULL;
0313     pen->desc_size = uclogic_rdesc_v1_pen_template_size;
0314     pen->id = UCLOGIC_RDESC_V1_PEN_ID;
0315     pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_INVERTED;
0316     found = true;
0317 finish:
0318     *pfound = found;
0319     rc = 0;
0320 cleanup:
0321     kfree(desc_ptr);
0322     kfree(buf);
0323     return rc;
0324 }
0325 
0326 /**
0327  * uclogic_params_get_le24() - get a 24-bit little-endian number from a
0328  * buffer.
0329  *
0330  * @p:  The pointer to the number buffer.
0331  *
0332  * Returns:
0333  *  The retrieved number
0334  */
0335 static s32 uclogic_params_get_le24(const void *p)
0336 {
0337     const __u8 *b = p;
0338     return b[0] | (b[1] << 8UL) | (b[2] << 16UL);
0339 }
0340 
0341 /**
0342  * uclogic_params_pen_init_v2() - initialize tablet interface pen
0343  * input and retrieve its parameters from the device, using v2 protocol.
0344  *
0345  * @pen:        Pointer to the pen parameters to initialize (to be
0346  *          cleaned up with uclogic_params_pen_cleanup()). Not
0347  *          modified in case of error, or if parameters are not
0348  *          found. Cannot be NULL.
0349  * @pfound:     Location for a flag which is set to true if the
0350  *          parameters were found, and to false if not (e.g.
0351  *          device was incompatible). Not modified in case of
0352  *          error. Cannot be NULL.
0353  * @pparams_ptr:    Location for a kmalloc'ed pointer to the retrieved raw
0354  *          parameters, which could be used to identify the tablet
0355  *          to some extent. Should be freed with kfree after use.
0356  *          NULL, if not needed. Not modified in case of error.
0357  *          Only set if *pfound is set to true.
0358  * @pparams_len:    Location for the length of the retrieved raw
0359  *          parameters. NULL, if not needed. Not modified in case
0360  *          of error. Only set if *pfound is set to true.
0361  * @hdev:       The HID device of the tablet interface to initialize
0362  *          and get parameters from. Cannot be NULL.
0363  *
0364  * Returns:
0365  *  Zero, if successful. A negative errno code on error.
0366  */
0367 static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
0368                     bool *pfound,
0369                     __u8 **pparams_ptr,
0370                     size_t *pparams_len,
0371                     struct hid_device *hdev)
0372 {
0373     int rc;
0374     bool found = false;
0375     /* Buffer for (part of) the parameter string descriptor */
0376     __u8 *buf = NULL;
0377     /* Parameter string descriptor required length */
0378     const int params_len_min = 18;
0379     /* Parameter string descriptor accepted length */
0380     const int params_len_max = 32;
0381     /* Parameter string descriptor received length */
0382     int params_len;
0383     size_t i;
0384     s32 resolution;
0385     /* Pen report descriptor template parameters */
0386     s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
0387     __u8 *desc_ptr = NULL;
0388 
0389     /* Check arguments */
0390     if (pen == NULL || pfound == NULL || hdev == NULL) {
0391         rc = -EINVAL;
0392         goto cleanup;
0393     }
0394 
0395     /*
0396      * Read string descriptor containing pen input parameters.
0397      * The specific string descriptor and data were discovered by sniffing
0398      * the Windows driver traffic.
0399      * NOTE: This enables fully-functional tablet mode.
0400      */
0401     rc = uclogic_params_get_str_desc(&buf, hdev, 200, params_len_max);
0402     if (rc == -EPIPE) {
0403         hid_dbg(hdev,
0404             "string descriptor with pen parameters not found, assuming not compatible\n");
0405         goto finish;
0406     } else if (rc < 0) {
0407         hid_err(hdev, "failed retrieving pen parameters: %d\n", rc);
0408         goto cleanup;
0409     } else if (rc < params_len_min) {
0410         hid_dbg(hdev,
0411             "string descriptor with pen parameters is too short (got %d, expected at least %d), assuming not compatible\n",
0412             rc, params_len_min);
0413         goto finish;
0414     }
0415 
0416     params_len = rc;
0417 
0418     /*
0419      * Check it's not just a catch-all UTF-16LE-encoded ASCII
0420      * string (such as the model name) some tablets put into all
0421      * unknown string descriptors.
0422      */
0423     for (i = 2;
0424          i < params_len &&
0425         (buf[i] >= 0x20 && buf[i] < 0x7f && buf[i + 1] == 0);
0426          i += 2);
0427     if (i >= params_len) {
0428         hid_dbg(hdev,
0429             "string descriptor with pen parameters seems to contain only text, assuming not compatible\n");
0430         goto finish;
0431     }
0432 
0433     /*
0434      * Fill report descriptor parameters from the string descriptor
0435      */
0436     desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
0437         uclogic_params_get_le24(buf + 2);
0438     desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
0439         uclogic_params_get_le24(buf + 5);
0440     desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
0441         get_unaligned_le16(buf + 8);
0442     resolution = get_unaligned_le16(buf + 10);
0443     if (resolution == 0) {
0444         desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
0445         desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
0446     } else {
0447         desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
0448             desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
0449             resolution;
0450         desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
0451             desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
0452             resolution;
0453     }
0454 
0455     /*
0456      * Generate pen report descriptor
0457      */
0458     desc_ptr = uclogic_rdesc_template_apply(
0459                 uclogic_rdesc_v2_pen_template_arr,
0460                 uclogic_rdesc_v2_pen_template_size,
0461                 desc_params, ARRAY_SIZE(desc_params));
0462     if (desc_ptr == NULL) {
0463         rc = -ENOMEM;
0464         goto cleanup;
0465     }
0466 
0467     /*
0468      * Fill-in the parameters
0469      */
0470     memset(pen, 0, sizeof(*pen));
0471     pen->desc_ptr = desc_ptr;
0472     desc_ptr = NULL;
0473     pen->desc_size = uclogic_rdesc_v2_pen_template_size;
0474     pen->id = UCLOGIC_RDESC_V2_PEN_ID;
0475     pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_NONE;
0476     pen->fragmented_hires = true;
0477     pen->tilt_y_flipped = true;
0478     found = true;
0479     if (pparams_ptr != NULL) {
0480         *pparams_ptr = buf;
0481         buf = NULL;
0482     }
0483     if (pparams_len != NULL)
0484         *pparams_len = params_len;
0485 
0486 finish:
0487     *pfound = found;
0488     rc = 0;
0489 cleanup:
0490     kfree(desc_ptr);
0491     kfree(buf);
0492     return rc;
0493 }
0494 
0495 /**
0496  * uclogic_params_frame_cleanup - free resources used by struct
0497  * uclogic_params_frame (tablet interface's frame controls input parameters).
0498  * Can be called repeatedly.
0499  *
0500  * @frame:  Frame controls input parameters to cleanup. Cannot be NULL.
0501  */
0502 static void uclogic_params_frame_cleanup(struct uclogic_params_frame *frame)
0503 {
0504     kfree(frame->desc_ptr);
0505     memset(frame, 0, sizeof(*frame));
0506 }
0507 
0508 /**
0509  * uclogic_params_frame_init_with_desc() - initialize tablet's frame control
0510  * parameters with a static report descriptor.
0511  *
0512  * @frame:  Pointer to the frame parameters to initialize (to be cleaned
0513  *      up with uclogic_params_frame_cleanup()). Not modified in case
0514  *      of error. Cannot be NULL.
0515  * @desc_ptr:   Report descriptor pointer. Can be NULL, if desc_size is zero.
0516  * @desc_size:  Report descriptor size.
0517  * @id:     Report ID used for frame reports, if they should be tweaked,
0518  *      zero if not.
0519  *
0520  * Returns:
0521  *  Zero, if successful. A negative errno code on error.
0522  */
0523 static int uclogic_params_frame_init_with_desc(
0524                     struct uclogic_params_frame *frame,
0525                     const __u8 *desc_ptr,
0526                     size_t desc_size,
0527                     unsigned int id)
0528 {
0529     __u8 *copy_desc_ptr;
0530 
0531     if (frame == NULL || (desc_ptr == NULL && desc_size != 0))
0532         return -EINVAL;
0533 
0534     copy_desc_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
0535     if (copy_desc_ptr == NULL)
0536         return -ENOMEM;
0537 
0538     memset(frame, 0, sizeof(*frame));
0539     frame->desc_ptr = copy_desc_ptr;
0540     frame->desc_size = desc_size;
0541     frame->id = id;
0542     return 0;
0543 }
0544 
0545 /**
0546  * uclogic_params_frame_init_v1() - initialize v1 tablet interface frame
0547  * controls.
0548  *
0549  * @frame:  Pointer to the frame parameters to initialize (to be cleaned
0550  *      up with uclogic_params_frame_cleanup()). Not modified in case
0551  *      of error, or if parameters are not found. Cannot be NULL.
0552  * @pfound: Location for a flag which is set to true if the parameters
0553  *      were found, and to false if not (e.g. device was
0554  *      incompatible). Not modified in case of error. Cannot be NULL.
0555  * @hdev:   The HID device of the tablet interface to initialize and get
0556  *      parameters from. Cannot be NULL.
0557  *
0558  * Returns:
0559  *  Zero, if successful. A negative errno code on error.
0560  */
0561 static int uclogic_params_frame_init_v1(struct uclogic_params_frame *frame,
0562                     bool *pfound,
0563                     struct hid_device *hdev)
0564 {
0565     int rc;
0566     bool found = false;
0567     struct usb_device *usb_dev;
0568     char *str_buf = NULL;
0569     const size_t str_len = 16;
0570 
0571     /* Check arguments */
0572     if (frame == NULL || pfound == NULL || hdev == NULL) {
0573         rc = -EINVAL;
0574         goto cleanup;
0575     }
0576 
0577     usb_dev = hid_to_usb_dev(hdev);
0578 
0579     /*
0580      * Enable generic button mode
0581      */
0582     str_buf = kzalloc(str_len, GFP_KERNEL);
0583     if (str_buf == NULL) {
0584         rc = -ENOMEM;
0585         goto cleanup;
0586     }
0587 
0588     rc = usb_string(usb_dev, 123, str_buf, str_len);
0589     if (rc == -EPIPE) {
0590         hid_dbg(hdev,
0591             "generic button -enabling string descriptor not found\n");
0592     } else if (rc < 0) {
0593         goto cleanup;
0594     } else if (strncmp(str_buf, "HK On", rc) != 0) {
0595         hid_dbg(hdev,
0596             "invalid response to enabling generic buttons: \"%s\"\n",
0597             str_buf);
0598     } else {
0599         hid_dbg(hdev, "generic buttons enabled\n");
0600         rc = uclogic_params_frame_init_with_desc(
0601                 frame,
0602                 uclogic_rdesc_v1_frame_arr,
0603                 uclogic_rdesc_v1_frame_size,
0604                 UCLOGIC_RDESC_V1_FRAME_ID);
0605         if (rc != 0)
0606             goto cleanup;
0607         found = true;
0608     }
0609 
0610     *pfound = found;
0611     rc = 0;
0612 cleanup:
0613     kfree(str_buf);
0614     return rc;
0615 }
0616 
0617 /**
0618  * uclogic_params_cleanup - free resources used by struct uclogic_params
0619  * (tablet interface's parameters).
0620  * Can be called repeatedly.
0621  *
0622  * @params: Input parameters to cleanup. Cannot be NULL.
0623  */
0624 void uclogic_params_cleanup(struct uclogic_params *params)
0625 {
0626     if (!params->invalid) {
0627         size_t i;
0628         kfree(params->desc_ptr);
0629         uclogic_params_pen_cleanup(&params->pen);
0630         for (i = 0; i < ARRAY_SIZE(params->frame_list); i++)
0631             uclogic_params_frame_cleanup(&params->frame_list[i]);
0632 
0633         memset(params, 0, sizeof(*params));
0634     }
0635 }
0636 
0637 /**
0638  * uclogic_params_get_desc() - Get a replacement report descriptor for a
0639  *                             tablet's interface.
0640  *
0641  * @params: The parameters of a tablet interface to get report
0642  *      descriptor for. Cannot be NULL.
0643  * @pdesc:  Location for the resulting, kmalloc-allocated report
0644  *      descriptor pointer, or for NULL, if there's no replacement
0645  *      report descriptor. Not modified in case of error. Cannot be
0646  *      NULL.
0647  * @psize:  Location for the resulting report descriptor size, not set if
0648  *      there's no replacement report descriptor. Not modified in case
0649  *      of error. Cannot be NULL.
0650  *
0651  * Returns:
0652  *  Zero, if successful.
0653  *  -EINVAL, if invalid arguments are supplied.
0654  *  -ENOMEM, if failed to allocate memory.
0655  */
0656 int uclogic_params_get_desc(const struct uclogic_params *params,
0657                 __u8 **pdesc,
0658                 unsigned int *psize)
0659 {
0660     int rc = -ENOMEM;
0661     bool present = false;
0662     unsigned int size = 0;
0663     __u8 *desc = NULL;
0664     size_t i;
0665 
0666     /* Check arguments */
0667     if (params == NULL || pdesc == NULL || psize == NULL)
0668         return -EINVAL;
0669 
0670     /* Concatenate descriptors */
0671 #define ADD_DESC(_desc_ptr, _desc_size) \
0672     do {                                                        \
0673         unsigned int new_size;                              \
0674         __u8 *new_desc;                                     \
0675         if ((_desc_ptr) == NULL) {                          \
0676             break;                                      \
0677         }                                                   \
0678         new_size = size + (_desc_size);                     \
0679         new_desc = krealloc(desc, new_size, GFP_KERNEL);    \
0680         if (new_desc == NULL) {                             \
0681             goto cleanup;                               \
0682         }                                                   \
0683         memcpy(new_desc + size, (_desc_ptr), (_desc_size)); \
0684         desc = new_desc;                                    \
0685         size = new_size;                                    \
0686         present = true;                                     \
0687     } while (0)
0688 
0689     ADD_DESC(params->desc_ptr, params->desc_size);
0690     ADD_DESC(params->pen.desc_ptr, params->pen.desc_size);
0691     for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
0692         ADD_DESC(params->frame_list[i].desc_ptr,
0693                 params->frame_list[i].desc_size);
0694     }
0695 
0696 #undef ADD_DESC
0697 
0698     if (present) {
0699         *pdesc = desc;
0700         *psize = size;
0701         desc = NULL;
0702     }
0703     rc = 0;
0704 cleanup:
0705     kfree(desc);
0706     return rc;
0707 }
0708 
0709 /**
0710  * uclogic_params_init_invalid() - initialize tablet interface parameters,
0711  * specifying the interface is invalid.
0712  *
0713  * @params:     Parameters to initialize (to be cleaned with
0714  *          uclogic_params_cleanup()). Cannot be NULL.
0715  */
0716 static void uclogic_params_init_invalid(struct uclogic_params *params)
0717 {
0718     params->invalid = true;
0719 }
0720 
0721 /**
0722  * uclogic_params_init_with_opt_desc() - initialize tablet interface
0723  * parameters with an optional replacement report descriptor. Only modify
0724  * report descriptor, if the original report descriptor matches the expected
0725  * size.
0726  *
0727  * @params:     Parameters to initialize (to be cleaned with
0728  *          uclogic_params_cleanup()). Not modified in case of
0729  *          error. Cannot be NULL.
0730  * @hdev:       The HID device of the tablet interface create the
0731  *          parameters for. Cannot be NULL.
0732  * @orig_desc_size: Expected size of the original report descriptor to
0733  *          be replaced.
0734  * @desc_ptr:       Pointer to the replacement report descriptor.
0735  *          Can be NULL, if desc_size is zero.
0736  * @desc_size:      Size of the replacement report descriptor.
0737  *
0738  * Returns:
0739  *  Zero, if successful. -EINVAL if an invalid argument was passed.
0740  *  -ENOMEM, if failed to allocate memory.
0741  */
0742 static int uclogic_params_init_with_opt_desc(struct uclogic_params *params,
0743                          struct hid_device *hdev,
0744                          unsigned int orig_desc_size,
0745                          __u8 *desc_ptr,
0746                          unsigned int desc_size)
0747 {
0748     __u8 *desc_copy_ptr = NULL;
0749     unsigned int desc_copy_size;
0750     int rc;
0751 
0752     /* Check arguments */
0753     if (params == NULL || hdev == NULL ||
0754         (desc_ptr == NULL && desc_size != 0)) {
0755         rc = -EINVAL;
0756         goto cleanup;
0757     }
0758 
0759     /* Replace report descriptor, if it matches */
0760     if (hdev->dev_rsize == orig_desc_size) {
0761         hid_dbg(hdev,
0762             "device report descriptor matches the expected size, replacing\n");
0763         desc_copy_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
0764         if (desc_copy_ptr == NULL) {
0765             rc = -ENOMEM;
0766             goto cleanup;
0767         }
0768         desc_copy_size = desc_size;
0769     } else {
0770         hid_dbg(hdev,
0771             "device report descriptor doesn't match the expected size (%u != %u), preserving\n",
0772             hdev->dev_rsize, orig_desc_size);
0773         desc_copy_ptr = NULL;
0774         desc_copy_size = 0;
0775     }
0776 
0777     /* Output parameters */
0778     memset(params, 0, sizeof(*params));
0779     params->desc_ptr = desc_copy_ptr;
0780     desc_copy_ptr = NULL;
0781     params->desc_size = desc_copy_size;
0782 
0783     rc = 0;
0784 cleanup:
0785     kfree(desc_copy_ptr);
0786     return rc;
0787 }
0788 
0789 /**
0790  * uclogic_params_huion_init() - initialize a Huion tablet interface and discover
0791  * its parameters.
0792  *
0793  * @params: Parameters to fill in (to be cleaned with
0794  *      uclogic_params_cleanup()). Not modified in case of error.
0795  *      Cannot be NULL.
0796  * @hdev:   The HID device of the tablet interface to initialize and get
0797  *      parameters from. Cannot be NULL.
0798  *
0799  * Returns:
0800  *  Zero, if successful. A negative errno code on error.
0801  */
0802 static int uclogic_params_huion_init(struct uclogic_params *params,
0803                      struct hid_device *hdev)
0804 {
0805     int rc;
0806     struct usb_device *udev;
0807     struct usb_interface *iface;
0808     __u8 bInterfaceNumber;
0809     bool found;
0810     /* The resulting parameters (noop) */
0811     struct uclogic_params p = {0, };
0812     static const char transition_ver[] = "HUION_T153_160607";
0813     char *ver_ptr = NULL;
0814     const size_t ver_len = sizeof(transition_ver) + 1;
0815     __u8 *params_ptr = NULL;
0816     size_t params_len = 0;
0817     /* Parameters string descriptor of a model with touch ring (HS610) */
0818     const __u8 touch_ring_model_params_buf[] = {
0819         0x13, 0x03, 0x70, 0xC6, 0x00, 0x06, 0x7C, 0x00,
0820         0xFF, 0x1F, 0xD8, 0x13, 0x03, 0x0D, 0x10, 0x01,
0821         0x04, 0x3C, 0x3E
0822     };
0823 
0824     /* Check arguments */
0825     if (params == NULL || hdev == NULL) {
0826         rc = -EINVAL;
0827         goto cleanup;
0828     }
0829 
0830     udev = hid_to_usb_dev(hdev);
0831     iface = to_usb_interface(hdev->dev.parent);
0832     bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
0833 
0834     /* If it's a custom keyboard interface */
0835     if (bInterfaceNumber == 1) {
0836         /* Keep everything intact, but mark pen usage invalid */
0837         p.pen.usage_invalid = true;
0838         goto output;
0839     /* Else, if it's not a pen interface */
0840     } else if (bInterfaceNumber != 0) {
0841         uclogic_params_init_invalid(&p);
0842         goto output;
0843     }
0844 
0845     /* Try to get firmware version */
0846     ver_ptr = kzalloc(ver_len, GFP_KERNEL);
0847     if (ver_ptr == NULL) {
0848         rc = -ENOMEM;
0849         goto cleanup;
0850     }
0851     rc = usb_string(udev, 201, ver_ptr, ver_len);
0852     if (rc == -EPIPE) {
0853         *ver_ptr = '\0';
0854     } else if (rc < 0) {
0855         hid_err(hdev,
0856             "failed retrieving Huion firmware version: %d\n", rc);
0857         goto cleanup;
0858     }
0859 
0860     /* If this is a transition firmware */
0861     if (strcmp(ver_ptr, transition_ver) == 0) {
0862         hid_dbg(hdev,
0863             "transition firmware detected, not probing pen v2 parameters\n");
0864     } else {
0865         /* Try to probe v2 pen parameters */
0866         rc = uclogic_params_pen_init_v2(&p.pen, &found,
0867                         &params_ptr, &params_len,
0868                         hdev);
0869         if (rc != 0) {
0870             hid_err(hdev,
0871                 "failed probing pen v2 parameters: %d\n", rc);
0872             goto cleanup;
0873         } else if (found) {
0874             hid_dbg(hdev, "pen v2 parameters found\n");
0875             /* Create v2 frame button parameters */
0876             rc = uclogic_params_frame_init_with_desc(
0877                     &p.frame_list[0],
0878                     uclogic_rdesc_v2_frame_buttons_arr,
0879                     uclogic_rdesc_v2_frame_buttons_size,
0880                     UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID);
0881             if (rc != 0) {
0882                 hid_err(hdev,
0883                     "failed creating v2 frame button parameters: %d\n",
0884                     rc);
0885                 goto cleanup;
0886             }
0887 
0888             /* Link from pen sub-report */
0889             p.pen.subreport_list[0].value = 0xe0;
0890             p.pen.subreport_list[0].id =
0891                 UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID;
0892 
0893             /* If this is the model with touch ring */
0894             if (params_ptr != NULL &&
0895                 params_len == sizeof(touch_ring_model_params_buf) &&
0896                 memcmp(params_ptr, touch_ring_model_params_buf,
0897                    params_len) == 0) {
0898                 /* Create touch ring parameters */
0899                 rc = uclogic_params_frame_init_with_desc(
0900                     &p.frame_list[1],
0901                     uclogic_rdesc_v2_frame_touch_ring_arr,
0902                     uclogic_rdesc_v2_frame_touch_ring_size,
0903                     UCLOGIC_RDESC_V2_FRAME_TOUCH_ID);
0904                 if (rc != 0) {
0905                     hid_err(hdev,
0906                         "failed creating v2 frame touch ring parameters: %d\n",
0907                         rc);
0908                     goto cleanup;
0909                 }
0910                 p.frame_list[1].suffix = "Touch Ring";
0911                 p.frame_list[1].dev_id_byte =
0912                     UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE;
0913                 p.frame_list[1].touch_byte = 5;
0914                 p.frame_list[1].touch_max = 12;
0915                 p.frame_list[1].touch_flip_at = 7;
0916             } else {
0917                 /* Create touch strip parameters */
0918                 rc = uclogic_params_frame_init_with_desc(
0919                     &p.frame_list[1],
0920                     uclogic_rdesc_v2_frame_touch_strip_arr,
0921                     uclogic_rdesc_v2_frame_touch_strip_size,
0922                     UCLOGIC_RDESC_V2_FRAME_TOUCH_ID);
0923                 if (rc != 0) {
0924                     hid_err(hdev,
0925                         "failed creating v2 frame touch strip parameters: %d\n",
0926                         rc);
0927                     goto cleanup;
0928                 }
0929                 p.frame_list[1].suffix = "Touch Strip";
0930                 p.frame_list[1].dev_id_byte =
0931                     UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE;
0932                 p.frame_list[1].touch_byte = 5;
0933                 p.frame_list[1].touch_max = 8;
0934             }
0935 
0936             /* Link from pen sub-report */
0937             p.pen.subreport_list[1].value = 0xf0;
0938             p.pen.subreport_list[1].id =
0939                 UCLOGIC_RDESC_V2_FRAME_TOUCH_ID;
0940 
0941             /* Create v2 frame dial parameters */
0942             rc = uclogic_params_frame_init_with_desc(
0943                     &p.frame_list[2],
0944                     uclogic_rdesc_v2_frame_dial_arr,
0945                     uclogic_rdesc_v2_frame_dial_size,
0946                     UCLOGIC_RDESC_V2_FRAME_DIAL_ID);
0947             if (rc != 0) {
0948                 hid_err(hdev,
0949                     "failed creating v2 frame dial parameters: %d\n",
0950                     rc);
0951                 goto cleanup;
0952             }
0953             p.frame_list[2].suffix = "Dial";
0954             p.frame_list[2].dev_id_byte =
0955                 UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE;
0956             p.frame_list[2].bitmap_dial_byte = 5;
0957 
0958             /* Link from pen sub-report */
0959             p.pen.subreport_list[2].value = 0xf1;
0960             p.pen.subreport_list[2].id =
0961                 UCLOGIC_RDESC_V2_FRAME_DIAL_ID;
0962 
0963             goto output;
0964         }
0965         hid_dbg(hdev, "pen v2 parameters not found\n");
0966     }
0967 
0968     /* Try to probe v1 pen parameters */
0969     rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
0970     if (rc != 0) {
0971         hid_err(hdev,
0972             "failed probing pen v1 parameters: %d\n", rc);
0973         goto cleanup;
0974     } else if (found) {
0975         hid_dbg(hdev, "pen v1 parameters found\n");
0976         /* Try to probe v1 frame */
0977         rc = uclogic_params_frame_init_v1(&p.frame_list[0],
0978                           &found, hdev);
0979         if (rc != 0) {
0980             hid_err(hdev, "v1 frame probing failed: %d\n", rc);
0981             goto cleanup;
0982         }
0983         hid_dbg(hdev, "frame v1 parameters%s found\n",
0984             (found ? "" : " not"));
0985         if (found) {
0986             /* Link frame button subreports from pen reports */
0987             p.pen.subreport_list[0].value = 0xe0;
0988             p.pen.subreport_list[0].id =
0989                 UCLOGIC_RDESC_V1_FRAME_ID;
0990         }
0991         goto output;
0992     }
0993     hid_dbg(hdev, "pen v1 parameters not found\n");
0994 
0995     uclogic_params_init_invalid(&p);
0996 
0997 output:
0998     /* Output parameters */
0999     memcpy(params, &p, sizeof(*params));
1000     memset(&p, 0, sizeof(p));
1001     rc = 0;
1002 cleanup:
1003     kfree(params_ptr);
1004     kfree(ver_ptr);
1005     uclogic_params_cleanup(&p);
1006     return rc;
1007 }
1008 
1009 /**
1010  * uclogic_probe_interface() - some tablets, like the Parblo A610 PLUS V2 or
1011  * the XP-PEN Deco Mini 7, need to be initialized by sending them magic data.
1012  *
1013  * @hdev:   The HID device of the tablet interface to initialize and get
1014  *      parameters from. Cannot be NULL.
1015  * @magic_arr:  The magic data that should be sent to probe the interface.
1016  *      Cannot be NULL.
1017  * @magic_size: Size of the magic data.
1018  * @endpoint:   Endpoint where the magic data should be sent.
1019  *
1020  * Returns:
1021  *  Zero, if successful. A negative errno code on error.
1022  */
1023 static int uclogic_probe_interface(struct hid_device *hdev, u8 *magic_arr,
1024                    int magic_size, int endpoint)
1025 {
1026     struct usb_device *udev;
1027     unsigned int pipe = 0;
1028     int sent;
1029     u8 *buf = NULL;
1030     int rc = 0;
1031 
1032     if (!hdev || !magic_arr) {
1033         rc = -EINVAL;
1034         goto cleanup;
1035     }
1036 
1037     buf = kmemdup(magic_arr, magic_size, GFP_KERNEL);
1038     if (!buf) {
1039         rc = -ENOMEM;
1040         goto cleanup;
1041     }
1042 
1043     udev = hid_to_usb_dev(hdev);
1044     pipe = usb_sndintpipe(udev, endpoint);
1045 
1046     rc = usb_interrupt_msg(udev, pipe, buf, magic_size, &sent, 1000);
1047     if (rc || sent != magic_size) {
1048         hid_err(hdev, "Interface probing failed: %d\n", rc);
1049         rc = -1;
1050         goto cleanup;
1051     }
1052 
1053     rc = 0;
1054 cleanup:
1055     kfree(buf);
1056     return rc;
1057 }
1058 
1059 /**
1060  * uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by
1061  * discovering their parameters.
1062  *
1063  * These tables, internally designed as v2 to differentiate them from older
1064  * models, expect a payload of magic data in orther to be switched to the fully
1065  * functional mode and expose their parameters in a similar way to the
1066  * information present in uclogic_params_pen_init_v1() but with some
1067  * differences.
1068  *
1069  * @params: Parameters to fill in (to be cleaned with
1070  *      uclogic_params_cleanup()). Not modified in case of error.
1071  *      Cannot be NULL.
1072  * @hdev:   The HID device of the tablet interface to initialize and get
1073  *      parameters from. Cannot be NULL.
1074  *
1075  * Returns:
1076  *  Zero, if successful. A negative errno code on error.
1077  */
1078 static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
1079                        struct hid_device *hdev)
1080 {
1081     int rc = 0;
1082     struct usb_interface *iface;
1083     __u8 bInterfaceNumber;
1084     const int str_desc_len = 12;
1085     __u8 *str_desc = NULL;
1086     __u8 *rdesc_pen = NULL;
1087     __u8 *rdesc_frame = NULL;
1088     s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
1089     s32 resolution;
1090     __u8 magic_arr[] = {
1091         0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1092     };
1093     /* The resulting parameters (noop) */
1094     struct uclogic_params p = {0, };
1095 
1096     if (!params || !hdev) {
1097         rc = -EINVAL;
1098         goto cleanup;
1099     }
1100 
1101     iface = to_usb_interface(hdev->dev.parent);
1102     bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
1103     if (bInterfaceNumber != 2) {
1104         uclogic_params_init_invalid(&p);
1105         goto output;
1106     }
1107 
1108     /*
1109      * Initialize the interface by sending magic data.
1110      * The specific data was discovered by sniffing the Windows driver
1111      * traffic.
1112      */
1113     rc = uclogic_probe_interface(hdev, magic_arr, sizeof(magic_arr), 0x03);
1114     if (rc) {
1115         uclogic_params_init_invalid(&p);
1116         goto output;
1117     }
1118 
1119     /*
1120      * Read the string descriptor containing pen and frame parameters.
1121      * The specific string descriptor and data were discovered by sniffing
1122      * the Windows driver traffic.
1123      */
1124     rc = uclogic_params_get_str_desc(&str_desc, hdev, 100, str_desc_len);
1125     if (rc != str_desc_len) {
1126         hid_err(hdev, "failed retrieving pen and frame parameters: %d\n", rc);
1127         uclogic_params_init_invalid(&p);
1128         goto output;
1129     }
1130 
1131     desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
1132         get_unaligned_le16(str_desc + 2);
1133     desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
1134         get_unaligned_le16(str_desc + 4);
1135     desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM] = str_desc[6];
1136     desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
1137         get_unaligned_le16(str_desc + 8);
1138     resolution = get_unaligned_le16(str_desc + 10);
1139     if (resolution == 0) {
1140         desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
1141         desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
1142     } else {
1143         desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
1144             desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
1145             resolution;
1146         desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
1147             desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
1148             resolution;
1149     }
1150     kfree(str_desc);
1151     str_desc = NULL;
1152 
1153     /* Initialize the pen interface */
1154     rdesc_pen = uclogic_rdesc_template_apply(
1155                 uclogic_rdesc_ugee_v2_pen_template_arr,
1156                 uclogic_rdesc_ugee_v2_pen_template_size,
1157                 desc_params, ARRAY_SIZE(desc_params));
1158     if (!rdesc_pen) {
1159         rc = -ENOMEM;
1160         goto cleanup;
1161     }
1162 
1163     p.pen.desc_ptr = rdesc_pen;
1164     p.pen.desc_size = uclogic_rdesc_ugee_v2_pen_template_size;
1165     p.pen.id = 0x02;
1166     p.pen.subreport_list[0].value = 0xf0;
1167     p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID;
1168 
1169     /* Initialize the frame interface */
1170     rdesc_frame = uclogic_rdesc_template_apply(
1171                 uclogic_rdesc_ugee_v2_frame_btn_template_arr,
1172                 uclogic_rdesc_ugee_v2_frame_btn_template_size,
1173                 desc_params, ARRAY_SIZE(desc_params));
1174     if (!rdesc_frame) {
1175         rc = -ENOMEM;
1176         goto cleanup;
1177     }
1178 
1179     rc = uclogic_params_frame_init_with_desc(&p.frame_list[0],
1180                          rdesc_frame,
1181                          uclogic_rdesc_ugee_v2_frame_btn_template_size,
1182                          UCLOGIC_RDESC_V1_FRAME_ID);
1183     kfree(rdesc_frame);
1184     if (rc) {
1185         uclogic_params_init_invalid(&p);
1186         goto output;
1187     }
1188 
1189 output:
1190     /* Output parameters */
1191     memcpy(params, &p, sizeof(*params));
1192     memset(&p, 0, sizeof(p));
1193     rc = 0;
1194 cleanup:
1195     kfree(str_desc);
1196     uclogic_params_cleanup(&p);
1197     return rc;
1198 }
1199 
1200 /**
1201  * uclogic_params_init() - initialize a tablet interface and discover its
1202  * parameters.
1203  *
1204  * @params: Parameters to fill in (to be cleaned with
1205  *      uclogic_params_cleanup()). Not modified in case of error.
1206  *      Cannot be NULL.
1207  * @hdev:   The HID device of the tablet interface to initialize and get
1208  *      parameters from. Cannot be NULL. Must be using the USB low-level
1209  *      driver, i.e. be an actual USB tablet.
1210  *
1211  * Returns:
1212  *  Zero, if successful. A negative errno code on error.
1213  */
1214 int uclogic_params_init(struct uclogic_params *params,
1215             struct hid_device *hdev)
1216 {
1217     int rc;
1218     struct usb_device *udev;
1219     __u8  bNumInterfaces;
1220     struct usb_interface *iface;
1221     __u8 bInterfaceNumber;
1222     bool found;
1223     /* The resulting parameters (noop) */
1224     struct uclogic_params p = {0, };
1225 
1226     /* Check arguments */
1227     if (params == NULL || hdev == NULL || !hid_is_usb(hdev)) {
1228         rc = -EINVAL;
1229         goto cleanup;
1230     }
1231 
1232     udev = hid_to_usb_dev(hdev);
1233     bNumInterfaces = udev->config->desc.bNumInterfaces;
1234     iface = to_usb_interface(hdev->dev.parent);
1235     bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
1236 
1237     /*
1238      * Set replacement report descriptor if the original matches the
1239      * specified size. Otherwise keep interface unchanged.
1240      */
1241 #define WITH_OPT_DESC(_orig_desc_token, _new_desc_token) \
1242     uclogic_params_init_with_opt_desc(                  \
1243         &p, hdev,                                   \
1244         UCLOGIC_RDESC_##_orig_desc_token##_SIZE,    \
1245         uclogic_rdesc_##_new_desc_token##_arr,      \
1246         uclogic_rdesc_##_new_desc_token##_size)
1247 
1248 #define VID_PID(_vid, _pid) \
1249     (((__u32)(_vid) << 16) | ((__u32)(_pid) & U16_MAX))
1250 
1251     /*
1252      * Handle specific interfaces for specific tablets.
1253      *
1254      * Observe the following logic:
1255      *
1256      * If the interface is recognized as producing certain useful input:
1257      *  Mark interface as valid.
1258      *  Output interface parameters.
1259      * Else, if the interface is recognized as *not* producing any useful
1260      * input:
1261      *  Mark interface as invalid.
1262      * Else:
1263      *  Mark interface as valid.
1264      *  Output noop parameters.
1265      *
1266      * Rule of thumb: it is better to disable a broken interface than let
1267      *        it spew garbage input.
1268      */
1269 
1270     switch (VID_PID(hdev->vendor, hdev->product)) {
1271     case VID_PID(USB_VENDOR_ID_UCLOGIC,
1272              USB_DEVICE_ID_UCLOGIC_TABLET_PF1209):
1273         rc = WITH_OPT_DESC(PF1209_ORIG, pf1209_fixed);
1274         if (rc != 0)
1275             goto cleanup;
1276         break;
1277     case VID_PID(USB_VENDOR_ID_UCLOGIC,
1278              USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U):
1279         rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp4030u_fixed);
1280         if (rc != 0)
1281             goto cleanup;
1282         break;
1283     case VID_PID(USB_VENDOR_ID_UCLOGIC,
1284              USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U):
1285         if (hdev->dev_rsize == UCLOGIC_RDESC_WP5540U_V2_ORIG_SIZE) {
1286             if (bInterfaceNumber == 0) {
1287                 /* Try to probe v1 pen parameters */
1288                 rc = uclogic_params_pen_init_v1(&p.pen,
1289                                 &found, hdev);
1290                 if (rc != 0) {
1291                     hid_err(hdev,
1292                         "pen probing failed: %d\n",
1293                         rc);
1294                     goto cleanup;
1295                 }
1296                 if (!found) {
1297                     hid_warn(hdev,
1298                          "pen parameters not found");
1299                 }
1300             } else {
1301                 uclogic_params_init_invalid(&p);
1302             }
1303         } else {
1304             rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp5540u_fixed);
1305             if (rc != 0)
1306                 goto cleanup;
1307         }
1308         break;
1309     case VID_PID(USB_VENDOR_ID_UCLOGIC,
1310              USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U):
1311         rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp8060u_fixed);
1312         if (rc != 0)
1313             goto cleanup;
1314         break;
1315     case VID_PID(USB_VENDOR_ID_UCLOGIC,
1316              USB_DEVICE_ID_UCLOGIC_TABLET_WP1062):
1317         rc = WITH_OPT_DESC(WP1062_ORIG, wp1062_fixed);
1318         if (rc != 0)
1319             goto cleanup;
1320         break;
1321     case VID_PID(USB_VENDOR_ID_UCLOGIC,
1322              USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850):
1323         switch (bInterfaceNumber) {
1324         case 0:
1325             rc = WITH_OPT_DESC(TWHL850_ORIG0, twhl850_fixed0);
1326             if (rc != 0)
1327                 goto cleanup;
1328             break;
1329         case 1:
1330             rc = WITH_OPT_DESC(TWHL850_ORIG1, twhl850_fixed1);
1331             if (rc != 0)
1332                 goto cleanup;
1333             break;
1334         case 2:
1335             rc = WITH_OPT_DESC(TWHL850_ORIG2, twhl850_fixed2);
1336             if (rc != 0)
1337                 goto cleanup;
1338             break;
1339         }
1340         break;
1341     case VID_PID(USB_VENDOR_ID_UCLOGIC,
1342              USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60):
1343         /*
1344          * If it is not a three-interface version, which is known to
1345          * respond to initialization.
1346          */
1347         if (bNumInterfaces != 3) {
1348             switch (bInterfaceNumber) {
1349             case 0:
1350                 rc = WITH_OPT_DESC(TWHA60_ORIG0,
1351                             twha60_fixed0);
1352                 if (rc != 0)
1353                     goto cleanup;
1354                 break;
1355             case 1:
1356                 rc = WITH_OPT_DESC(TWHA60_ORIG1,
1357                             twha60_fixed1);
1358                 if (rc != 0)
1359                     goto cleanup;
1360                 break;
1361             }
1362             break;
1363         }
1364         fallthrough;
1365     case VID_PID(USB_VENDOR_ID_HUION,
1366              USB_DEVICE_ID_HUION_TABLET):
1367     case VID_PID(USB_VENDOR_ID_HUION,
1368              USB_DEVICE_ID_HUION_TABLET2):
1369     case VID_PID(USB_VENDOR_ID_UCLOGIC,
1370              USB_DEVICE_ID_HUION_TABLET):
1371     case VID_PID(USB_VENDOR_ID_UCLOGIC,
1372              USB_DEVICE_ID_YIYNOVA_TABLET):
1373     case VID_PID(USB_VENDOR_ID_UCLOGIC,
1374              USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81):
1375     case VID_PID(USB_VENDOR_ID_UCLOGIC,
1376              USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3):
1377     case VID_PID(USB_VENDOR_ID_UCLOGIC,
1378              USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45):
1379     case VID_PID(USB_VENDOR_ID_UCLOGIC,
1380              USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47):
1381         rc = uclogic_params_huion_init(&p, hdev);
1382         if (rc != 0)
1383             goto cleanup;
1384         break;
1385     case VID_PID(USB_VENDOR_ID_UGTIZER,
1386              USB_DEVICE_ID_UGTIZER_TABLET_GP0610):
1387     case VID_PID(USB_VENDOR_ID_UGTIZER,
1388              USB_DEVICE_ID_UGTIZER_TABLET_GT5040):
1389     case VID_PID(USB_VENDOR_ID_UGEE,
1390              USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540):
1391     case VID_PID(USB_VENDOR_ID_UGEE,
1392              USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640):
1393     case VID_PID(USB_VENDOR_ID_UGEE,
1394              USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06):
1395     case VID_PID(USB_VENDOR_ID_UGEE,
1396              USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720):
1397         /* If this is the pen interface */
1398         if (bInterfaceNumber == 1) {
1399             /* Probe v1 pen parameters */
1400             rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1401             if (rc != 0) {
1402                 hid_err(hdev, "pen probing failed: %d\n", rc);
1403                 goto cleanup;
1404             }
1405             if (!found) {
1406                 hid_warn(hdev, "pen parameters not found");
1407                 uclogic_params_init_invalid(&p);
1408             }
1409         } else {
1410             uclogic_params_init_invalid(&p);
1411         }
1412         break;
1413     case VID_PID(USB_VENDOR_ID_UGEE,
1414              USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01):
1415         /* If this is the pen and frame interface */
1416         if (bInterfaceNumber == 1) {
1417             /* Probe v1 pen parameters */
1418             rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1419             if (rc != 0) {
1420                 hid_err(hdev, "pen probing failed: %d\n", rc);
1421                 goto cleanup;
1422             }
1423             /* Initialize frame parameters */
1424             rc = uclogic_params_frame_init_with_desc(
1425                 &p.frame_list[0],
1426                 uclogic_rdesc_xppen_deco01_frame_arr,
1427                 uclogic_rdesc_xppen_deco01_frame_size,
1428                 0);
1429             if (rc != 0)
1430                 goto cleanup;
1431         } else {
1432             uclogic_params_init_invalid(&p);
1433         }
1434         break;
1435     case VID_PID(USB_VENDOR_ID_UGEE,
1436              USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L):
1437         rc = uclogic_params_ugee_v2_init(&p, hdev);
1438         if (rc != 0)
1439             goto cleanup;
1440         break;
1441     case VID_PID(USB_VENDOR_ID_TRUST,
1442              USB_DEVICE_ID_TRUST_PANORA_TABLET):
1443     case VID_PID(USB_VENDOR_ID_UGEE,
1444              USB_DEVICE_ID_UGEE_TABLET_G5):
1445         /* Ignore non-pen interfaces */
1446         if (bInterfaceNumber != 1) {
1447             uclogic_params_init_invalid(&p);
1448             break;
1449         }
1450 
1451         rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1452         if (rc != 0) {
1453             hid_err(hdev, "pen probing failed: %d\n", rc);
1454             goto cleanup;
1455         } else if (found) {
1456             rc = uclogic_params_frame_init_with_desc(
1457                 &p.frame_list[0],
1458                 uclogic_rdesc_ugee_g5_frame_arr,
1459                 uclogic_rdesc_ugee_g5_frame_size,
1460                 UCLOGIC_RDESC_UGEE_G5_FRAME_ID);
1461             if (rc != 0) {
1462                 hid_err(hdev,
1463                     "failed creating frame parameters: %d\n",
1464                     rc);
1465                 goto cleanup;
1466             }
1467             p.frame_list[0].re_lsb =
1468                 UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB;
1469             p.frame_list[0].dev_id_byte =
1470                 UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE;
1471         } else {
1472             hid_warn(hdev, "pen parameters not found");
1473             uclogic_params_init_invalid(&p);
1474         }
1475 
1476         break;
1477     case VID_PID(USB_VENDOR_ID_UGEE,
1478              USB_DEVICE_ID_UGEE_TABLET_EX07S):
1479         /* Ignore non-pen interfaces */
1480         if (bInterfaceNumber != 1) {
1481             uclogic_params_init_invalid(&p);
1482             break;
1483         }
1484 
1485         rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1486         if (rc != 0) {
1487             hid_err(hdev, "pen probing failed: %d\n", rc);
1488             goto cleanup;
1489         } else if (found) {
1490             rc = uclogic_params_frame_init_with_desc(
1491                 &p.frame_list[0],
1492                 uclogic_rdesc_ugee_ex07_frame_arr,
1493                 uclogic_rdesc_ugee_ex07_frame_size,
1494                 0);
1495             if (rc != 0) {
1496                 hid_err(hdev,
1497                     "failed creating frame parameters: %d\n",
1498                     rc);
1499                 goto cleanup;
1500             }
1501         } else {
1502             hid_warn(hdev, "pen parameters not found");
1503             uclogic_params_init_invalid(&p);
1504         }
1505 
1506         break;
1507     }
1508 
1509 #undef VID_PID
1510 #undef WITH_OPT_DESC
1511 
1512     /* Output parameters */
1513     memcpy(params, &p, sizeof(*params));
1514     memset(&p, 0, sizeof(p));
1515     rc = 0;
1516 cleanup:
1517     uclogic_params_cleanup(&p);
1518     return rc;
1519 }