From 8be024e136c7426772c3bd8f9a56fe4000d6d24c Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Fri, 13 May 2016 18:45:12 +0200 Subject: Patch for wacom support --- hel/wacom.patch | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 hel/wacom.patch (limited to 'hel') diff --git a/hel/wacom.patch b/hel/wacom.patch new file mode 100644 index 00000000..61500efc --- /dev/null +++ b/hel/wacom.patch @@ -0,0 +1,206 @@ +From 326ea2a90500fe4add86c5fb95d914d46910e780 Mon Sep 17 00:00:00 2001 +From: Jason Gerecke +Date: Mon, 4 Apr 2016 11:26:52 -0700 +Subject: [PATCH] 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 +Signed-off-by: Jason Gerecke +Reviewed-by: Benjamin Tissoires +Signed-off-by: Jiri Kosina +--- + drivers/hid/wacom_sys.c | 100 ++++++++++++++++++++++++++++++++++-------------- + drivers/hid/wacom_wac.h | 8 ++++ + 2 files changed, 80 insertions(+), 28 deletions(-) + +diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c +index b338bbf..ccf1883 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, + hid_data->inputmode = field->report->id; + hid_data->inputmode_index = usage->usage_index; + break; ++ ++ case HID_UP_DIGITIZER: ++ if (field->report->id == 0x0B && ++ (field->application == WACOM_G9_DIGITIZER || ++ field->application == WACOM_G11_DIGITIZER)) { ++ wacom->wacom_wac.mode_report = field->report->id; ++ wacom->wacom_wac.mode_value = 0; ++ } ++ break; ++ ++ case WACOM_G9_PAGE: ++ case WACOM_G11_PAGE: ++ if (field->report->id == 0x03 && ++ (field->application == WACOM_G9_TOUCHSCREEN || ++ field->application == WACOM_G11_TOUCHSCREEN)) { ++ wacom->wacom_wac.mode_report = field->report->id; ++ wacom->wacom_wac.mode_value = 0; ++ } ++ break; + } + } + +@@ -322,26 +341,41 @@ static int wacom_hid_set_device_mode(struct hid_device *hdev) + return 0; + } + +-static int wacom_set_device_mode(struct hid_device *hdev, int report_id, +- int length, int mode) ++static int wacom_set_device_mode(struct hid_device *hdev, ++ struct wacom_wac *wacom_wac) + { +- unsigned char *rep_data; ++ u8 *rep_data; ++ struct hid_report *r; ++ struct hid_report_enum *re; ++ int length; + int error = -ENOMEM, limit = 0; + +- rep_data = kzalloc(length, GFP_KERNEL); ++ if (wacom_wac->mode_report < 0) ++ return 0; ++ ++ re = &(hdev->report_enum[HID_FEATURE_REPORT]); ++ r = re->report_id_hash[wacom_wac->mode_report]; ++ if (!r) ++ return -EINVAL; ++ ++ rep_data = hid_alloc_report_buf(r, GFP_KERNEL); + if (!rep_data) +- return error; ++ return -ENOMEM; ++ ++ length = hid_report_len(r); + + do { +- rep_data[0] = report_id; +- rep_data[1] = mode; ++ rep_data[0] = wacom_wac->mode_report; ++ rep_data[1] = wacom_wac->mode_value; + + error = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, + length, 1); + if (error >= 0) + error = wacom_get_report(hdev, HID_FEATURE_REPORT, + rep_data, length, 1); +- } while (error >= 0 && rep_data[1] != mode && limit++ < WAC_MSG_RETRIES); ++ } while (error >= 0 && ++ rep_data[1] != wacom_wac->mode_report && ++ limit++ < WAC_MSG_RETRIES); + + kfree(rep_data); + +@@ -411,32 +445,41 @@ static int wacom_bt_query_tablet_data(struct hid_device *hdev, u8 speed, + static int wacom_query_tablet_data(struct hid_device *hdev, + struct wacom_features *features) + { ++ struct wacom *wacom = hid_get_drvdata(hdev); ++ struct wacom_wac *wacom_wac = &wacom->wacom_wac; ++ + if (hdev->bus == BUS_BLUETOOTH) + return wacom_bt_query_tablet_data(hdev, 1, features); + +- if (features->type == HID_GENERIC) +- return wacom_hid_set_device_mode(hdev); +- +- if (features->device_type & WACOM_DEVICETYPE_TOUCH) { +- if (features->type > TABLETPC) { +- /* MT Tablet PC touch */ +- return wacom_set_device_mode(hdev, 3, 4, 4); +- } +- else if (features->type == WACOM_24HDT) { +- return wacom_set_device_mode(hdev, 18, 3, 2); +- } +- else if (features->type == WACOM_27QHDT) { +- return wacom_set_device_mode(hdev, 131, 3, 2); +- } +- else if (features->type == BAMBOO_PAD) { +- return wacom_set_device_mode(hdev, 2, 2, 2); +- } +- } else if (features->device_type & WACOM_DEVICETYPE_PEN) { +- if (features->type <= BAMBOO_PT) { +- return wacom_set_device_mode(hdev, 2, 2, 2); ++ if (features->type != HID_GENERIC) { ++ if (features->device_type & WACOM_DEVICETYPE_TOUCH) { ++ if (features->type > TABLETPC) { ++ /* MT Tablet PC touch */ ++ wacom_wac->mode_report = 3; ++ wacom_wac->mode_value = 4; ++ } else if (features->type == WACOM_24HDT) { ++ wacom_wac->mode_report = 18; ++ wacom_wac->mode_value = 2; ++ } else if (features->type == WACOM_27QHDT) { ++ wacom_wac->mode_report = 131; ++ wacom_wac->mode_value = 2; ++ } else if (features->type == BAMBOO_PAD) { ++ wacom_wac->mode_report = 2; ++ wacom_wac->mode_value = 2; ++ } ++ } else if (features->device_type & WACOM_DEVICETYPE_PEN) { ++ if (features->type <= BAMBOO_PT) { ++ wacom_wac->mode_report = 2; ++ wacom_wac->mode_value = 2; ++ } + } + } + ++ wacom_set_device_mode(hdev, wacom_wac); ++ ++ if (features->type == HID_GENERIC) ++ return wacom_hid_set_device_mode(hdev); ++ + return 0; + } + +@@ -1818,6 +1861,7 @@ static int wacom_probe(struct hid_device *hdev, + } + + wacom_wac->hid_data.inputmode = -1; ++ wacom_wac->mode_report = -1; + + wacom->usbdev = dev; + wacom->intf = intf; +diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h +index 25baa7f..e2084d9 100644 +--- a/drivers/hid/wacom_wac.h ++++ b/drivers/hid/wacom_wac.h +@@ -84,6 +84,12 @@ + #define WACOM_DEVICETYPE_WL_MONITOR 0x0008 + + #define WACOM_VENDORDEFINED_PEN 0xff0d0001 ++#define WACOM_G9_PAGE 0xff090000 ++#define WACOM_G9_DIGITIZER (WACOM_G9_PAGE | 0x02) ++#define WACOM_G9_TOUCHSCREEN (WACOM_G9_PAGE | 0x11) ++#define WACOM_G11_PAGE 0xff110000 ++#define WACOM_G11_DIGITIZER (WACOM_G11_PAGE | 0x02) ++#define WACOM_G11_TOUCHSCREEN (WACOM_G11_PAGE | 0x11) + + #define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ + ((f)->physical == HID_DG_STYLUS) || \ +@@ -238,6 +244,8 @@ struct wacom_wac { + int ps_connected; + u8 bt_features; + u8 bt_high_speed; ++ int mode_report; ++ int mode_value; + struct hid_data hid_data; + }; + +-- +2.1.4 + -- cgit v1.2.3