19614219eSNikolai Kondrashov // SPDX-License-Identifier: GPL-2.0+ 29614219eSNikolai Kondrashov /* 39614219eSNikolai Kondrashov * HID driver for UC-Logic devices not fully compliant with HID standard 49614219eSNikolai Kondrashov * - tablet initialization and parameter retrieval 59614219eSNikolai Kondrashov * 69614219eSNikolai Kondrashov * Copyright (c) 2018 Nikolai Kondrashov 79614219eSNikolai Kondrashov */ 89614219eSNikolai Kondrashov 99614219eSNikolai Kondrashov /* 109614219eSNikolai Kondrashov * This program is free software; you can redistribute it and/or modify it 119614219eSNikolai Kondrashov * under the terms of the GNU General Public License as published by the Free 129614219eSNikolai Kondrashov * Software Foundation; either version 2 of the License, or (at your option) 139614219eSNikolai Kondrashov * any later version. 149614219eSNikolai Kondrashov */ 159614219eSNikolai Kondrashov 169614219eSNikolai Kondrashov #include "hid-uclogic-params.h" 179614219eSNikolai Kondrashov #include "hid-uclogic-rdesc.h" 189614219eSNikolai Kondrashov #include "usbhid/usbhid.h" 199614219eSNikolai Kondrashov #include "hid-ids.h" 209614219eSNikolai Kondrashov #include <linux/ctype.h> 219614219eSNikolai Kondrashov #include <asm/unaligned.h> 229614219eSNikolai Kondrashov 239614219eSNikolai Kondrashov /** 245abb5445SLee Jones * uclogic_params_pen_inrange_to_str() - Convert a pen in-range reporting type 255abb5445SLee Jones * to a string. 269614219eSNikolai Kondrashov * 279614219eSNikolai Kondrashov * @inrange: The in-range reporting type to convert. 289614219eSNikolai Kondrashov * 299614219eSNikolai Kondrashov * Returns: 309614219eSNikolai Kondrashov * The string representing the type, or NULL if the type is unknown. 319614219eSNikolai Kondrashov */ 329614219eSNikolai Kondrashov const char *uclogic_params_pen_inrange_to_str( 339614219eSNikolai Kondrashov enum uclogic_params_pen_inrange inrange) 349614219eSNikolai Kondrashov { 359614219eSNikolai Kondrashov switch (inrange) { 369614219eSNikolai Kondrashov case UCLOGIC_PARAMS_PEN_INRANGE_NORMAL: 379614219eSNikolai Kondrashov return "normal"; 389614219eSNikolai Kondrashov case UCLOGIC_PARAMS_PEN_INRANGE_INVERTED: 399614219eSNikolai Kondrashov return "inverted"; 4001309e29SNikolai Kondrashov case UCLOGIC_PARAMS_PEN_INRANGE_NONE: 4101309e29SNikolai Kondrashov return "none"; 429614219eSNikolai Kondrashov default: 439614219eSNikolai Kondrashov return NULL; 449614219eSNikolai Kondrashov } 459614219eSNikolai Kondrashov } 469614219eSNikolai Kondrashov 479614219eSNikolai Kondrashov /** 489614219eSNikolai Kondrashov * uclogic_params_get_str_desc - retrieve a string descriptor from a HID 499614219eSNikolai Kondrashov * device interface, putting it into a kmalloc-allocated buffer as is, without 509614219eSNikolai Kondrashov * character encoding conversion. 519614219eSNikolai Kondrashov * 529614219eSNikolai Kondrashov * @pbuf: Location for the kmalloc-allocated buffer pointer containing 539614219eSNikolai Kondrashov * the retrieved descriptor. Not modified in case of error. 549614219eSNikolai Kondrashov * Can be NULL to have retrieved descriptor discarded. 559614219eSNikolai Kondrashov * @hdev: The HID device of the tablet interface to retrieve the string 569614219eSNikolai Kondrashov * descriptor from. Cannot be NULL. 579614219eSNikolai Kondrashov * @idx: Index of the string descriptor to request from the device. 589614219eSNikolai Kondrashov * @len: Length of the buffer to allocate and the data to retrieve. 599614219eSNikolai Kondrashov * 609614219eSNikolai Kondrashov * Returns: 619614219eSNikolai Kondrashov * number of bytes retrieved (<= len), 629614219eSNikolai Kondrashov * -EPIPE, if the descriptor was not found, or 639614219eSNikolai Kondrashov * another negative errno code in case of other error. 649614219eSNikolai Kondrashov */ 659614219eSNikolai Kondrashov static int uclogic_params_get_str_desc(__u8 **pbuf, struct hid_device *hdev, 669614219eSNikolai Kondrashov __u8 idx, size_t len) 679614219eSNikolai Kondrashov { 689614219eSNikolai Kondrashov int rc; 690a94131dSJosé Expósito struct usb_device *udev; 709614219eSNikolai Kondrashov __u8 *buf = NULL; 719614219eSNikolai Kondrashov 729614219eSNikolai Kondrashov /* Check arguments */ 739614219eSNikolai Kondrashov if (hdev == NULL) { 749614219eSNikolai Kondrashov rc = -EINVAL; 759614219eSNikolai Kondrashov goto cleanup; 769614219eSNikolai Kondrashov } 779614219eSNikolai Kondrashov 780a94131dSJosé Expósito udev = hid_to_usb_dev(hdev); 790a94131dSJosé Expósito 809614219eSNikolai Kondrashov buf = kmalloc(len, GFP_KERNEL); 819614219eSNikolai Kondrashov if (buf == NULL) { 829614219eSNikolai Kondrashov rc = -ENOMEM; 839614219eSNikolai Kondrashov goto cleanup; 849614219eSNikolai Kondrashov } 859614219eSNikolai Kondrashov 869614219eSNikolai Kondrashov rc = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 879614219eSNikolai Kondrashov USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, 889614219eSNikolai Kondrashov (USB_DT_STRING << 8) + idx, 899614219eSNikolai Kondrashov 0x0409, buf, len, 909614219eSNikolai Kondrashov USB_CTRL_GET_TIMEOUT); 919614219eSNikolai Kondrashov if (rc == -EPIPE) { 929614219eSNikolai Kondrashov hid_dbg(hdev, "string descriptor #%hhu not found\n", idx); 939614219eSNikolai Kondrashov goto cleanup; 949614219eSNikolai Kondrashov } else if (rc < 0) { 959614219eSNikolai Kondrashov hid_err(hdev, 96a876e7e2STom Rix "failed retrieving string descriptor #%u: %d\n", 979614219eSNikolai Kondrashov idx, rc); 989614219eSNikolai Kondrashov goto cleanup; 999614219eSNikolai Kondrashov } 1009614219eSNikolai Kondrashov 1019614219eSNikolai Kondrashov if (pbuf != NULL) { 1029614219eSNikolai Kondrashov *pbuf = buf; 1039614219eSNikolai Kondrashov buf = NULL; 1049614219eSNikolai Kondrashov } 1059614219eSNikolai Kondrashov 1069614219eSNikolai Kondrashov cleanup: 1079614219eSNikolai Kondrashov kfree(buf); 1089614219eSNikolai Kondrashov return rc; 1099614219eSNikolai Kondrashov } 1109614219eSNikolai Kondrashov 1119614219eSNikolai Kondrashov /** 1129614219eSNikolai Kondrashov * uclogic_params_pen_cleanup - free resources used by struct 1139614219eSNikolai Kondrashov * uclogic_params_pen (tablet interface's pen input parameters). 1149614219eSNikolai Kondrashov * Can be called repeatedly. 1159614219eSNikolai Kondrashov * 1169614219eSNikolai Kondrashov * @pen: Pen input parameters to cleanup. Cannot be NULL. 1179614219eSNikolai Kondrashov */ 1189614219eSNikolai Kondrashov static void uclogic_params_pen_cleanup(struct uclogic_params_pen *pen) 1199614219eSNikolai Kondrashov { 1209614219eSNikolai Kondrashov kfree(pen->desc_ptr); 1219614219eSNikolai Kondrashov memset(pen, 0, sizeof(*pen)); 1229614219eSNikolai Kondrashov } 1239614219eSNikolai Kondrashov 1249614219eSNikolai Kondrashov /** 125eecb5b84SNikolai Kondrashov * uclogic_params_pen_init_v1() - initialize tablet interface pen 126eecb5b84SNikolai Kondrashov * input and retrieve its parameters from the device, using v1 protocol. 1279614219eSNikolai Kondrashov * 1289614219eSNikolai Kondrashov * @pen: Pointer to the pen parameters to initialize (to be 1299614219eSNikolai Kondrashov * cleaned up with uclogic_params_pen_cleanup()). Not modified in 1309614219eSNikolai Kondrashov * case of error, or if parameters are not found. Cannot be NULL. 1319614219eSNikolai Kondrashov * @pfound: Location for a flag which is set to true if the parameters 1329614219eSNikolai Kondrashov * were found, and to false if not (e.g. device was 1339614219eSNikolai Kondrashov * incompatible). Not modified in case of error. Cannot be NULL. 1349614219eSNikolai Kondrashov * @hdev: The HID device of the tablet interface to initialize and get 1359614219eSNikolai Kondrashov * parameters from. Cannot be NULL. 1369614219eSNikolai Kondrashov * 1379614219eSNikolai Kondrashov * Returns: 1389614219eSNikolai Kondrashov * Zero, if successful. A negative errno code on error. 1399614219eSNikolai Kondrashov */ 140eecb5b84SNikolai Kondrashov static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen, 1419614219eSNikolai Kondrashov bool *pfound, 1429614219eSNikolai Kondrashov struct hid_device *hdev) 1439614219eSNikolai Kondrashov { 1449614219eSNikolai Kondrashov int rc; 1459614219eSNikolai Kondrashov bool found = false; 1469614219eSNikolai Kondrashov /* Buffer for (part of) the string descriptor */ 1479614219eSNikolai Kondrashov __u8 *buf = NULL; 1489614219eSNikolai Kondrashov /* Minimum descriptor length required, maximum seen so far is 18 */ 1499614219eSNikolai Kondrashov const int len = 12; 1509614219eSNikolai Kondrashov s32 resolution; 1519614219eSNikolai Kondrashov /* Pen report descriptor template parameters */ 1529614219eSNikolai Kondrashov s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM]; 1539614219eSNikolai Kondrashov __u8 *desc_ptr = NULL; 1549614219eSNikolai Kondrashov 1559614219eSNikolai Kondrashov /* Check arguments */ 1569614219eSNikolai Kondrashov if (pen == NULL || pfound == NULL || hdev == NULL) { 1579614219eSNikolai Kondrashov rc = -EINVAL; 1589614219eSNikolai Kondrashov goto cleanup; 1599614219eSNikolai Kondrashov } 1609614219eSNikolai Kondrashov 1619614219eSNikolai Kondrashov /* 1629614219eSNikolai Kondrashov * Read string descriptor containing pen input parameters. 1639614219eSNikolai Kondrashov * The specific string descriptor and data were discovered by sniffing 1649614219eSNikolai Kondrashov * the Windows driver traffic. 1659614219eSNikolai Kondrashov * NOTE: This enables fully-functional tablet mode. 1669614219eSNikolai Kondrashov */ 1679614219eSNikolai Kondrashov rc = uclogic_params_get_str_desc(&buf, hdev, 100, len); 1689614219eSNikolai Kondrashov if (rc == -EPIPE) { 1699614219eSNikolai Kondrashov hid_dbg(hdev, 1709614219eSNikolai Kondrashov "string descriptor with pen parameters not found, assuming not compatible\n"); 1719614219eSNikolai Kondrashov goto finish; 1729614219eSNikolai Kondrashov } else if (rc < 0) { 1739614219eSNikolai Kondrashov hid_err(hdev, "failed retrieving pen parameters: %d\n", rc); 1749614219eSNikolai Kondrashov goto cleanup; 1759614219eSNikolai Kondrashov } else if (rc != len) { 1769614219eSNikolai Kondrashov hid_dbg(hdev, 1779614219eSNikolai Kondrashov "string descriptor with pen parameters has invalid length (got %d, expected %d), assuming not compatible\n", 1789614219eSNikolai Kondrashov rc, len); 1799614219eSNikolai Kondrashov goto finish; 1809614219eSNikolai Kondrashov } 1819614219eSNikolai Kondrashov 1829614219eSNikolai Kondrashov /* 1839614219eSNikolai Kondrashov * Fill report descriptor parameters from the string descriptor 1849614219eSNikolai Kondrashov */ 1859614219eSNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 1869614219eSNikolai Kondrashov get_unaligned_le16(buf + 2); 1879614219eSNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 1889614219eSNikolai Kondrashov get_unaligned_le16(buf + 4); 1899614219eSNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 1909614219eSNikolai Kondrashov get_unaligned_le16(buf + 8); 1919614219eSNikolai Kondrashov resolution = get_unaligned_le16(buf + 10); 1929614219eSNikolai Kondrashov if (resolution == 0) { 1939614219eSNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0; 1949614219eSNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0; 1959614219eSNikolai Kondrashov } else { 1969614219eSNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 1979614219eSNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 / 1989614219eSNikolai Kondrashov resolution; 1999614219eSNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 2009614219eSNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 / 2019614219eSNikolai Kondrashov resolution; 2029614219eSNikolai Kondrashov } 2039614219eSNikolai Kondrashov kfree(buf); 2049614219eSNikolai Kondrashov buf = NULL; 2059614219eSNikolai Kondrashov 2069614219eSNikolai Kondrashov /* 2079614219eSNikolai Kondrashov * Generate pen report descriptor 2089614219eSNikolai Kondrashov */ 2099614219eSNikolai Kondrashov desc_ptr = uclogic_rdesc_template_apply( 210a985de58SNikolai Kondrashov uclogic_rdesc_v1_pen_template_arr, 211a985de58SNikolai Kondrashov uclogic_rdesc_v1_pen_template_size, 2129614219eSNikolai Kondrashov desc_params, ARRAY_SIZE(desc_params)); 2139614219eSNikolai Kondrashov if (desc_ptr == NULL) { 2149614219eSNikolai Kondrashov rc = -ENOMEM; 2159614219eSNikolai Kondrashov goto cleanup; 2169614219eSNikolai Kondrashov } 2179614219eSNikolai Kondrashov 2189614219eSNikolai Kondrashov /* 2199614219eSNikolai Kondrashov * Fill-in the parameters 2209614219eSNikolai Kondrashov */ 2219614219eSNikolai Kondrashov memset(pen, 0, sizeof(*pen)); 2229614219eSNikolai Kondrashov pen->desc_ptr = desc_ptr; 2239614219eSNikolai Kondrashov desc_ptr = NULL; 224a985de58SNikolai Kondrashov pen->desc_size = uclogic_rdesc_v1_pen_template_size; 225a985de58SNikolai Kondrashov pen->id = UCLOGIC_RDESC_V1_PEN_ID; 2269614219eSNikolai Kondrashov pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_INVERTED; 2279614219eSNikolai Kondrashov found = true; 2289614219eSNikolai Kondrashov finish: 2299614219eSNikolai Kondrashov *pfound = found; 2309614219eSNikolai Kondrashov rc = 0; 2319614219eSNikolai Kondrashov cleanup: 2329614219eSNikolai Kondrashov kfree(desc_ptr); 2339614219eSNikolai Kondrashov kfree(buf); 2349614219eSNikolai Kondrashov return rc; 2359614219eSNikolai Kondrashov } 2369614219eSNikolai Kondrashov 2379614219eSNikolai Kondrashov /** 2382c3a88c6SNikolai Kondrashov * uclogic_params_get_le24() - get a 24-bit little-endian number from a 2392c3a88c6SNikolai Kondrashov * buffer. 2402c3a88c6SNikolai Kondrashov * 2412c3a88c6SNikolai Kondrashov * @p: The pointer to the number buffer. 2422c3a88c6SNikolai Kondrashov * 2432c3a88c6SNikolai Kondrashov * Returns: 2442c3a88c6SNikolai Kondrashov * The retrieved number 2452c3a88c6SNikolai Kondrashov */ 2462c3a88c6SNikolai Kondrashov static s32 uclogic_params_get_le24(const void *p) 2472c3a88c6SNikolai Kondrashov { 2482c3a88c6SNikolai Kondrashov const __u8 *b = p; 2492c3a88c6SNikolai Kondrashov return b[0] | (b[1] << 8UL) | (b[2] << 16UL); 2502c3a88c6SNikolai Kondrashov } 2512c3a88c6SNikolai Kondrashov 2522c3a88c6SNikolai Kondrashov /** 2532c3a88c6SNikolai Kondrashov * uclogic_params_pen_init_v2() - initialize tablet interface pen 2542c3a88c6SNikolai Kondrashov * input and retrieve its parameters from the device, using v2 protocol. 2552c3a88c6SNikolai Kondrashov * 2562c3a88c6SNikolai Kondrashov * @pen: Pointer to the pen parameters to initialize (to be 2572c3a88c6SNikolai Kondrashov * cleaned up with uclogic_params_pen_cleanup()). Not modified in 2582c3a88c6SNikolai Kondrashov * case of error, or if parameters are not found. Cannot be NULL. 2592c3a88c6SNikolai Kondrashov * @pfound: Location for a flag which is set to true if the parameters 2602c3a88c6SNikolai Kondrashov * were found, and to false if not (e.g. device was 2612c3a88c6SNikolai Kondrashov * incompatible). Not modified in case of error. Cannot be NULL. 2622c3a88c6SNikolai Kondrashov * @hdev: The HID device of the tablet interface to initialize and get 2632c3a88c6SNikolai Kondrashov * parameters from. Cannot be NULL. 2642c3a88c6SNikolai Kondrashov * 2652c3a88c6SNikolai Kondrashov * Returns: 2662c3a88c6SNikolai Kondrashov * Zero, if successful. A negative errno code on error. 2672c3a88c6SNikolai Kondrashov */ 2682c3a88c6SNikolai Kondrashov static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen, 2692c3a88c6SNikolai Kondrashov bool *pfound, 2702c3a88c6SNikolai Kondrashov struct hid_device *hdev) 2712c3a88c6SNikolai Kondrashov { 2722c3a88c6SNikolai Kondrashov int rc; 2732c3a88c6SNikolai Kondrashov bool found = false; 2742c3a88c6SNikolai Kondrashov /* Buffer for (part of) the string descriptor */ 2752c3a88c6SNikolai Kondrashov __u8 *buf = NULL; 2762c3a88c6SNikolai Kondrashov /* Descriptor length required */ 2772c3a88c6SNikolai Kondrashov const int len = 18; 2782c3a88c6SNikolai Kondrashov s32 resolution; 2792c3a88c6SNikolai Kondrashov /* Pen report descriptor template parameters */ 2802c3a88c6SNikolai Kondrashov s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM]; 2812c3a88c6SNikolai Kondrashov __u8 *desc_ptr = NULL; 2822c3a88c6SNikolai Kondrashov 2832c3a88c6SNikolai Kondrashov /* Check arguments */ 2842c3a88c6SNikolai Kondrashov if (pen == NULL || pfound == NULL || hdev == NULL) { 2852c3a88c6SNikolai Kondrashov rc = -EINVAL; 2862c3a88c6SNikolai Kondrashov goto cleanup; 2872c3a88c6SNikolai Kondrashov } 2882c3a88c6SNikolai Kondrashov 2892c3a88c6SNikolai Kondrashov /* 2902c3a88c6SNikolai Kondrashov * Read string descriptor containing pen input parameters. 2912c3a88c6SNikolai Kondrashov * The specific string descriptor and data were discovered by sniffing 2922c3a88c6SNikolai Kondrashov * the Windows driver traffic. 2932c3a88c6SNikolai Kondrashov * NOTE: This enables fully-functional tablet mode. 2942c3a88c6SNikolai Kondrashov */ 2952c3a88c6SNikolai Kondrashov rc = uclogic_params_get_str_desc(&buf, hdev, 200, len); 2962c3a88c6SNikolai Kondrashov if (rc == -EPIPE) { 2972c3a88c6SNikolai Kondrashov hid_dbg(hdev, 2982c3a88c6SNikolai Kondrashov "string descriptor with pen parameters not found, assuming not compatible\n"); 2992c3a88c6SNikolai Kondrashov goto finish; 3002c3a88c6SNikolai Kondrashov } else if (rc < 0) { 3012c3a88c6SNikolai Kondrashov hid_err(hdev, "failed retrieving pen parameters: %d\n", rc); 3022c3a88c6SNikolai Kondrashov goto cleanup; 3032c3a88c6SNikolai Kondrashov } else if (rc != len) { 3042c3a88c6SNikolai Kondrashov hid_dbg(hdev, 3052c3a88c6SNikolai Kondrashov "string descriptor with pen parameters has invalid length (got %d, expected %d), assuming not compatible\n", 3062c3a88c6SNikolai Kondrashov rc, len); 3072c3a88c6SNikolai Kondrashov goto finish; 3082c3a88c6SNikolai Kondrashov } else { 3092c3a88c6SNikolai Kondrashov size_t i; 3102c3a88c6SNikolai Kondrashov /* 3112c3a88c6SNikolai Kondrashov * Check it's not just a catch-all UTF-16LE-encoded ASCII 3122c3a88c6SNikolai Kondrashov * string (such as the model name) some tablets put into all 3132c3a88c6SNikolai Kondrashov * unknown string descriptors. 3142c3a88c6SNikolai Kondrashov */ 3152c3a88c6SNikolai Kondrashov for (i = 2; 3162c3a88c6SNikolai Kondrashov i < len && 3172c3a88c6SNikolai Kondrashov (buf[i] >= 0x20 && buf[i] < 0x7f && buf[i + 1] == 0); 3182c3a88c6SNikolai Kondrashov i += 2); 3192c3a88c6SNikolai Kondrashov if (i >= len) { 3202c3a88c6SNikolai Kondrashov hid_dbg(hdev, 3212c3a88c6SNikolai Kondrashov "string descriptor with pen parameters seems to contain only text, assuming not compatible\n"); 3222c3a88c6SNikolai Kondrashov goto finish; 3232c3a88c6SNikolai Kondrashov } 3242c3a88c6SNikolai Kondrashov } 3252c3a88c6SNikolai Kondrashov 3262c3a88c6SNikolai Kondrashov /* 3272c3a88c6SNikolai Kondrashov * Fill report descriptor parameters from the string descriptor 3282c3a88c6SNikolai Kondrashov */ 3292c3a88c6SNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 3302c3a88c6SNikolai Kondrashov uclogic_params_get_le24(buf + 2); 3312c3a88c6SNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 3322c3a88c6SNikolai Kondrashov uclogic_params_get_le24(buf + 5); 3332c3a88c6SNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 3342c3a88c6SNikolai Kondrashov get_unaligned_le16(buf + 8); 3352c3a88c6SNikolai Kondrashov resolution = get_unaligned_le16(buf + 10); 3362c3a88c6SNikolai Kondrashov if (resolution == 0) { 3372c3a88c6SNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0; 3382c3a88c6SNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0; 3392c3a88c6SNikolai Kondrashov } else { 3402c3a88c6SNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 3412c3a88c6SNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 / 3422c3a88c6SNikolai Kondrashov resolution; 3432c3a88c6SNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 3442c3a88c6SNikolai Kondrashov desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 / 3452c3a88c6SNikolai Kondrashov resolution; 3462c3a88c6SNikolai Kondrashov } 3472c3a88c6SNikolai Kondrashov kfree(buf); 3482c3a88c6SNikolai Kondrashov buf = NULL; 3492c3a88c6SNikolai Kondrashov 3502c3a88c6SNikolai Kondrashov /* 3512c3a88c6SNikolai Kondrashov * Generate pen report descriptor 3522c3a88c6SNikolai Kondrashov */ 3532c3a88c6SNikolai Kondrashov desc_ptr = uclogic_rdesc_template_apply( 354a985de58SNikolai Kondrashov uclogic_rdesc_v2_pen_template_arr, 355a985de58SNikolai Kondrashov uclogic_rdesc_v2_pen_template_size, 3562c3a88c6SNikolai Kondrashov desc_params, ARRAY_SIZE(desc_params)); 3572c3a88c6SNikolai Kondrashov if (desc_ptr == NULL) { 3582c3a88c6SNikolai Kondrashov rc = -ENOMEM; 3592c3a88c6SNikolai Kondrashov goto cleanup; 3602c3a88c6SNikolai Kondrashov } 3612c3a88c6SNikolai Kondrashov 3622c3a88c6SNikolai Kondrashov /* 3632c3a88c6SNikolai Kondrashov * Fill-in the parameters 3642c3a88c6SNikolai Kondrashov */ 3652c3a88c6SNikolai Kondrashov memset(pen, 0, sizeof(*pen)); 3662c3a88c6SNikolai Kondrashov pen->desc_ptr = desc_ptr; 3672c3a88c6SNikolai Kondrashov desc_ptr = NULL; 368a985de58SNikolai Kondrashov pen->desc_size = uclogic_rdesc_v2_pen_template_size; 369a985de58SNikolai Kondrashov pen->id = UCLOGIC_RDESC_V2_PEN_ID; 3702c3a88c6SNikolai Kondrashov pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_NONE; 3712c3a88c6SNikolai Kondrashov pen->fragmented_hires = true; 3721324c5acSNikolai Kondrashov pen->tilt_y_flipped = true; 3732c3a88c6SNikolai Kondrashov found = true; 3742c3a88c6SNikolai Kondrashov finish: 3752c3a88c6SNikolai Kondrashov *pfound = found; 3762c3a88c6SNikolai Kondrashov rc = 0; 3772c3a88c6SNikolai Kondrashov cleanup: 3782c3a88c6SNikolai Kondrashov kfree(desc_ptr); 3792c3a88c6SNikolai Kondrashov kfree(buf); 3802c3a88c6SNikolai Kondrashov return rc; 3812c3a88c6SNikolai Kondrashov } 3822c3a88c6SNikolai Kondrashov 3832c3a88c6SNikolai Kondrashov /** 3849614219eSNikolai Kondrashov * uclogic_params_frame_cleanup - free resources used by struct 3859614219eSNikolai Kondrashov * uclogic_params_frame (tablet interface's frame controls input parameters). 3869614219eSNikolai Kondrashov * Can be called repeatedly. 3879614219eSNikolai Kondrashov * 3889614219eSNikolai Kondrashov * @frame: Frame controls input parameters to cleanup. Cannot be NULL. 3899614219eSNikolai Kondrashov */ 3909614219eSNikolai Kondrashov static void uclogic_params_frame_cleanup(struct uclogic_params_frame *frame) 3919614219eSNikolai Kondrashov { 3929614219eSNikolai Kondrashov kfree(frame->desc_ptr); 3939614219eSNikolai Kondrashov memset(frame, 0, sizeof(*frame)); 3949614219eSNikolai Kondrashov } 3959614219eSNikolai Kondrashov 3969614219eSNikolai Kondrashov /** 3979614219eSNikolai Kondrashov * uclogic_params_frame_init_with_desc() - initialize tablet's frame control 3989614219eSNikolai Kondrashov * parameters with a static report descriptor. 3999614219eSNikolai Kondrashov * 4009614219eSNikolai Kondrashov * @frame: Pointer to the frame parameters to initialize (to be cleaned 4019614219eSNikolai Kondrashov * up with uclogic_params_frame_cleanup()). Not modified in case 4029614219eSNikolai Kondrashov * of error. Cannot be NULL. 4039614219eSNikolai Kondrashov * @desc_ptr: Report descriptor pointer. Can be NULL, if desc_size is zero. 4049614219eSNikolai Kondrashov * @desc_size: Report descriptor size. 4059614219eSNikolai Kondrashov * @id: Report ID used for frame reports, if they should be tweaked, 4069614219eSNikolai Kondrashov * zero if not. 4079614219eSNikolai Kondrashov * 4089614219eSNikolai Kondrashov * Returns: 4099614219eSNikolai Kondrashov * Zero, if successful. A negative errno code on error. 4109614219eSNikolai Kondrashov */ 4119614219eSNikolai Kondrashov static int uclogic_params_frame_init_with_desc( 4129614219eSNikolai Kondrashov struct uclogic_params_frame *frame, 4139614219eSNikolai Kondrashov const __u8 *desc_ptr, 4149614219eSNikolai Kondrashov size_t desc_size, 4159614219eSNikolai Kondrashov unsigned int id) 4169614219eSNikolai Kondrashov { 4179614219eSNikolai Kondrashov __u8 *copy_desc_ptr; 4189614219eSNikolai Kondrashov 4199614219eSNikolai Kondrashov if (frame == NULL || (desc_ptr == NULL && desc_size != 0)) 4209614219eSNikolai Kondrashov return -EINVAL; 4219614219eSNikolai Kondrashov 4229614219eSNikolai Kondrashov copy_desc_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL); 4239614219eSNikolai Kondrashov if (copy_desc_ptr == NULL) 4249614219eSNikolai Kondrashov return -ENOMEM; 4259614219eSNikolai Kondrashov 4269614219eSNikolai Kondrashov memset(frame, 0, sizeof(*frame)); 4279614219eSNikolai Kondrashov frame->desc_ptr = copy_desc_ptr; 4289614219eSNikolai Kondrashov frame->desc_size = desc_size; 4299614219eSNikolai Kondrashov frame->id = id; 4309614219eSNikolai Kondrashov return 0; 4319614219eSNikolai Kondrashov } 4329614219eSNikolai Kondrashov 4339614219eSNikolai Kondrashov /** 4342e28f3e0SNikolai Kondrashov * uclogic_params_frame_init_v1() - initialize v1 tablet interface frame 4352e28f3e0SNikolai Kondrashov * controls. 4369614219eSNikolai Kondrashov * 4379614219eSNikolai Kondrashov * @frame: Pointer to the frame parameters to initialize (to be cleaned 4389614219eSNikolai Kondrashov * up with uclogic_params_frame_cleanup()). Not modified in case 4399614219eSNikolai Kondrashov * of error, or if parameters are not found. Cannot be NULL. 4409614219eSNikolai Kondrashov * @pfound: Location for a flag which is set to true if the parameters 4419614219eSNikolai Kondrashov * were found, and to false if not (e.g. device was 4429614219eSNikolai Kondrashov * incompatible). Not modified in case of error. Cannot be NULL. 4439614219eSNikolai Kondrashov * @hdev: The HID device of the tablet interface to initialize and get 4449614219eSNikolai Kondrashov * parameters from. Cannot be NULL. 4459614219eSNikolai Kondrashov * 4469614219eSNikolai Kondrashov * Returns: 4479614219eSNikolai Kondrashov * Zero, if successful. A negative errno code on error. 4489614219eSNikolai Kondrashov */ 4492e28f3e0SNikolai Kondrashov static int uclogic_params_frame_init_v1(struct uclogic_params_frame *frame, 4509614219eSNikolai Kondrashov bool *pfound, 4519614219eSNikolai Kondrashov struct hid_device *hdev) 4529614219eSNikolai Kondrashov { 4539614219eSNikolai Kondrashov int rc; 4549614219eSNikolai Kondrashov bool found = false; 455aa320fdbSJosé Expósito struct usb_device *usb_dev; 4569614219eSNikolai Kondrashov char *str_buf = NULL; 4579614219eSNikolai Kondrashov const size_t str_len = 16; 4589614219eSNikolai Kondrashov 4599614219eSNikolai Kondrashov /* Check arguments */ 4609614219eSNikolai Kondrashov if (frame == NULL || pfound == NULL || hdev == NULL) { 4619614219eSNikolai Kondrashov rc = -EINVAL; 4629614219eSNikolai Kondrashov goto cleanup; 4639614219eSNikolai Kondrashov } 4649614219eSNikolai Kondrashov 465aa320fdbSJosé Expósito usb_dev = hid_to_usb_dev(hdev); 466aa320fdbSJosé Expósito 4679614219eSNikolai Kondrashov /* 4689614219eSNikolai Kondrashov * Enable generic button mode 4699614219eSNikolai Kondrashov */ 4709614219eSNikolai Kondrashov str_buf = kzalloc(str_len, GFP_KERNEL); 4719614219eSNikolai Kondrashov if (str_buf == NULL) { 4729614219eSNikolai Kondrashov rc = -ENOMEM; 4739614219eSNikolai Kondrashov goto cleanup; 4749614219eSNikolai Kondrashov } 4759614219eSNikolai Kondrashov 4769614219eSNikolai Kondrashov rc = usb_string(usb_dev, 123, str_buf, str_len); 4779614219eSNikolai Kondrashov if (rc == -EPIPE) { 4789614219eSNikolai Kondrashov hid_dbg(hdev, 4799614219eSNikolai Kondrashov "generic button -enabling string descriptor not found\n"); 4809614219eSNikolai Kondrashov } else if (rc < 0) { 4819614219eSNikolai Kondrashov goto cleanup; 4829614219eSNikolai Kondrashov } else if (strncmp(str_buf, "HK On", rc) != 0) { 4839614219eSNikolai Kondrashov hid_dbg(hdev, 4849614219eSNikolai Kondrashov "invalid response to enabling generic buttons: \"%s\"\n", 4859614219eSNikolai Kondrashov str_buf); 4869614219eSNikolai Kondrashov } else { 4879614219eSNikolai Kondrashov hid_dbg(hdev, "generic buttons enabled\n"); 4889614219eSNikolai Kondrashov rc = uclogic_params_frame_init_with_desc( 4899614219eSNikolai Kondrashov frame, 490a985de58SNikolai Kondrashov uclogic_rdesc_v1_frame_arr, 491a985de58SNikolai Kondrashov uclogic_rdesc_v1_frame_size, 492a985de58SNikolai Kondrashov UCLOGIC_RDESC_V1_FRAME_ID); 4939614219eSNikolai Kondrashov if (rc != 0) 4949614219eSNikolai Kondrashov goto cleanup; 4959614219eSNikolai Kondrashov found = true; 4969614219eSNikolai Kondrashov } 4979614219eSNikolai Kondrashov 4989614219eSNikolai Kondrashov *pfound = found; 4999614219eSNikolai Kondrashov rc = 0; 5009614219eSNikolai Kondrashov cleanup: 5019614219eSNikolai Kondrashov kfree(str_buf); 5029614219eSNikolai Kondrashov return rc; 5039614219eSNikolai Kondrashov } 5049614219eSNikolai Kondrashov 5059614219eSNikolai Kondrashov /** 5069614219eSNikolai Kondrashov * uclogic_params_cleanup - free resources used by struct uclogic_params 5079614219eSNikolai Kondrashov * (tablet interface's parameters). 5089614219eSNikolai Kondrashov * Can be called repeatedly. 5099614219eSNikolai Kondrashov * 5109614219eSNikolai Kondrashov * @params: Input parameters to cleanup. Cannot be NULL. 5119614219eSNikolai Kondrashov */ 5129614219eSNikolai Kondrashov void uclogic_params_cleanup(struct uclogic_params *params) 5139614219eSNikolai Kondrashov { 5149614219eSNikolai Kondrashov if (!params->invalid) { 515*337fa051SNikolai Kondrashov size_t i; 5169614219eSNikolai Kondrashov kfree(params->desc_ptr); 5179614219eSNikolai Kondrashov uclogic_params_pen_cleanup(¶ms->pen); 518*337fa051SNikolai Kondrashov for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) 519*337fa051SNikolai Kondrashov uclogic_params_frame_cleanup(¶ms->frame_list[i]); 520*337fa051SNikolai Kondrashov 5219614219eSNikolai Kondrashov memset(params, 0, sizeof(*params)); 5229614219eSNikolai Kondrashov } 5239614219eSNikolai Kondrashov } 5249614219eSNikolai Kondrashov 5259614219eSNikolai Kondrashov /** 5265abb5445SLee Jones * uclogic_params_get_desc() - Get a replacement report descriptor for a 5275abb5445SLee Jones * tablet's interface. 5289614219eSNikolai Kondrashov * 5299614219eSNikolai Kondrashov * @params: The parameters of a tablet interface to get report 5309614219eSNikolai Kondrashov * descriptor for. Cannot be NULL. 5319614219eSNikolai Kondrashov * @pdesc: Location for the resulting, kmalloc-allocated report 5329614219eSNikolai Kondrashov * descriptor pointer, or for NULL, if there's no replacement 5339614219eSNikolai Kondrashov * report descriptor. Not modified in case of error. Cannot be 5349614219eSNikolai Kondrashov * NULL. 5359614219eSNikolai Kondrashov * @psize: Location for the resulting report descriptor size, not set if 5369614219eSNikolai Kondrashov * there's no replacement report descriptor. Not modified in case 5379614219eSNikolai Kondrashov * of error. Cannot be NULL. 5389614219eSNikolai Kondrashov * 5399614219eSNikolai Kondrashov * Returns: 5409614219eSNikolai Kondrashov * Zero, if successful. 5419614219eSNikolai Kondrashov * -EINVAL, if invalid arguments are supplied. 5429614219eSNikolai Kondrashov * -ENOMEM, if failed to allocate memory. 5439614219eSNikolai Kondrashov */ 5449614219eSNikolai Kondrashov int uclogic_params_get_desc(const struct uclogic_params *params, 5459614219eSNikolai Kondrashov __u8 **pdesc, 5469614219eSNikolai Kondrashov unsigned int *psize) 5479614219eSNikolai Kondrashov { 548*337fa051SNikolai Kondrashov int rc = -ENOMEM; 549*337fa051SNikolai Kondrashov bool present = false; 550*337fa051SNikolai Kondrashov unsigned int size = 0; 5519614219eSNikolai Kondrashov __u8 *desc = NULL; 552*337fa051SNikolai Kondrashov size_t i; 5539614219eSNikolai Kondrashov 5549614219eSNikolai Kondrashov /* Check arguments */ 5559614219eSNikolai Kondrashov if (params == NULL || pdesc == NULL || psize == NULL) 5569614219eSNikolai Kondrashov return -EINVAL; 5579614219eSNikolai Kondrashov 558*337fa051SNikolai Kondrashov /* Concatenate descriptors */ 559*337fa051SNikolai Kondrashov #define ADD_DESC(_desc_ptr, _desc_size) \ 560*337fa051SNikolai Kondrashov do { \ 561*337fa051SNikolai Kondrashov unsigned int new_size; \ 562*337fa051SNikolai Kondrashov __u8 *new_desc; \ 563*337fa051SNikolai Kondrashov if ((_desc_ptr) == NULL) { \ 564*337fa051SNikolai Kondrashov break; \ 565*337fa051SNikolai Kondrashov } \ 566*337fa051SNikolai Kondrashov new_size = size + (_desc_size); \ 567*337fa051SNikolai Kondrashov new_desc = krealloc(desc, new_size, GFP_KERNEL); \ 568*337fa051SNikolai Kondrashov if (new_desc == NULL) { \ 569*337fa051SNikolai Kondrashov goto cleanup; \ 570*337fa051SNikolai Kondrashov } \ 571*337fa051SNikolai Kondrashov memcpy(new_desc + size, (_desc_ptr), (_desc_size)); \ 572*337fa051SNikolai Kondrashov desc = new_desc; \ 573*337fa051SNikolai Kondrashov size = new_size; \ 574*337fa051SNikolai Kondrashov present = true; \ 575*337fa051SNikolai Kondrashov } while (0) 5769614219eSNikolai Kondrashov 577*337fa051SNikolai Kondrashov ADD_DESC(params->desc_ptr, params->desc_size); 578*337fa051SNikolai Kondrashov ADD_DESC(params->pen.desc_ptr, params->pen.desc_size); 579*337fa051SNikolai Kondrashov for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) { 580*337fa051SNikolai Kondrashov ADD_DESC(params->frame_list[i].desc_ptr, 581*337fa051SNikolai Kondrashov params->frame_list[i].desc_size); 5829614219eSNikolai Kondrashov } 5839614219eSNikolai Kondrashov 584*337fa051SNikolai Kondrashov #undef ADD_DESC 5859614219eSNikolai Kondrashov 586*337fa051SNikolai Kondrashov if (present) { 5879614219eSNikolai Kondrashov *pdesc = desc; 588*337fa051SNikolai Kondrashov *psize = size; 589*337fa051SNikolai Kondrashov desc = NULL; 590*337fa051SNikolai Kondrashov } 591*337fa051SNikolai Kondrashov rc = 0; 592*337fa051SNikolai Kondrashov cleanup: 593*337fa051SNikolai Kondrashov kfree(desc); 594*337fa051SNikolai Kondrashov return rc; 5959614219eSNikolai Kondrashov } 5969614219eSNikolai Kondrashov 5979614219eSNikolai Kondrashov /** 5989614219eSNikolai Kondrashov * uclogic_params_init_invalid() - initialize tablet interface parameters, 5999614219eSNikolai Kondrashov * specifying the interface is invalid. 6009614219eSNikolai Kondrashov * 6019614219eSNikolai Kondrashov * @params: Parameters to initialize (to be cleaned with 6029614219eSNikolai Kondrashov * uclogic_params_cleanup()). Cannot be NULL. 6039614219eSNikolai Kondrashov */ 6049614219eSNikolai Kondrashov static void uclogic_params_init_invalid(struct uclogic_params *params) 6059614219eSNikolai Kondrashov { 6069614219eSNikolai Kondrashov params->invalid = true; 6079614219eSNikolai Kondrashov } 6089614219eSNikolai Kondrashov 6099614219eSNikolai Kondrashov /** 6109614219eSNikolai Kondrashov * uclogic_params_init_with_opt_desc() - initialize tablet interface 6119614219eSNikolai Kondrashov * parameters with an optional replacement report descriptor. Only modify 6129614219eSNikolai Kondrashov * report descriptor, if the original report descriptor matches the expected 6139614219eSNikolai Kondrashov * size. 6149614219eSNikolai Kondrashov * 6159614219eSNikolai Kondrashov * @params: Parameters to initialize (to be cleaned with 6169614219eSNikolai Kondrashov * uclogic_params_cleanup()). Not modified in case of 6179614219eSNikolai Kondrashov * error. Cannot be NULL. 6189614219eSNikolai Kondrashov * @hdev: The HID device of the tablet interface create the 6199614219eSNikolai Kondrashov * parameters for. Cannot be NULL. 6209614219eSNikolai Kondrashov * @orig_desc_size: Expected size of the original report descriptor to 6219614219eSNikolai Kondrashov * be replaced. 6229614219eSNikolai Kondrashov * @desc_ptr: Pointer to the replacement report descriptor. 6239614219eSNikolai Kondrashov * Can be NULL, if desc_size is zero. 6249614219eSNikolai Kondrashov * @desc_size: Size of the replacement report descriptor. 6259614219eSNikolai Kondrashov * 6269614219eSNikolai Kondrashov * Returns: 6279614219eSNikolai Kondrashov * Zero, if successful. -EINVAL if an invalid argument was passed. 6289614219eSNikolai Kondrashov * -ENOMEM, if failed to allocate memory. 6299614219eSNikolai Kondrashov */ 6309614219eSNikolai Kondrashov static int uclogic_params_init_with_opt_desc(struct uclogic_params *params, 6319614219eSNikolai Kondrashov struct hid_device *hdev, 6329614219eSNikolai Kondrashov unsigned int orig_desc_size, 6339614219eSNikolai Kondrashov __u8 *desc_ptr, 6349614219eSNikolai Kondrashov unsigned int desc_size) 6359614219eSNikolai Kondrashov { 6369614219eSNikolai Kondrashov __u8 *desc_copy_ptr = NULL; 6379614219eSNikolai Kondrashov unsigned int desc_copy_size; 6389614219eSNikolai Kondrashov int rc; 6399614219eSNikolai Kondrashov 6409614219eSNikolai Kondrashov /* Check arguments */ 6419614219eSNikolai Kondrashov if (params == NULL || hdev == NULL || 6429614219eSNikolai Kondrashov (desc_ptr == NULL && desc_size != 0)) { 6439614219eSNikolai Kondrashov rc = -EINVAL; 6449614219eSNikolai Kondrashov goto cleanup; 6459614219eSNikolai Kondrashov } 6469614219eSNikolai Kondrashov 6479614219eSNikolai Kondrashov /* Replace report descriptor, if it matches */ 6489614219eSNikolai Kondrashov if (hdev->dev_rsize == orig_desc_size) { 6499614219eSNikolai Kondrashov hid_dbg(hdev, 6509614219eSNikolai Kondrashov "device report descriptor matches the expected size, replacing\n"); 6519614219eSNikolai Kondrashov desc_copy_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL); 6529614219eSNikolai Kondrashov if (desc_copy_ptr == NULL) { 6539614219eSNikolai Kondrashov rc = -ENOMEM; 6549614219eSNikolai Kondrashov goto cleanup; 6559614219eSNikolai Kondrashov } 6569614219eSNikolai Kondrashov desc_copy_size = desc_size; 6579614219eSNikolai Kondrashov } else { 6589614219eSNikolai Kondrashov hid_dbg(hdev, 6599614219eSNikolai Kondrashov "device report descriptor doesn't match the expected size (%u != %u), preserving\n", 6609614219eSNikolai Kondrashov hdev->dev_rsize, orig_desc_size); 6619614219eSNikolai Kondrashov desc_copy_ptr = NULL; 6629614219eSNikolai Kondrashov desc_copy_size = 0; 6639614219eSNikolai Kondrashov } 6649614219eSNikolai Kondrashov 6659614219eSNikolai Kondrashov /* Output parameters */ 6669614219eSNikolai Kondrashov memset(params, 0, sizeof(*params)); 6679614219eSNikolai Kondrashov params->desc_ptr = desc_copy_ptr; 6689614219eSNikolai Kondrashov desc_copy_ptr = NULL; 6699614219eSNikolai Kondrashov params->desc_size = desc_copy_size; 6709614219eSNikolai Kondrashov 6719614219eSNikolai Kondrashov rc = 0; 6729614219eSNikolai Kondrashov cleanup: 6739614219eSNikolai Kondrashov kfree(desc_copy_ptr); 6749614219eSNikolai Kondrashov return rc; 6759614219eSNikolai Kondrashov } 6769614219eSNikolai Kondrashov 6779614219eSNikolai Kondrashov /** 6785abb5445SLee Jones * uclogic_params_huion_init() - initialize a Huion tablet interface and discover 6799614219eSNikolai Kondrashov * its parameters. 6809614219eSNikolai Kondrashov * 6819614219eSNikolai Kondrashov * @params: Parameters to fill in (to be cleaned with 6829614219eSNikolai Kondrashov * uclogic_params_cleanup()). Not modified in case of error. 6839614219eSNikolai Kondrashov * Cannot be NULL. 6849614219eSNikolai Kondrashov * @hdev: The HID device of the tablet interface to initialize and get 6859614219eSNikolai Kondrashov * parameters from. Cannot be NULL. 6869614219eSNikolai Kondrashov * 6879614219eSNikolai Kondrashov * Returns: 6889614219eSNikolai Kondrashov * Zero, if successful. A negative errno code on error. 6899614219eSNikolai Kondrashov */ 6909614219eSNikolai Kondrashov static int uclogic_params_huion_init(struct uclogic_params *params, 6919614219eSNikolai Kondrashov struct hid_device *hdev) 6929614219eSNikolai Kondrashov { 6939614219eSNikolai Kondrashov int rc; 694ff6b548aSJosé Expósito struct usb_device *udev; 695ff6b548aSJosé Expósito struct usb_interface *iface; 696ff6b548aSJosé Expósito __u8 bInterfaceNumber; 6979614219eSNikolai Kondrashov bool found; 6989614219eSNikolai Kondrashov /* The resulting parameters (noop) */ 6999614219eSNikolai Kondrashov struct uclogic_params p = {0, }; 7002c3a88c6SNikolai Kondrashov static const char transition_ver[] = "HUION_T153_160607"; 7012c3a88c6SNikolai Kondrashov char *ver_ptr = NULL; 7022c3a88c6SNikolai Kondrashov const size_t ver_len = sizeof(transition_ver) + 1; 7039614219eSNikolai Kondrashov 7049614219eSNikolai Kondrashov /* Check arguments */ 7059614219eSNikolai Kondrashov if (params == NULL || hdev == NULL) { 7069614219eSNikolai Kondrashov rc = -EINVAL; 7079614219eSNikolai Kondrashov goto cleanup; 7089614219eSNikolai Kondrashov } 7099614219eSNikolai Kondrashov 710ff6b548aSJosé Expósito udev = hid_to_usb_dev(hdev); 711ff6b548aSJosé Expósito iface = to_usb_interface(hdev->dev.parent); 712ff6b548aSJosé Expósito bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber; 713ff6b548aSJosé Expósito 7149614219eSNikolai Kondrashov /* If it's not a pen interface */ 7159614219eSNikolai Kondrashov if (bInterfaceNumber != 0) { 716606dadc1SNikolai Kondrashov uclogic_params_init_invalid(&p); 7179614219eSNikolai Kondrashov goto output; 7189614219eSNikolai Kondrashov } 7199614219eSNikolai Kondrashov 7202c3a88c6SNikolai Kondrashov /* Try to get firmware version */ 7212c3a88c6SNikolai Kondrashov ver_ptr = kzalloc(ver_len, GFP_KERNEL); 7222c3a88c6SNikolai Kondrashov if (ver_ptr == NULL) { 7232c3a88c6SNikolai Kondrashov rc = -ENOMEM; 7242c3a88c6SNikolai Kondrashov goto cleanup; 7252c3a88c6SNikolai Kondrashov } 7262c3a88c6SNikolai Kondrashov rc = usb_string(udev, 201, ver_ptr, ver_len); 7272c3a88c6SNikolai Kondrashov if (rc == -EPIPE) { 7282c3a88c6SNikolai Kondrashov *ver_ptr = '\0'; 7292c3a88c6SNikolai Kondrashov } else if (rc < 0) { 7302c3a88c6SNikolai Kondrashov hid_err(hdev, 7312c3a88c6SNikolai Kondrashov "failed retrieving Huion firmware version: %d\n", rc); 7322c3a88c6SNikolai Kondrashov goto cleanup; 7332c3a88c6SNikolai Kondrashov } 7342c3a88c6SNikolai Kondrashov 7352c3a88c6SNikolai Kondrashov /* If this is a transition firmware */ 7362c3a88c6SNikolai Kondrashov if (strcmp(ver_ptr, transition_ver) == 0) { 7372c3a88c6SNikolai Kondrashov hid_dbg(hdev, 7382c3a88c6SNikolai Kondrashov "transition firmware detected, not probing pen v2 parameters\n"); 7392c3a88c6SNikolai Kondrashov } else { 7402c3a88c6SNikolai Kondrashov /* Try to probe v2 pen parameters */ 7412c3a88c6SNikolai Kondrashov rc = uclogic_params_pen_init_v2(&p.pen, &found, hdev); 7422c3a88c6SNikolai Kondrashov if (rc != 0) { 7432c3a88c6SNikolai Kondrashov hid_err(hdev, 7442c3a88c6SNikolai Kondrashov "failed probing pen v2 parameters: %d\n", rc); 7452c3a88c6SNikolai Kondrashov goto cleanup; 7462c3a88c6SNikolai Kondrashov } else if (found) { 7472c3a88c6SNikolai Kondrashov hid_dbg(hdev, "pen v2 parameters found\n"); 7482e28f3e0SNikolai Kondrashov /* Create v2 frame parameters */ 7492c3a88c6SNikolai Kondrashov rc = uclogic_params_frame_init_with_desc( 750*337fa051SNikolai Kondrashov &p.frame_list[0], 751a985de58SNikolai Kondrashov uclogic_rdesc_v2_frame_arr, 752a985de58SNikolai Kondrashov uclogic_rdesc_v2_frame_size, 753a985de58SNikolai Kondrashov UCLOGIC_RDESC_V2_FRAME_ID); 7542c3a88c6SNikolai Kondrashov if (rc != 0) { 7552c3a88c6SNikolai Kondrashov hid_err(hdev, 7562e28f3e0SNikolai Kondrashov "failed creating v2 frame parameters: %d\n", 7572c3a88c6SNikolai Kondrashov rc); 7582c3a88c6SNikolai Kondrashov goto cleanup; 7592c3a88c6SNikolai Kondrashov } 7608b013098SNikolai Kondrashov /* Link frame button subreports from pen reports */ 761e6be956fSNikolai Kondrashov p.pen.subreport_list[0].value = 0xe0; 7628b013098SNikolai Kondrashov p.pen.subreport_list[0].id = 763a985de58SNikolai Kondrashov UCLOGIC_RDESC_V2_FRAME_ID; 7642c3a88c6SNikolai Kondrashov goto output; 7652c3a88c6SNikolai Kondrashov } 7662c3a88c6SNikolai Kondrashov hid_dbg(hdev, "pen v2 parameters not found\n"); 7672c3a88c6SNikolai Kondrashov } 7682c3a88c6SNikolai Kondrashov 769eecb5b84SNikolai Kondrashov /* Try to probe v1 pen parameters */ 770eecb5b84SNikolai Kondrashov rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev); 7719614219eSNikolai Kondrashov if (rc != 0) { 7729614219eSNikolai Kondrashov hid_err(hdev, 773eecb5b84SNikolai Kondrashov "failed probing pen v1 parameters: %d\n", rc); 7749614219eSNikolai Kondrashov goto cleanup; 7759614219eSNikolai Kondrashov } else if (found) { 776eecb5b84SNikolai Kondrashov hid_dbg(hdev, "pen v1 parameters found\n"); 7772e28f3e0SNikolai Kondrashov /* Try to probe v1 frame */ 778*337fa051SNikolai Kondrashov rc = uclogic_params_frame_init_v1(&p.frame_list[0], 7799614219eSNikolai Kondrashov &found, hdev); 7809614219eSNikolai Kondrashov if (rc != 0) { 7812e28f3e0SNikolai Kondrashov hid_err(hdev, "v1 frame probing failed: %d\n", rc); 7829614219eSNikolai Kondrashov goto cleanup; 7839614219eSNikolai Kondrashov } 7842e28f3e0SNikolai Kondrashov hid_dbg(hdev, "frame v1 parameters%s found\n", 7859614219eSNikolai Kondrashov (found ? "" : " not")); 7869614219eSNikolai Kondrashov if (found) { 7878b013098SNikolai Kondrashov /* Link frame button subreports from pen reports */ 788e6be956fSNikolai Kondrashov p.pen.subreport_list[0].value = 0xe0; 7898b013098SNikolai Kondrashov p.pen.subreport_list[0].id = 790a985de58SNikolai Kondrashov UCLOGIC_RDESC_V1_FRAME_ID; 7919614219eSNikolai Kondrashov } 7929614219eSNikolai Kondrashov goto output; 7939614219eSNikolai Kondrashov } 794eecb5b84SNikolai Kondrashov hid_dbg(hdev, "pen v1 parameters not found\n"); 7959614219eSNikolai Kondrashov 7969614219eSNikolai Kondrashov uclogic_params_init_invalid(&p); 7979614219eSNikolai Kondrashov 7989614219eSNikolai Kondrashov output: 7999614219eSNikolai Kondrashov /* Output parameters */ 8009614219eSNikolai Kondrashov memcpy(params, &p, sizeof(*params)); 8019614219eSNikolai Kondrashov memset(&p, 0, sizeof(p)); 8029614219eSNikolai Kondrashov rc = 0; 8039614219eSNikolai Kondrashov cleanup: 8042c3a88c6SNikolai Kondrashov kfree(ver_ptr); 8059614219eSNikolai Kondrashov uclogic_params_cleanup(&p); 8069614219eSNikolai Kondrashov return rc; 8079614219eSNikolai Kondrashov } 8089614219eSNikolai Kondrashov 8099614219eSNikolai Kondrashov /** 8109614219eSNikolai Kondrashov * uclogic_params_init() - initialize a tablet interface and discover its 8119614219eSNikolai Kondrashov * parameters. 8129614219eSNikolai Kondrashov * 8139614219eSNikolai Kondrashov * @params: Parameters to fill in (to be cleaned with 8149614219eSNikolai Kondrashov * uclogic_params_cleanup()). Not modified in case of error. 8159614219eSNikolai Kondrashov * Cannot be NULL. 8169614219eSNikolai Kondrashov * @hdev: The HID device of the tablet interface to initialize and get 8178547b778SNikolai Kondrashov * parameters from. Cannot be NULL. Must be using the USB low-level 8188547b778SNikolai Kondrashov * driver, i.e. be an actual USB tablet. 8199614219eSNikolai Kondrashov * 8209614219eSNikolai Kondrashov * Returns: 8219614219eSNikolai Kondrashov * Zero, if successful. A negative errno code on error. 8229614219eSNikolai Kondrashov */ 8239614219eSNikolai Kondrashov int uclogic_params_init(struct uclogic_params *params, 8249614219eSNikolai Kondrashov struct hid_device *hdev) 8259614219eSNikolai Kondrashov { 8269614219eSNikolai Kondrashov int rc; 827f364c571SJosé Expósito struct usb_device *udev; 828f364c571SJosé Expósito __u8 bNumInterfaces; 829f364c571SJosé Expósito struct usb_interface *iface; 830f364c571SJosé Expósito __u8 bInterfaceNumber; 8319614219eSNikolai Kondrashov bool found; 8329614219eSNikolai Kondrashov /* The resulting parameters (noop) */ 8339614219eSNikolai Kondrashov struct uclogic_params p = {0, }; 8349614219eSNikolai Kondrashov 8359614219eSNikolai Kondrashov /* Check arguments */ 836f83baa0cSGreg Kroah-Hartman if (params == NULL || hdev == NULL || !hid_is_usb(hdev)) { 8379614219eSNikolai Kondrashov rc = -EINVAL; 8389614219eSNikolai Kondrashov goto cleanup; 8399614219eSNikolai Kondrashov } 8409614219eSNikolai Kondrashov 841f364c571SJosé Expósito udev = hid_to_usb_dev(hdev); 842f364c571SJosé Expósito bNumInterfaces = udev->config->desc.bNumInterfaces; 843f364c571SJosé Expósito iface = to_usb_interface(hdev->dev.parent); 844f364c571SJosé Expósito bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber; 845f364c571SJosé Expósito 8469614219eSNikolai Kondrashov /* 8479614219eSNikolai Kondrashov * Set replacement report descriptor if the original matches the 8489614219eSNikolai Kondrashov * specified size. Otherwise keep interface unchanged. 8499614219eSNikolai Kondrashov */ 8509614219eSNikolai Kondrashov #define WITH_OPT_DESC(_orig_desc_token, _new_desc_token) \ 8519614219eSNikolai Kondrashov uclogic_params_init_with_opt_desc( \ 8529614219eSNikolai Kondrashov &p, hdev, \ 8539614219eSNikolai Kondrashov UCLOGIC_RDESC_##_orig_desc_token##_SIZE, \ 8549614219eSNikolai Kondrashov uclogic_rdesc_##_new_desc_token##_arr, \ 8559614219eSNikolai Kondrashov uclogic_rdesc_##_new_desc_token##_size) 8569614219eSNikolai Kondrashov 8579614219eSNikolai Kondrashov #define VID_PID(_vid, _pid) \ 8589614219eSNikolai Kondrashov (((__u32)(_vid) << 16) | ((__u32)(_pid) & U16_MAX)) 8599614219eSNikolai Kondrashov 8609614219eSNikolai Kondrashov /* 8619614219eSNikolai Kondrashov * Handle specific interfaces for specific tablets. 8629614219eSNikolai Kondrashov * 8639614219eSNikolai Kondrashov * Observe the following logic: 8649614219eSNikolai Kondrashov * 8659614219eSNikolai Kondrashov * If the interface is recognized as producing certain useful input: 8669614219eSNikolai Kondrashov * Mark interface as valid. 8679614219eSNikolai Kondrashov * Output interface parameters. 8689614219eSNikolai Kondrashov * Else, if the interface is recognized as *not* producing any useful 8699614219eSNikolai Kondrashov * input: 8709614219eSNikolai Kondrashov * Mark interface as invalid. 8719614219eSNikolai Kondrashov * Else: 8729614219eSNikolai Kondrashov * Mark interface as valid. 8739614219eSNikolai Kondrashov * Output noop parameters. 8749614219eSNikolai Kondrashov * 8759614219eSNikolai Kondrashov * Rule of thumb: it is better to disable a broken interface than let 8769614219eSNikolai Kondrashov * it spew garbage input. 8779614219eSNikolai Kondrashov */ 8789614219eSNikolai Kondrashov 8799614219eSNikolai Kondrashov switch (VID_PID(hdev->vendor, hdev->product)) { 8809614219eSNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UCLOGIC, 8819614219eSNikolai Kondrashov USB_DEVICE_ID_UCLOGIC_TABLET_PF1209): 8829614219eSNikolai Kondrashov rc = WITH_OPT_DESC(PF1209_ORIG, pf1209_fixed); 8839614219eSNikolai Kondrashov if (rc != 0) 8849614219eSNikolai Kondrashov goto cleanup; 8859614219eSNikolai Kondrashov break; 8869614219eSNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UCLOGIC, 8879614219eSNikolai Kondrashov USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U): 8889614219eSNikolai Kondrashov rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp4030u_fixed); 8899614219eSNikolai Kondrashov if (rc != 0) 8909614219eSNikolai Kondrashov goto cleanup; 8919614219eSNikolai Kondrashov break; 8929614219eSNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UCLOGIC, 8939614219eSNikolai Kondrashov USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U): 8949c17f735SNikolai Kondrashov if (hdev->dev_rsize == UCLOGIC_RDESC_WP5540U_V2_ORIG_SIZE) { 8959c17f735SNikolai Kondrashov if (bInterfaceNumber == 0) { 8969c17f735SNikolai Kondrashov /* Try to probe v1 pen parameters */ 8979c17f735SNikolai Kondrashov rc = uclogic_params_pen_init_v1(&p.pen, 8989c17f735SNikolai Kondrashov &found, hdev); 8999c17f735SNikolai Kondrashov if (rc != 0) { 9009c17f735SNikolai Kondrashov hid_err(hdev, 9019c17f735SNikolai Kondrashov "pen probing failed: %d\n", 9029c17f735SNikolai Kondrashov rc); 9039c17f735SNikolai Kondrashov goto cleanup; 9049c17f735SNikolai Kondrashov } 9059c17f735SNikolai Kondrashov if (!found) { 9069c17f735SNikolai Kondrashov hid_warn(hdev, 9079c17f735SNikolai Kondrashov "pen parameters not found"); 9089c17f735SNikolai Kondrashov } 9099c17f735SNikolai Kondrashov } else { 9109c17f735SNikolai Kondrashov uclogic_params_init_invalid(&p); 9119c17f735SNikolai Kondrashov } 9129c17f735SNikolai Kondrashov } else { 9139614219eSNikolai Kondrashov rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp5540u_fixed); 9149614219eSNikolai Kondrashov if (rc != 0) 9159614219eSNikolai Kondrashov goto cleanup; 9169c17f735SNikolai Kondrashov } 9179614219eSNikolai Kondrashov break; 9189614219eSNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UCLOGIC, 9199614219eSNikolai Kondrashov USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U): 9209614219eSNikolai Kondrashov rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp8060u_fixed); 9219614219eSNikolai Kondrashov if (rc != 0) 9229614219eSNikolai Kondrashov goto cleanup; 9239614219eSNikolai Kondrashov break; 9249614219eSNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UCLOGIC, 9259614219eSNikolai Kondrashov USB_DEVICE_ID_UCLOGIC_TABLET_WP1062): 9269614219eSNikolai Kondrashov rc = WITH_OPT_DESC(WP1062_ORIG, wp1062_fixed); 9279614219eSNikolai Kondrashov if (rc != 0) 9289614219eSNikolai Kondrashov goto cleanup; 9299614219eSNikolai Kondrashov break; 9309614219eSNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UCLOGIC, 9319614219eSNikolai Kondrashov USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850): 9329614219eSNikolai Kondrashov switch (bInterfaceNumber) { 9339614219eSNikolai Kondrashov case 0: 9349614219eSNikolai Kondrashov rc = WITH_OPT_DESC(TWHL850_ORIG0, twhl850_fixed0); 9359614219eSNikolai Kondrashov if (rc != 0) 9369614219eSNikolai Kondrashov goto cleanup; 9379614219eSNikolai Kondrashov break; 9389614219eSNikolai Kondrashov case 1: 9399614219eSNikolai Kondrashov rc = WITH_OPT_DESC(TWHL850_ORIG1, twhl850_fixed1); 9409614219eSNikolai Kondrashov if (rc != 0) 9419614219eSNikolai Kondrashov goto cleanup; 9429614219eSNikolai Kondrashov break; 9439614219eSNikolai Kondrashov case 2: 9449614219eSNikolai Kondrashov rc = WITH_OPT_DESC(TWHL850_ORIG2, twhl850_fixed2); 9459614219eSNikolai Kondrashov if (rc != 0) 9469614219eSNikolai Kondrashov goto cleanup; 9479614219eSNikolai Kondrashov break; 9489614219eSNikolai Kondrashov } 9499614219eSNikolai Kondrashov break; 9509614219eSNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UCLOGIC, 9519614219eSNikolai Kondrashov USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60): 9529614219eSNikolai Kondrashov /* 9539614219eSNikolai Kondrashov * If it is not a three-interface version, which is known to 9549614219eSNikolai Kondrashov * respond to initialization. 9559614219eSNikolai Kondrashov */ 9569614219eSNikolai Kondrashov if (bNumInterfaces != 3) { 9579614219eSNikolai Kondrashov switch (bInterfaceNumber) { 9589614219eSNikolai Kondrashov case 0: 9599614219eSNikolai Kondrashov rc = WITH_OPT_DESC(TWHA60_ORIG0, 9609614219eSNikolai Kondrashov twha60_fixed0); 9619614219eSNikolai Kondrashov if (rc != 0) 9629614219eSNikolai Kondrashov goto cleanup; 9639614219eSNikolai Kondrashov break; 9649614219eSNikolai Kondrashov case 1: 9659614219eSNikolai Kondrashov rc = WITH_OPT_DESC(TWHA60_ORIG1, 9669614219eSNikolai Kondrashov twha60_fixed1); 9679614219eSNikolai Kondrashov if (rc != 0) 9689614219eSNikolai Kondrashov goto cleanup; 9699614219eSNikolai Kondrashov break; 9709614219eSNikolai Kondrashov } 9719614219eSNikolai Kondrashov break; 9729614219eSNikolai Kondrashov } 973df561f66SGustavo A. R. Silva fallthrough; 9749614219eSNikolai Kondrashov case VID_PID(USB_VENDOR_ID_HUION, 9759614219eSNikolai Kondrashov USB_DEVICE_ID_HUION_TABLET): 976315ffcc9SKyle Godbey case VID_PID(USB_VENDOR_ID_HUION, 97785e86071SNikolai Kondrashov USB_DEVICE_ID_HUION_TABLET2): 9789614219eSNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UCLOGIC, 9799614219eSNikolai Kondrashov USB_DEVICE_ID_HUION_TABLET): 9809614219eSNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UCLOGIC, 9819614219eSNikolai Kondrashov USB_DEVICE_ID_YIYNOVA_TABLET): 9829614219eSNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UCLOGIC, 9839614219eSNikolai Kondrashov USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81): 9849614219eSNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UCLOGIC, 9859614219eSNikolai Kondrashov USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3): 9869614219eSNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UCLOGIC, 9879614219eSNikolai Kondrashov USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45): 9880c15efe9SNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UCLOGIC, 9890c15efe9SNikolai Kondrashov USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47): 9909614219eSNikolai Kondrashov rc = uclogic_params_huion_init(&p, hdev); 9919614219eSNikolai Kondrashov if (rc != 0) 9929614219eSNikolai Kondrashov goto cleanup; 9939614219eSNikolai Kondrashov break; 9949614219eSNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UGTIZER, 9959614219eSNikolai Kondrashov USB_DEVICE_ID_UGTIZER_TABLET_GP0610): 996022fc531SMartijn van de Streek case VID_PID(USB_VENDOR_ID_UGTIZER, 997022fc531SMartijn van de Streek USB_DEVICE_ID_UGTIZER_TABLET_GT5040): 998c3e5a67cSNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UGEE, 999c3e5a67cSNikolai Kondrashov USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540): 1000492a9e9aSNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UGEE, 1001492a9e9aSNikolai Kondrashov USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640): 100288bb346dSWang Xuerui case VID_PID(USB_VENDOR_ID_UGEE, 100388bb346dSWang Xuerui USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720): 10049614219eSNikolai Kondrashov /* If this is the pen interface */ 10059614219eSNikolai Kondrashov if (bInterfaceNumber == 1) { 1006eecb5b84SNikolai Kondrashov /* Probe v1 pen parameters */ 1007eecb5b84SNikolai Kondrashov rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev); 10089614219eSNikolai Kondrashov if (rc != 0) { 10099614219eSNikolai Kondrashov hid_err(hdev, "pen probing failed: %d\n", rc); 10109614219eSNikolai Kondrashov goto cleanup; 10119614219eSNikolai Kondrashov } 10129614219eSNikolai Kondrashov if (!found) { 10139614219eSNikolai Kondrashov hid_warn(hdev, "pen parameters not found"); 10149614219eSNikolai Kondrashov uclogic_params_init_invalid(&p); 10159614219eSNikolai Kondrashov } 10169614219eSNikolai Kondrashov } else { 1017606dadc1SNikolai Kondrashov uclogic_params_init_invalid(&p); 10189614219eSNikolai Kondrashov } 10199614219eSNikolai Kondrashov break; 10201ee7c685SNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UGEE, 102108367be1SNikolai Kondrashov USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01): 102208367be1SNikolai Kondrashov /* If this is the pen and frame interface */ 102308367be1SNikolai Kondrashov if (bInterfaceNumber == 1) { 102408367be1SNikolai Kondrashov /* Probe v1 pen parameters */ 102508367be1SNikolai Kondrashov rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev); 102608367be1SNikolai Kondrashov if (rc != 0) { 102708367be1SNikolai Kondrashov hid_err(hdev, "pen probing failed: %d\n", rc); 102808367be1SNikolai Kondrashov goto cleanup; 102908367be1SNikolai Kondrashov } 103008367be1SNikolai Kondrashov /* Initialize frame parameters */ 103108367be1SNikolai Kondrashov rc = uclogic_params_frame_init_with_desc( 1032*337fa051SNikolai Kondrashov &p.frame_list[0], 103308367be1SNikolai Kondrashov uclogic_rdesc_xppen_deco01_frame_arr, 103408367be1SNikolai Kondrashov uclogic_rdesc_xppen_deco01_frame_size, 103508367be1SNikolai Kondrashov 0); 103608367be1SNikolai Kondrashov if (rc != 0) 103708367be1SNikolai Kondrashov goto cleanup; 103808367be1SNikolai Kondrashov } else { 1039606dadc1SNikolai Kondrashov uclogic_params_init_invalid(&p); 104008367be1SNikolai Kondrashov } 104108367be1SNikolai Kondrashov break; 1042f7271b2aSCristian Klein case VID_PID(USB_VENDOR_ID_TRUST, 1043f7271b2aSCristian Klein USB_DEVICE_ID_TRUST_PANORA_TABLET): 104408367be1SNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UGEE, 1045e902ed93SNikolai Kondrashov USB_DEVICE_ID_UGEE_TABLET_G5): 1046e902ed93SNikolai Kondrashov /* Ignore non-pen interfaces */ 1047e902ed93SNikolai Kondrashov if (bInterfaceNumber != 1) { 1048e902ed93SNikolai Kondrashov uclogic_params_init_invalid(&p); 1049e902ed93SNikolai Kondrashov break; 1050e902ed93SNikolai Kondrashov } 1051e902ed93SNikolai Kondrashov 1052e902ed93SNikolai Kondrashov rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev); 1053e902ed93SNikolai Kondrashov if (rc != 0) { 1054e902ed93SNikolai Kondrashov hid_err(hdev, "pen probing failed: %d\n", rc); 1055e902ed93SNikolai Kondrashov goto cleanup; 1056e902ed93SNikolai Kondrashov } else if (found) { 1057e902ed93SNikolai Kondrashov rc = uclogic_params_frame_init_with_desc( 1058*337fa051SNikolai Kondrashov &p.frame_list[0], 1059e902ed93SNikolai Kondrashov uclogic_rdesc_ugee_g5_frame_arr, 1060e902ed93SNikolai Kondrashov uclogic_rdesc_ugee_g5_frame_size, 1061e902ed93SNikolai Kondrashov UCLOGIC_RDESC_UGEE_G5_FRAME_ID); 1062e902ed93SNikolai Kondrashov if (rc != 0) { 1063e902ed93SNikolai Kondrashov hid_err(hdev, 10642e28f3e0SNikolai Kondrashov "failed creating frame parameters: %d\n", 1065e902ed93SNikolai Kondrashov rc); 1066e902ed93SNikolai Kondrashov goto cleanup; 1067e902ed93SNikolai Kondrashov } 1068*337fa051SNikolai Kondrashov p.frame_list[0].re_lsb = 1069e902ed93SNikolai Kondrashov UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB; 1070*337fa051SNikolai Kondrashov p.frame_list[0].dev_id_byte = 1071e902ed93SNikolai Kondrashov UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE; 1072e902ed93SNikolai Kondrashov } else { 1073e902ed93SNikolai Kondrashov hid_warn(hdev, "pen parameters not found"); 1074e902ed93SNikolai Kondrashov uclogic_params_init_invalid(&p); 1075e902ed93SNikolai Kondrashov } 1076e902ed93SNikolai Kondrashov 1077e902ed93SNikolai Kondrashov break; 1078e902ed93SNikolai Kondrashov case VID_PID(USB_VENDOR_ID_UGEE, 10791ee7c685SNikolai Kondrashov USB_DEVICE_ID_UGEE_TABLET_EX07S): 10801ee7c685SNikolai Kondrashov /* Ignore non-pen interfaces */ 10811ee7c685SNikolai Kondrashov if (bInterfaceNumber != 1) { 10821ee7c685SNikolai Kondrashov uclogic_params_init_invalid(&p); 10831ee7c685SNikolai Kondrashov break; 10841ee7c685SNikolai Kondrashov } 10851ee7c685SNikolai Kondrashov 10861ee7c685SNikolai Kondrashov rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev); 10871ee7c685SNikolai Kondrashov if (rc != 0) { 10881ee7c685SNikolai Kondrashov hid_err(hdev, "pen probing failed: %d\n", rc); 10891ee7c685SNikolai Kondrashov goto cleanup; 10901ee7c685SNikolai Kondrashov } else if (found) { 10911ee7c685SNikolai Kondrashov rc = uclogic_params_frame_init_with_desc( 1092*337fa051SNikolai Kondrashov &p.frame_list[0], 10932e28f3e0SNikolai Kondrashov uclogic_rdesc_ugee_ex07_frame_arr, 10942e28f3e0SNikolai Kondrashov uclogic_rdesc_ugee_ex07_frame_size, 10951ee7c685SNikolai Kondrashov 0); 10961ee7c685SNikolai Kondrashov if (rc != 0) { 10971ee7c685SNikolai Kondrashov hid_err(hdev, 10982e28f3e0SNikolai Kondrashov "failed creating frame parameters: %d\n", 10991ee7c685SNikolai Kondrashov rc); 11001ee7c685SNikolai Kondrashov goto cleanup; 11011ee7c685SNikolai Kondrashov } 11021ee7c685SNikolai Kondrashov } else { 11031ee7c685SNikolai Kondrashov hid_warn(hdev, "pen parameters not found"); 11041ee7c685SNikolai Kondrashov uclogic_params_init_invalid(&p); 11051ee7c685SNikolai Kondrashov } 11061ee7c685SNikolai Kondrashov 11071ee7c685SNikolai Kondrashov break; 11089614219eSNikolai Kondrashov } 11099614219eSNikolai Kondrashov 11109614219eSNikolai Kondrashov #undef VID_PID 11119614219eSNikolai Kondrashov #undef WITH_OPT_DESC 11129614219eSNikolai Kondrashov 11139614219eSNikolai Kondrashov /* Output parameters */ 11149614219eSNikolai Kondrashov memcpy(params, &p, sizeof(*params)); 11159614219eSNikolai Kondrashov memset(&p, 0, sizeof(p)); 11169614219eSNikolai Kondrashov rc = 0; 11179614219eSNikolai Kondrashov cleanup: 11189614219eSNikolai Kondrashov uclogic_params_cleanup(&p); 11199614219eSNikolai Kondrashov return rc; 11209614219eSNikolai Kondrashov } 1121