4.17-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Tissoires benjamin.tissoires@redhat.com
commit 8f732850df1b2b4d8d719f7e606dfb3050e7ea11 upstream.
Detected on the Dell XPS 9365.
The laptop has 2 devices that benefit from the hid-generic auto-unbinding. When those 2 devices are presented to the userspace, udev loads both wacom and hid-multitouch. When this happens, the code in __hid_bus_reprobe_drivers() is called concurrently and the second device gets reprobed twice.
An other bug in the power_supply subsystem prevent to remove the wacom driver if it just finished its initialization, which basically kills the wacom node.
[jkosina@suse.cz: reformat changelog a bit] Fixes c17a7476e4c4 ("HID: core: rewrite the hid-generic automatic unbind") Cc: stable@vger.kernel.org # v4.17 Tested-by: Mario Limonciello mario.limonciello@dell.com Signed-off-by: Benjamin Tissoires benjamin.tissoires@redhat.com Signed-off-by: Jiri Kosina jkosina@suse.cz Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/hid/hid-core.c | 5 ++++- include/linux/hid.h | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-)
--- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1942,6 +1942,8 @@ static int hid_device_probe(struct devic } hdev->io_started = false;
+ clear_bit(ffs(HID_STAT_REPROBED), &hdev->status); + if (!hdev->driver) { id = hid_match_device(hdev, hdrv); if (id == NULL) { @@ -2205,7 +2207,8 @@ static int __hid_bus_reprobe_drivers(str struct hid_device *hdev = to_hid_device(dev);
if (hdev->driver == hdrv && - !hdrv->match(hdev, hid_ignore_special_drivers)) + !hdrv->match(hdev, hid_ignore_special_drivers) && + !test_and_set_bit(ffs(HID_STAT_REPROBED), &hdev->status)) return device_reprobe(dev);
return 0; --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -502,6 +502,7 @@ struct hid_output_fifo {
#define HID_STAT_ADDED BIT(0) #define HID_STAT_PARSED BIT(1) +#define HID_STAT_REPROBED BIT(3)
struct hid_input { struct list_head list; @@ -568,7 +569,7 @@ struct hid_device { /* device repo bool battery_avoid_query; #endif
- unsigned int status; /* see STAT flags above */ + unsigned long status; /* see STAT flags above */ unsigned claimed; /* Claimed by hidinput, hiddev? */ unsigned quirks; /* Various quirks the device can pull on us */ bool io_started; /* If IO has started */