aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>2018-05-31 07:49:29 -0400
committerJiri Kosina <jkosina@suse.cz>2018-06-25 09:29:16 -0400
commit8f732850df1b2b4d8d719f7e606dfb3050e7ea11 (patch)
tree6404276bcb01659e9933242c89a9ba7672edcb66
parentd471b6b22d37bf9928c6d0202bdaaf76583b8b61 (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.c5
-rw-r--r--include/linux/hid.h3
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
515struct hid_input { 516struct 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 */