Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: wacom: Support switching from vendor-defined device mode on G9 and G11

A tablet PC booted into Windows may have its pen/touch hardware switched
into "Wacom mode" similar to what we do with explicitly-supported hardware.
Some devices appear to maintain this state across reboots, preventing their
use with the generic HID driver. This patch adds support for detecting the
presence of the mode switch feature report used by devices based on the G9
and G11 chips and has the HID codepath always attempt to reset the device
back to sending standard HID reports.

Fixes: https://sourceforge.net/p/linuxwacom/bugs/307/
Fixes: https://sourceforge.net/p/linuxwacom/bugs/310/
Fixes: https://github.com/linuxwacom/input-wacom/issues/15

Co-authored-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

authored by

Jason Gerecke
Benjamin Tissoires
and committed by
Jiri Kosina
326ea2a9 c6fa1aeb

+80 -28
+72 -28
drivers/hid/wacom_sys.c
··· 152 152 hid_data->inputmode = field->report->id; 153 153 hid_data->inputmode_index = usage->usage_index; 154 154 break; 155 + 156 + case HID_UP_DIGITIZER: 157 + if (field->report->id == 0x0B && 158 + (field->application == WACOM_G9_DIGITIZER || 159 + field->application == WACOM_G11_DIGITIZER)) { 160 + wacom->wacom_wac.mode_report = field->report->id; 161 + wacom->wacom_wac.mode_value = 0; 162 + } 163 + break; 164 + 165 + case WACOM_G9_PAGE: 166 + case WACOM_G11_PAGE: 167 + if (field->report->id == 0x03 && 168 + (field->application == WACOM_G9_TOUCHSCREEN || 169 + field->application == WACOM_G11_TOUCHSCREEN)) { 170 + wacom->wacom_wac.mode_report = field->report->id; 171 + wacom->wacom_wac.mode_value = 0; 172 + } 173 + break; 155 174 } 156 175 } 157 176 ··· 341 322 return 0; 342 323 } 343 324 344 - static int wacom_set_device_mode(struct hid_device *hdev, int report_id, 345 - int length, int mode) 325 + static int wacom_set_device_mode(struct hid_device *hdev, 326 + struct wacom_wac *wacom_wac) 346 327 { 347 - unsigned char *rep_data; 328 + u8 *rep_data; 329 + struct hid_report *r; 330 + struct hid_report_enum *re; 331 + int length; 348 332 int error = -ENOMEM, limit = 0; 349 333 350 - rep_data = kzalloc(length, GFP_KERNEL); 334 + if (wacom_wac->mode_report < 0) 335 + return 0; 336 + 337 + re = &(hdev->report_enum[HID_FEATURE_REPORT]); 338 + r = re->report_id_hash[wacom_wac->mode_report]; 339 + if (!r) 340 + return -EINVAL; 341 + 342 + rep_data = hid_alloc_report_buf(r, GFP_KERNEL); 351 343 if (!rep_data) 352 - return error; 344 + return -ENOMEM; 345 + 346 + length = hid_report_len(r); 353 347 354 348 do { 355 - rep_data[0] = report_id; 356 - rep_data[1] = mode; 349 + rep_data[0] = wacom_wac->mode_report; 350 + rep_data[1] = wacom_wac->mode_value; 357 351 358 352 error = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 359 353 length, 1); 360 354 if (error >= 0) 361 355 error = wacom_get_report(hdev, HID_FEATURE_REPORT, 362 356 rep_data, length, 1); 363 - } while (error >= 0 && rep_data[1] != mode && limit++ < WAC_MSG_RETRIES); 357 + } while (error >= 0 && 358 + rep_data[1] != wacom_wac->mode_report && 359 + limit++ < WAC_MSG_RETRIES); 364 360 365 361 kfree(rep_data); 366 362 ··· 445 411 static int wacom_query_tablet_data(struct hid_device *hdev, 446 412 struct wacom_features *features) 447 413 { 414 + struct wacom *wacom = hid_get_drvdata(hdev); 415 + struct wacom_wac *wacom_wac = &wacom->wacom_wac; 416 + 448 417 if (hdev->bus == BUS_BLUETOOTH) 449 418 return wacom_bt_query_tablet_data(hdev, 1, features); 450 419 451 - if (features->type == HID_GENERIC) 452 - return wacom_hid_set_device_mode(hdev); 453 - 454 - if (features->device_type & WACOM_DEVICETYPE_TOUCH) { 455 - if (features->type > TABLETPC) { 456 - /* MT Tablet PC touch */ 457 - return wacom_set_device_mode(hdev, 3, 4, 4); 458 - } 459 - else if (features->type == WACOM_24HDT) { 460 - return wacom_set_device_mode(hdev, 18, 3, 2); 461 - } 462 - else if (features->type == WACOM_27QHDT) { 463 - return wacom_set_device_mode(hdev, 131, 3, 2); 464 - } 465 - else if (features->type == BAMBOO_PAD) { 466 - return wacom_set_device_mode(hdev, 2, 2, 2); 467 - } 468 - } else if (features->device_type & WACOM_DEVICETYPE_PEN) { 469 - if (features->type <= BAMBOO_PT) { 470 - return wacom_set_device_mode(hdev, 2, 2, 2); 420 + if (features->type != HID_GENERIC) { 421 + if (features->device_type & WACOM_DEVICETYPE_TOUCH) { 422 + if (features->type > TABLETPC) { 423 + /* MT Tablet PC touch */ 424 + wacom_wac->mode_report = 3; 425 + wacom_wac->mode_value = 4; 426 + } else if (features->type == WACOM_24HDT) { 427 + wacom_wac->mode_report = 18; 428 + wacom_wac->mode_value = 2; 429 + } else if (features->type == WACOM_27QHDT) { 430 + wacom_wac->mode_report = 131; 431 + wacom_wac->mode_value = 2; 432 + } else if (features->type == BAMBOO_PAD) { 433 + wacom_wac->mode_report = 2; 434 + wacom_wac->mode_value = 2; 435 + } 436 + } else if (features->device_type & WACOM_DEVICETYPE_PEN) { 437 + if (features->type <= BAMBOO_PT) { 438 + wacom_wac->mode_report = 2; 439 + wacom_wac->mode_value = 2; 440 + } 471 441 } 472 442 } 443 + 444 + wacom_set_device_mode(hdev, wacom_wac); 445 + 446 + if (features->type == HID_GENERIC) 447 + return wacom_hid_set_device_mode(hdev); 473 448 474 449 return 0; 475 450 } ··· 1861 1818 } 1862 1819 1863 1820 wacom_wac->hid_data.inputmode = -1; 1821 + wacom_wac->mode_report = -1; 1864 1822 1865 1823 wacom->usbdev = dev; 1866 1824 wacom->intf = intf;
+8
drivers/hid/wacom_wac.h
··· 84 84 #define WACOM_DEVICETYPE_WL_MONITOR 0x0008 85 85 86 86 #define WACOM_VENDORDEFINED_PEN 0xff0d0001 87 + #define WACOM_G9_PAGE 0xff090000 88 + #define WACOM_G9_DIGITIZER (WACOM_G9_PAGE | 0x02) 89 + #define WACOM_G9_TOUCHSCREEN (WACOM_G9_PAGE | 0x11) 90 + #define WACOM_G11_PAGE 0xff110000 91 + #define WACOM_G11_DIGITIZER (WACOM_G11_PAGE | 0x02) 92 + #define WACOM_G11_TOUCHSCREEN (WACOM_G11_PAGE | 0x11) 87 93 88 94 #define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ 89 95 ((f)->physical == HID_DG_STYLUS) || \ ··· 244 238 int ps_connected; 245 239 u8 bt_features; 246 240 u8 bt_high_speed; 241 + int mode_report; 242 + int mode_value; 247 243 struct hid_data hid_data; 248 244 }; 249 245