diff options
author | Benjamin Tissoires <benjamin.tissoires@redhat.com> | 2018-05-31 07:49:29 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2018-06-25 09:29:16 -0400 |
commit | 8f732850df1b2b4d8d719f7e606dfb3050e7ea11 (patch) | |
tree | 6404276bcb01659e9933242c89a9ba7672edcb66 | |
parent | d471b6b22d37bf9928c6d0202bdaaf76583b8b61 (diff) |
HID: core: allow concurrent registration of drivers
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>
-rw-r--r-- | drivers/hid/hid-core.c | 5 | ||||
-rw-r--r-- | include/linux/hid.h | 3 |
2 files changed, 6 insertions, 2 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 355dc7e49562..a460ec147aee 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
@@ -1949,6 +1949,8 @@ static int hid_device_probe(struct device *dev) | |||
1949 | } | 1949 | } |
1950 | hdev->io_started = false; | 1950 | hdev->io_started = false; |
1951 | 1951 | ||
1952 | clear_bit(ffs(HID_STAT_REPROBED), &hdev->status); | ||
1953 | |||
1952 | if (!hdev->driver) { | 1954 | if (!hdev->driver) { |
1953 | id = hid_match_device(hdev, hdrv); | 1955 | id = hid_match_device(hdev, hdrv); |
1954 | if (id == NULL) { | 1956 | if (id == NULL) { |
@@ -2212,7 +2214,8 @@ static int __hid_bus_reprobe_drivers(struct device *dev, void *data) | |||
2212 | struct hid_device *hdev = to_hid_device(dev); | 2214 | struct hid_device *hdev = to_hid_device(dev); |
2213 | 2215 | ||
2214 | if (hdev->driver == hdrv && | 2216 | if (hdev->driver == hdrv && |
2215 | !hdrv->match(hdev, hid_ignore_special_drivers)) | 2217 | !hdrv->match(hdev, hid_ignore_special_drivers) && |
2218 | !test_and_set_bit(ffs(HID_STAT_REPROBED), &hdev->status)) | ||
2216 | return device_reprobe(dev); | 2219 | return device_reprobe(dev); |
2217 | 2220 | ||
2218 | return 0; | 2221 | return 0; |
diff --git a/include/linux/hid.h b/include/linux/hid.h index 41a3d5775394..773bcb1d4044 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
@@ -511,6 +511,7 @@ struct hid_output_fifo { | |||
511 | #define HID_STAT_ADDED BIT(0) | 511 | #define HID_STAT_ADDED BIT(0) |
512 | #define HID_STAT_PARSED BIT(1) | 512 | #define HID_STAT_PARSED BIT(1) |
513 | #define HID_STAT_DUP_DETECTED BIT(2) | 513 | #define HID_STAT_DUP_DETECTED BIT(2) |
514 | #define HID_STAT_REPROBED BIT(3) | ||
514 | 515 | ||
515 | struct hid_input { | 516 | struct hid_input { |
516 | struct list_head list; | 517 | struct list_head list; |
@@ -579,7 +580,7 @@ struct hid_device { /* device report descriptor */ | |||
579 | bool battery_avoid_query; | 580 | bool battery_avoid_query; |
580 | #endif | 581 | #endif |
581 | 582 | ||
582 | unsigned int status; /* see STAT flags above */ | 583 | unsigned long status; /* see STAT flags above */ |
583 | unsigned claimed; /* Claimed by hidinput, hiddev? */ | 584 | unsigned claimed; /* Claimed by hidinput, hiddev? */ |
584 | unsigned quirks; /* Various quirks the device can pull on us */ | 585 | unsigned quirks; /* Various quirks the device can pull on us */ |
585 | bool io_started; /* If IO has started */ | 586 | bool io_started; /* If IO has started */ |