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