1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * HID driver for UC-Logic devices not fully compliant with HID standard 4 * 5 * Copyright (c) 2010-2014 Nikolai Kondrashov 6 * Copyright (c) 2013 Martin Rusko 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 <linux/device.h> 17 #include <linux/hid.h> 18 #include <linux/module.h> 19 #include <linux/usb.h> 20 #include "usbhid/usbhid.h" 21 #include "hid-uclogic-rdesc.h" 22 23 #include "hid-ids.h" 24 25 /* Parameter indices */ 26 enum uclogic_prm { 27 UCLOGIC_PRM_X_LM = 1, 28 UCLOGIC_PRM_Y_LM = 2, 29 UCLOGIC_PRM_PRESSURE_LM = 4, 30 UCLOGIC_PRM_RESOLUTION = 5, 31 UCLOGIC_PRM_NUM 32 }; 33 34 /* Driver data */ 35 struct uclogic_drvdata { 36 __u8 *rdesc; 37 unsigned int rsize; 38 bool invert_pen_inrange; 39 bool ignore_pen_usage; 40 bool has_virtual_pad_interface; 41 }; 42 43 static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc, 44 unsigned int *rsize) 45 { 46 struct usb_interface *iface = to_usb_interface(hdev->dev.parent); 47 __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber; 48 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); 49 50 if (drvdata->rdesc != NULL) { 51 rdesc = drvdata->rdesc; 52 *rsize = drvdata->rsize; 53 return rdesc; 54 } 55 56 switch (hdev->product) { 57 case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209: 58 if (*rsize == UCLOGIC_RDESC_PF1209_ORIG_SIZE) { 59 rdesc = uclogic_rdesc_pf1209_fixed_arr; 60 *rsize = uclogic_rdesc_pf1209_fixed_size; 61 } 62 break; 63 case USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U: 64 if (*rsize == UCLOGIC_RDESC_WPXXXXU_ORIG_SIZE) { 65 rdesc = uclogic_rdesc_wp4030u_fixed_arr; 66 *rsize = uclogic_rdesc_wp4030u_fixed_size; 67 } 68 break; 69 case USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U: 70 if (*rsize == UCLOGIC_RDESC_WPXXXXU_ORIG_SIZE) { 71 rdesc = uclogic_rdesc_wp5540u_fixed_arr; 72 *rsize = uclogic_rdesc_wp5540u_fixed_size; 73 } 74 break; 75 case USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U: 76 if (*rsize == UCLOGIC_RDESC_WPXXXXU_ORIG_SIZE) { 77 rdesc = uclogic_rdesc_wp8060u_fixed_arr; 78 *rsize = uclogic_rdesc_wp8060u_fixed_size; 79 } 80 break; 81 case USB_DEVICE_ID_UCLOGIC_TABLET_WP1062: 82 if (*rsize == UCLOGIC_RDESC_WP1062_ORIG_SIZE) { 83 rdesc = uclogic_rdesc_wp1062_fixed_arr; 84 *rsize = uclogic_rdesc_wp1062_fixed_size; 85 } 86 break; 87 case USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850: 88 switch (iface_num) { 89 case 0: 90 if (*rsize == UCLOGIC_RDESC_TWHL850_ORIG0_SIZE) { 91 rdesc = uclogic_rdesc_twhl850_fixed0_arr; 92 *rsize = uclogic_rdesc_twhl850_fixed0_size; 93 } 94 break; 95 case 1: 96 if (*rsize == UCLOGIC_RDESC_TWHL850_ORIG1_SIZE) { 97 rdesc = uclogic_rdesc_twhl850_fixed1_arr; 98 *rsize = uclogic_rdesc_twhl850_fixed1_size; 99 } 100 break; 101 case 2: 102 if (*rsize == UCLOGIC_RDESC_TWHL850_ORIG2_SIZE) { 103 rdesc = uclogic_rdesc_twhl850_fixed2_arr; 104 *rsize = uclogic_rdesc_twhl850_fixed2_size; 105 } 106 break; 107 } 108 break; 109 case USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60: 110 switch (iface_num) { 111 case 0: 112 if (*rsize == UCLOGIC_RDESC_TWHA60_ORIG0_SIZE) { 113 rdesc = uclogic_rdesc_twha60_fixed0_arr; 114 *rsize = uclogic_rdesc_twha60_fixed0_size; 115 } 116 break; 117 case 1: 118 if (*rsize == UCLOGIC_RDESC_TWHA60_ORIG1_SIZE) { 119 rdesc = uclogic_rdesc_twha60_fixed1_arr; 120 *rsize = uclogic_rdesc_twha60_fixed1_size; 121 } 122 break; 123 } 124 break; 125 } 126 127 return rdesc; 128 } 129 130 static int uclogic_input_mapping(struct hid_device *hdev, struct hid_input *hi, 131 struct hid_field *field, struct hid_usage *usage, 132 unsigned long **bit, int *max) 133 { 134 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); 135 136 /* discard the unused pen interface */ 137 if ((drvdata->ignore_pen_usage) && 138 (field->application == HID_DG_PEN)) 139 return -1; 140 141 /* let hid-core decide what to do */ 142 return 0; 143 } 144 145 static int uclogic_input_configured(struct hid_device *hdev, 146 struct hid_input *hi) 147 { 148 char *name; 149 const char *suffix = NULL; 150 struct hid_field *field; 151 size_t len; 152 153 /* no report associated (HID_QUIRK_MULTI_INPUT not set) */ 154 if (!hi->report) 155 return 0; 156 157 field = hi->report->field[0]; 158 159 switch (field->application) { 160 case HID_GD_KEYBOARD: 161 suffix = "Keyboard"; 162 break; 163 case HID_GD_MOUSE: 164 suffix = "Mouse"; 165 break; 166 case HID_GD_KEYPAD: 167 suffix = "Pad"; 168 break; 169 case HID_DG_PEN: 170 suffix = "Pen"; 171 break; 172 case HID_CP_CONSUMER_CONTROL: 173 suffix = "Consumer Control"; 174 break; 175 case HID_GD_SYSTEM_CONTROL: 176 suffix = "System Control"; 177 break; 178 } 179 180 if (suffix) { 181 len = strlen(hdev->name) + 2 + strlen(suffix); 182 name = devm_kzalloc(&hi->input->dev, len, GFP_KERNEL); 183 if (name) { 184 snprintf(name, len, "%s %s", hdev->name, suffix); 185 hi->input->name = name; 186 } 187 } 188 189 return 0; 190 } 191 192 /** 193 * Enable fully-functional tablet mode and determine device parameters. 194 * 195 * @hdev: HID device 196 */ 197 static int uclogic_tablet_enable(struct hid_device *hdev) 198 { 199 int rc; 200 struct usb_device *usb_dev = hid_to_usb_dev(hdev); 201 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); 202 __le16 *buf = NULL; 203 size_t len; 204 s32 params[UCLOGIC_RDESC_PEN_PH_ID_NUM]; 205 s32 resolution; 206 207 /* 208 * Read string descriptor containing tablet parameters. The specific 209 * string descriptor and data were discovered by sniffing the Windows 210 * driver traffic. 211 * NOTE: This enables fully-functional tablet mode. 212 */ 213 len = UCLOGIC_PRM_NUM * sizeof(*buf); 214 buf = kmalloc(len, GFP_KERNEL); 215 if (buf == NULL) { 216 rc = -ENOMEM; 217 goto cleanup; 218 } 219 rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 220 USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, 221 (USB_DT_STRING << 8) + 0x64, 222 0x0409, buf, len, 223 USB_CTRL_GET_TIMEOUT); 224 if (rc == -EPIPE) { 225 hid_err(hdev, "device parameters not found\n"); 226 rc = -ENODEV; 227 goto cleanup; 228 } else if (rc < 0) { 229 hid_err(hdev, "failed to get device parameters: %d\n", rc); 230 rc = -ENODEV; 231 goto cleanup; 232 } else if (rc != len) { 233 hid_err(hdev, "invalid device parameters\n"); 234 rc = -ENODEV; 235 goto cleanup; 236 } 237 238 /* Extract device parameters */ 239 params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 240 le16_to_cpu(buf[UCLOGIC_PRM_X_LM]); 241 params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 242 le16_to_cpu(buf[UCLOGIC_PRM_Y_LM]); 243 params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 244 le16_to_cpu(buf[UCLOGIC_PRM_PRESSURE_LM]); 245 resolution = le16_to_cpu(buf[UCLOGIC_PRM_RESOLUTION]); 246 if (resolution == 0) { 247 params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0; 248 params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0; 249 } else { 250 params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 251 params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 252 1000 / resolution; 253 params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 254 params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 255 1000 / resolution; 256 } 257 258 /* Format fixed report descriptor */ 259 drvdata->rdesc = uclogic_rdesc_template_apply( 260 uclogic_rdesc_pen_template_arr, 261 uclogic_rdesc_pen_template_size, 262 params, ARRAY_SIZE(params)); 263 if (drvdata->rdesc == NULL) { 264 rc = -ENOMEM; 265 goto cleanup; 266 } 267 drvdata->rsize = uclogic_rdesc_pen_template_size; 268 269 rc = 0; 270 271 cleanup: 272 kfree(buf); 273 return rc; 274 } 275 276 /** 277 * Enable actual button mode. 278 * 279 * @hdev: HID device 280 */ 281 static int uclogic_button_enable(struct hid_device *hdev) 282 { 283 int rc; 284 struct usb_device *usb_dev = hid_to_usb_dev(hdev); 285 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); 286 char *str_buf; 287 size_t str_len = 16; 288 unsigned char *rdesc; 289 size_t rdesc_len; 290 291 str_buf = kzalloc(str_len, GFP_KERNEL); 292 if (str_buf == NULL) { 293 rc = -ENOMEM; 294 goto cleanup; 295 } 296 297 /* Enable abstract keyboard mode */ 298 rc = usb_string(usb_dev, 0x7b, str_buf, str_len); 299 if (rc == -EPIPE) { 300 hid_info(hdev, "button mode setting not found\n"); 301 rc = 0; 302 goto cleanup; 303 } else if (rc < 0) { 304 hid_err(hdev, "failed to enable abstract keyboard\n"); 305 goto cleanup; 306 } else if (strncmp(str_buf, "HK On", rc)) { 307 hid_info(hdev, "invalid answer when requesting buttons: '%s'\n", 308 str_buf); 309 rc = -EINVAL; 310 goto cleanup; 311 } 312 313 /* Re-allocate fixed report descriptor */ 314 rdesc_len = drvdata->rsize + uclogic_rdesc_buttonpad_size; 315 rdesc = devm_kzalloc(&hdev->dev, rdesc_len, GFP_KERNEL); 316 if (!rdesc) { 317 rc = -ENOMEM; 318 goto cleanup; 319 } 320 321 memcpy(rdesc, drvdata->rdesc, drvdata->rsize); 322 323 /* Append the buttonpad descriptor */ 324 memcpy(rdesc + drvdata->rsize, uclogic_rdesc_buttonpad_arr, 325 uclogic_rdesc_buttonpad_size); 326 327 /* clean up old rdesc and use the new one */ 328 drvdata->rsize = rdesc_len; 329 devm_kfree(&hdev->dev, drvdata->rdesc); 330 drvdata->rdesc = rdesc; 331 332 rc = 0; 333 334 cleanup: 335 kfree(str_buf); 336 return rc; 337 } 338 339 static int uclogic_probe(struct hid_device *hdev, 340 const struct hid_device_id *id) 341 { 342 int rc; 343 struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 344 struct usb_device *udev = hid_to_usb_dev(hdev); 345 struct uclogic_drvdata *drvdata; 346 347 /* 348 * libinput requires the pad interface to be on a different node 349 * than the pen, so use QUIRK_MULTI_INPUT for all tablets. 350 */ 351 hdev->quirks |= HID_QUIRK_MULTI_INPUT; 352 353 /* Allocate and assign driver data */ 354 drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL); 355 if (drvdata == NULL) 356 return -ENOMEM; 357 358 hid_set_drvdata(hdev, drvdata); 359 360 switch (id->product) { 361 case USB_DEVICE_ID_HUION_TABLET: 362 case USB_DEVICE_ID_YIYNOVA_TABLET: 363 case USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81: 364 case USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3: 365 case USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45: 366 /* If this is the pen interface */ 367 if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { 368 rc = uclogic_tablet_enable(hdev); 369 if (rc) { 370 hid_err(hdev, "tablet enabling failed\n"); 371 return rc; 372 } 373 drvdata->invert_pen_inrange = true; 374 375 rc = uclogic_button_enable(hdev); 376 drvdata->has_virtual_pad_interface = !rc; 377 } else { 378 drvdata->ignore_pen_usage = true; 379 } 380 break; 381 case USB_DEVICE_ID_UGTIZER_TABLET_GP0610: 382 case USB_DEVICE_ID_UGEE_TABLET_EX07S: 383 /* If this is the pen interface */ 384 if (intf->cur_altsetting->desc.bInterfaceNumber == 1) { 385 rc = uclogic_tablet_enable(hdev); 386 if (rc) { 387 hid_err(hdev, "tablet enabling failed\n"); 388 return rc; 389 } 390 drvdata->invert_pen_inrange = true; 391 } else { 392 drvdata->ignore_pen_usage = true; 393 } 394 break; 395 case USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60: 396 /* 397 * If it is the three-interface version, which is known to 398 * respond to initialization. 399 */ 400 if (udev->config->desc.bNumInterfaces == 3) { 401 /* If it is the pen interface */ 402 if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { 403 rc = uclogic_tablet_enable(hdev); 404 if (rc) { 405 hid_err(hdev, "tablet enabling failed\n"); 406 return rc; 407 } 408 drvdata->invert_pen_inrange = true; 409 410 rc = uclogic_button_enable(hdev); 411 drvdata->has_virtual_pad_interface = !rc; 412 } else { 413 drvdata->ignore_pen_usage = true; 414 } 415 } 416 break; 417 } 418 419 rc = hid_parse(hdev); 420 if (rc) { 421 hid_err(hdev, "parse failed\n"); 422 return rc; 423 } 424 425 rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 426 if (rc) { 427 hid_err(hdev, "hw start failed\n"); 428 return rc; 429 } 430 431 return 0; 432 } 433 434 static int uclogic_raw_event(struct hid_device *hdev, struct hid_report *report, 435 u8 *data, int size) 436 { 437 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); 438 439 if ((report->type == HID_INPUT_REPORT) && 440 (report->id == UCLOGIC_RDESC_PEN_ID) && 441 (size >= 2)) { 442 if (drvdata->has_virtual_pad_interface && (data[1] & 0x20)) 443 /* Change to virtual frame button report ID */ 444 data[0] = 0xf7; 445 else if (drvdata->invert_pen_inrange) 446 /* Invert the in-range bit */ 447 data[1] ^= 0x40; 448 } 449 450 return 0; 451 } 452 453 static const struct hid_device_id uclogic_devices[] = { 454 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, 455 USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) }, 456 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, 457 USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) }, 458 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, 459 USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) }, 460 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, 461 USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) }, 462 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, 463 USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) }, 464 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, 465 USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) }, 466 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, 467 USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) }, 468 { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) }, 469 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_HUION_TABLET) }, 470 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_YIYNOVA_TABLET) }, 471 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81) }, 472 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45) }, 473 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3) }, 474 { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_GP0610) }, 475 { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_TABLET_EX07S) }, 476 { } 477 }; 478 MODULE_DEVICE_TABLE(hid, uclogic_devices); 479 480 static struct hid_driver uclogic_driver = { 481 .name = "uclogic", 482 .id_table = uclogic_devices, 483 .probe = uclogic_probe, 484 .report_fixup = uclogic_report_fixup, 485 .raw_event = uclogic_raw_event, 486 .input_mapping = uclogic_input_mapping, 487 .input_configured = uclogic_input_configured, 488 }; 489 module_hid_driver(uclogic_driver); 490 491 MODULE_AUTHOR("Martin Rusko"); 492 MODULE_AUTHOR("Nikolai Kondrashov"); 493 MODULE_LICENSE("GPL"); 494