aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Gerecke <killertofu@gmail.com>2016-04-04 14:26:52 -0400
committerJiri Kosina <jkosina@suse.cz>2016-04-05 11:20:32 -0400
commit326ea2a90500fe4add86c5fb95d914d46910e780 (patch)
tree4bdfcb4a4b6f4f249399cb006d99c9042f34503b
parentc6fa1aeba02111ed8676494ac7cd453a03efef3c (diff)
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>
-rw-r--r--drivers/hid/wacom_sys.c100
-rw-r--r--drivers/hid/wacom_wac.h8
2 files changed, 80 insertions, 28 deletions
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index b338bbf8e626..ccf1883318c3 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -152,6 +152,25 @@ static void wacom_feature_mapping(struct hid_device *hdev,
152 hid_data->inputmode = field->report->id; 152 hid_data->inputmode = field->report->id;
153 hid_data->inputmode_index = usage->usage_index; 153 hid_data->inputmode_index = usage->usage_index;
154 break; 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
@@ -322,26 +341,41 @@ static int wacom_hid_set_device_mode(struct hid_device *hdev)
322 return 0; 341 return 0;
323} 342}
324 343
325static int wacom_set_device_mode(struct hid_device *hdev, int report_id, 344static int wacom_set_device_mode(struct hid_device *hdev,
326 int length, int mode) 345 struct wacom_wac *wacom_wac)
327{ 346{
328 unsigned char *rep_data; 347 u8 *rep_data;
348 struct hid_report *r;
349 struct hid_report_enum *re;
350 int length;
329 int error = -ENOMEM, limit = 0; 351 int error = -ENOMEM, limit = 0;
330 352
331 rep_data = kzalloc(length, GFP_KERNEL); 353 if (wacom_wac->mode_report < 0)
354 return 0;
355
356 re = &(hdev->report_enum[HID_FEATURE_REPORT]);
357 r = re->report_id_hash[wacom_wac->mode_report];
358 if (!r)
359 return -EINVAL;
360
361 rep_data = hid_alloc_report_buf(r, GFP_KERNEL);
332 if (!rep_data) 362 if (!rep_data)
333 return error; 363 return -ENOMEM;
364
365 length = hid_report_len(r);
334 366
335 do { 367 do {
336 rep_data[0] = report_id; 368 rep_data[0] = wacom_wac->mode_report;
337 rep_data[1] = mode; 369 rep_data[1] = wacom_wac->mode_value;
338 370
339 error = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 371 error = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data,
340 length, 1); 372 length, 1);
341 if (error >= 0) 373 if (error >= 0)
342 error = wacom_get_report(hdev, HID_FEATURE_REPORT, 374 error = wacom_get_report(hdev, HID_FEATURE_REPORT,
343 rep_data, length, 1); 375 rep_data, length, 1);
344 } while (error >= 0 && rep_data[1] != mode && limit++ < WAC_MSG_RETRIES); 376 } while (error >= 0 &&
377 rep_data[1] != wacom_wac->mode_report &&
378 limit++ < WAC_MSG_RETRIES);
345 379
346 kfree(rep_data); 380 kfree(rep_data);
347 381
@@ -411,32 +445,41 @@ static int wacom_bt_query_tablet_data(struct hid_device *hdev, u8 speed,
411static int wacom_query_tablet_data(struct hid_device *hdev, 445static int wacom_query_tablet_data(struct hid_device *hdev,
412 struct wacom_features *features) 446 struct wacom_features *features)
413{ 447{
448 struct wacom *wacom = hid_get_drvdata(hdev);
449 struct wacom_wac *wacom_wac = &wacom->wacom_wac;
450
414 if (hdev->bus == BUS_BLUETOOTH) 451 if (hdev->bus == BUS_BLUETOOTH)
415 return wacom_bt_query_tablet_data(hdev, 1, features); 452 return wacom_bt_query_tablet_data(hdev, 1, features);
416 453
417 if (features->type == HID_GENERIC) 454 if (features->type != HID_GENERIC) {
418 return wacom_hid_set_device_mode(hdev); 455 if (features->device_type & WACOM_DEVICETYPE_TOUCH) {
419 456 if (features->type > TABLETPC) {
420 if (features->device_type & WACOM_DEVICETYPE_TOUCH) { 457 /* MT Tablet PC touch */
421 if (features->type > TABLETPC) { 458 wacom_wac->mode_report = 3;
422 /* MT Tablet PC touch */ 459 wacom_wac->mode_value = 4;
423 return wacom_set_device_mode(hdev, 3, 4, 4); 460 } else if (features->type == WACOM_24HDT) {
424 } 461 wacom_wac->mode_report = 18;
425 else if (features->type == WACOM_24HDT) { 462 wacom_wac->mode_value = 2;
426 return wacom_set_device_mode(hdev, 18, 3, 2); 463 } else if (features->type == WACOM_27QHDT) {
427 } 464 wacom_wac->mode_report = 131;
428 else if (features->type == WACOM_27QHDT) { 465 wacom_wac->mode_value = 2;
429 return wacom_set_device_mode(hdev, 131, 3, 2); 466 } else if (features->type == BAMBOO_PAD) {
430 } 467 wacom_wac->mode_report = 2;
431 else if (features->type == BAMBOO_PAD) { 468 wacom_wac->mode_value = 2;
432 return wacom_set_device_mode(hdev, 2, 2, 2); 469 }
433 } 470 } else if (features->device_type & WACOM_DEVICETYPE_PEN) {
434 } else if (features->device_type & WACOM_DEVICETYPE_PEN) { 471 if (features->type <= BAMBOO_PT) {
435 if (features->type <= BAMBOO_PT) { 472 wacom_wac->mode_report = 2;
436 return wacom_set_device_mode(hdev, 2, 2, 2); 473 wacom_wac->mode_value = 2;
474 }
437 } 475 }
438 } 476 }
439 477
478 wacom_set_device_mode(hdev, wacom_wac);
479
480 if (features->type == HID_GENERIC)
481 return wacom_hid_set_device_mode(hdev);
482
440 return 0; 483 return 0;
441} 484}
442 485
@@ -1818,6 +1861,7 @@ static int wacom_probe(struct hid_device *hdev,
1818 } 1861 }
1819 1862
1820 wacom_wac->hid_data.inputmode = -1; 1863 wacom_wac->hid_data.inputmode = -1;
1864 wacom_wac->mode_report = -1;
1821 1865
1822 wacom->usbdev = dev; 1866 wacom->usbdev = dev;
1823 wacom->intf = intf; 1867 wacom->intf = intf;
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
index 25baa7f29599..e2084d914c14 100644
--- a/drivers/hid/wacom_wac.h
+++ b/drivers/hid/wacom_wac.h
@@ -84,6 +84,12 @@
84#define WACOM_DEVICETYPE_WL_MONITOR 0x0008 84#define WACOM_DEVICETYPE_WL_MONITOR 0x0008
85 85
86#define WACOM_VENDORDEFINED_PEN 0xff0d0001 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#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ 94#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \
89 ((f)->physical == HID_DG_STYLUS) || \ 95 ((f)->physical == HID_DG_STYLUS) || \
@@ -238,6 +244,8 @@ struct wacom_wac {
238 int ps_connected; 244 int ps_connected;
239 u8 bt_features; 245 u8 bt_features;
240 u8 bt_high_speed; 246 u8 bt_high_speed;
247 int mode_report;
248 int mode_value;
241 struct hid_data hid_data; 249 struct hid_data hid_data;
242}; 250};
243 251