diff options
Diffstat (limited to '0002-surface4-type-cover.patch')
-rw-r--r-- | 0002-surface4-type-cover.patch | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/0002-surface4-type-cover.patch b/0002-surface4-type-cover.patch new file mode 100644 index 000000000000..bcf8a9721661 --- /dev/null +++ b/0002-surface4-type-cover.patch @@ -0,0 +1,370 @@ +diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c +index 2b89c701076f..bd8b833f7fb4 100644 +--- a/drivers/hid/hid-core.c ++++ b/drivers/hid/hid-core.c +@@ -724,12 +724,7 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type) + hid->group = HID_GROUP_SENSOR_HUB; + + if (hid->vendor == USB_VENDOR_ID_MICROSOFT && +- (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 || +- hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 || +- hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP || +- hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP || +- hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 || +- hid->product == USB_DEVICE_ID_MS_POWER_COVER) && ++ hid->product == USB_DEVICE_ID_MS_POWER_COVER && + hid->group == HID_GROUP_MULTITOUCH) + hid->group = HID_GROUP_GENERIC; + +@@ -1980,11 +1975,6 @@ static const struct hid_device_id hid_have_special_driver[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, +- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) }, +- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2) }, +- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) }, +- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP) }, +- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1) }, +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index 575aa65436d1..3c92c7aefe33 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -718,8 +718,9 @@ + #define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 0x07dc + #define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 0x07e2 + #define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP 0x07dd ++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4 0x07e4 ++#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2 0x07e8 + #define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP 0x07e9 +-#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07de + #define USB_DEVICE_ID_MS_POWER_COVER 0x07da + + #define USB_VENDOR_ID_MOJO 0x8282 +diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c +index fb9ace1cef8b..55db58459531 100644 +--- a/drivers/hid/hid-input.c ++++ b/drivers/hid/hid-input.c +@@ -1468,6 +1468,31 @@ static void hidinput_cleanup_hidinput(struct hid_device *hid, + kfree(hidinput); + } + ++static struct hid_input *hidinput_match(struct hid_report *report) ++{ ++ struct hid_device *hid = report->device; ++ struct hid_input *hidinput; ++ ++ list_for_each_entry(hidinput, &hid->inputs, list) { ++ if (hidinput->report && ++ hidinput->report->id == report->id) ++ return hidinput; ++ } ++ ++ return NULL; ++} ++ ++static inline void hidinput_configure_usages(struct hid_input *hidinput, ++ struct hid_report *report) ++{ ++ int i, j; ++ ++ for (i = 0; i < report->maxfield; i++) ++ for (j = 0; j < report->field[i]->maxusage; j++) ++ hidinput_configure_usage(hidinput, report->field[i], ++ report->field[i]->usage + j); ++} ++ + /* + * Register the input device; print a message. + * Configure the input layer interface +@@ -1478,8 +1503,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) + { + struct hid_driver *drv = hid->driver; + struct hid_report *report; +- struct hid_input *hidinput = NULL; +- int i, j, k; ++ struct hid_input *next, *hidinput = NULL; ++ int i, k; + + INIT_LIST_HEAD(&hid->inputs); + INIT_WORK(&hid->led_work, hidinput_led_worker); +@@ -1509,43 +1534,40 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) + if (!report->maxfield) + continue; + ++ /* ++ * Find the previous hidinput report attached ++ * to this report id. ++ */ ++ if (hid->quirks & HID_QUIRK_MULTI_INPUT) ++ hidinput = hidinput_match(report); ++ + if (!hidinput) { + hidinput = hidinput_allocate(hid); + if (!hidinput) + goto out_unwind; + } + +- for (i = 0; i < report->maxfield; i++) +- for (j = 0; j < report->field[i]->maxusage; j++) +- hidinput_configure_usage(hidinput, report->field[i], +- report->field[i]->usage + j); +- +- if ((hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) && +- !hidinput_has_been_populated(hidinput)) +- continue; ++ hidinput_configure_usages(hidinput, report); + +- if (hid->quirks & HID_QUIRK_MULTI_INPUT) { +- /* This will leave hidinput NULL, so that it +- * allocates another one if we have more inputs on +- * the same interface. Some devices (e.g. Happ's +- * UGCI) cram a lot of unrelated inputs into the +- * same interface. */ ++ if (hid->quirks & HID_QUIRK_MULTI_INPUT) + hidinput->report = report; +- if (drv->input_configured && +- drv->input_configured(hid, hidinput)) +- goto out_cleanup; +- if (input_register_device(hidinput->input)) +- goto out_cleanup; +- hidinput = NULL; +- } + } + } + +- if (hidinput && (hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) && +- !hidinput_has_been_populated(hidinput)) { +- /* no need to register an input device not populated */ +- hidinput_cleanup_hidinput(hid, hidinput); +- hidinput = NULL; ++ list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { ++ if ((hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) && ++ !hidinput_has_been_populated(hidinput)) { ++ /* no need to register an input device not populated */ ++ hidinput_cleanup_hidinput(hid, hidinput); ++ continue; ++ } ++ ++ if (drv->input_configured && ++ drv->input_configured(hid, hidinput)) ++ goto out_unwind; ++ if (input_register_device(hidinput->input)) ++ goto out_unwind; ++ hidinput->registered = true; + } + + if (list_empty(&hid->inputs)) { +@@ -1553,20 +1575,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) + goto out_unwind; + } + +- if (hidinput) { +- if (drv->input_configured && +- drv->input_configured(hid, hidinput)) +- goto out_cleanup; +- if (input_register_device(hidinput->input)) +- goto out_cleanup; +- } +- + return 0; + +-out_cleanup: +- list_del(&hidinput->list); +- input_free_device(hidinput->input); +- kfree(hidinput); + out_unwind: + /* unwind the ones we already registered */ + hidinput_disconnect(hid); +@@ -1583,7 +1593,10 @@ void hidinput_disconnect(struct hid_device *hid) + + list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { + list_del(&hidinput->list); +- input_unregister_device(hidinput->input); ++ if (hidinput->registered) ++ input_unregister_device(hidinput->input); ++ else ++ input_free_device(hidinput->input); + kfree(hidinput); + } + +diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c +index c6cd392e9f99..96e7d3231d2f 100644 +--- a/drivers/hid/hid-microsoft.c ++++ b/drivers/hid/hid-microsoft.c +@@ -274,16 +274,6 @@ static const struct hid_device_id ms_devices[] = { + .driver_data = MS_NOGET }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500), + .driver_data = MS_DUPLICATE_USAGES }, +- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3), +- .driver_data = MS_HIDINPUT }, +- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2), +- .driver_data = MS_HIDINPUT }, +- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP), +- .driver_data = MS_HIDINPUT }, +- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP), +- .driver_data = MS_HIDINPUT }, +- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3), +- .driver_data = MS_HIDINPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), + .driver_data = MS_HIDINPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD), +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index fb6f1f447279..89e9032ab1e7 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -108,6 +108,7 @@ struct mt_device { + int cc_value_index; /* contact count value index in the field */ + unsigned last_slot_field; /* the last field of a slot */ + unsigned mt_report_id; /* the report ID of the multitouch device */ ++ unsigned long initial_quirks; /* initial quirks state */ + __s16 inputmode; /* InputMode HID feature, -1 if non-existent */ + __s16 inputmode_index; /* InputMode HID feature index in the report */ + __s16 maxcontact_report_id; /* Maximum Contact Number HID feature, +@@ -318,13 +319,10 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report) + u8 *buf; + + /* +- * Only fetch the feature report if initial reports are not already +- * been retrieved. Currently this is only done for Windows 8 touch +- * devices. ++ * Do not fetch the feature report if the device has been explicitly ++ * marked as non-capable. + */ +- if (!(hdev->quirks & HID_QUIRK_NO_INIT_REPORTS)) +- return; +- if (td->mtclass.name != MT_CLS_WIN_8) ++ if (td->initial_quirks & HID_QUIRK_NO_INIT_REPORTS) + return; + + buf = hid_alloc_report_buf(report, GFP_KERNEL); +@@ -842,7 +840,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + if (!td->mtclass.export_all_inputs && + field->application != HID_DG_TOUCHSCREEN && + field->application != HID_DG_PEN && +- field->application != HID_DG_TOUCHPAD) ++ field->application != HID_DG_TOUCHPAD && ++ field->application != HID_GD_KEYBOARD && ++ field->application != HID_CP_CONSUMER_CONTROL) + return -1; + + /* +@@ -1083,36 +1083,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + } + } + +- /* This allows the driver to correctly support devices +- * that emit events over several HID messages. +- */ +- hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; +- +- /* +- * This allows the driver to handle different input sensors +- * that emits events through different reports on the same HID +- * device. +- */ +- hdev->quirks |= HID_QUIRK_MULTI_INPUT; +- hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT; +- +- /* +- * Handle special quirks for Windows 8 certified devices. +- */ +- if (id->group == HID_GROUP_MULTITOUCH_WIN_8) +- /* +- * Some multitouch screens do not like to be polled for input +- * reports. Fortunately, the Win8 spec says that all touches +- * should be sent during each report, making the initialization +- * of input reports unnecessary. +- * +- * In addition some touchpads do not behave well if we read +- * all feature reports from them. Instead we prevent +- * initial report fetching and then selectively fetch each +- * report we are interested in. +- */ +- hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; +- + td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL); + if (!td) { + dev_err(&hdev->dev, "cannot allocate multitouch data\n"); +@@ -1136,6 +1106,39 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) + td->serial_maybe = true; + ++ /* ++ * Store the initial quirk state ++ */ ++ td->initial_quirks = hdev->quirks; ++ ++ /* This allows the driver to correctly support devices ++ * that emit events over several HID messages. ++ */ ++ hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; ++ ++ /* ++ * This allows the driver to handle different input sensors ++ * that emits events through different reports on the same HID ++ * device. ++ */ ++ hdev->quirks |= HID_QUIRK_MULTI_INPUT; ++ hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT; ++ ++ /* ++ * Some multitouch screens do not like to be polled for input ++ * reports. Fortunately, the Win8 spec says that all touches ++ * should be sent during each report, making the initialization ++ * of input reports unnecessary. For Win7 devices, well, let's hope ++ * they will still be happy (this is only be a problem if a touch ++ * was already there while probing the device). ++ * ++ * In addition some touchpads do not behave well if we read ++ * all feature reports from them. Instead we prevent ++ * initial report fetching and then selectively fetch each ++ * report we are interested in. ++ */ ++ hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; ++ + ret = hid_parse(hdev); + if (ret != 0) + return ret; +@@ -1204,8 +1207,11 @@ static int mt_resume(struct hid_device *hdev) + + static void mt_remove(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); ++ + sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); + hid_hw_stop(hdev); ++ hdev->quirks = td->initial_quirks; + } + + /* +diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c +index e6cfd323babc..5c8ea9ac276f 100644 +--- a/drivers/hid/usbhid/hid-quirks.c ++++ b/drivers/hid/usbhid/hid-quirks.c +@@ -98,11 +98,6 @@ static const struct hid_blacklist { + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2, HID_QUIRK_NO_INIT_REPORTS }, +- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3, HID_QUIRK_NO_INIT_REPORTS }, +- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2, HID_QUIRK_NO_INIT_REPORTS }, +- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP, HID_QUIRK_NO_INIT_REPORTS }, +- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP, HID_QUIRK_NO_INIT_REPORTS }, +- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS }, +diff --git a/include/linux/hid.h b/include/linux/hid.h +index b2ec82712baa..596b9232c19e 100644 +--- a/include/linux/hid.h ++++ b/include/linux/hid.h +@@ -479,6 +479,7 @@ struct hid_input { + struct list_head list; + struct hid_report *report; + struct input_dev *input; ++ bool registered; + }; + + enum hid_type { |