summaryrefslogtreecommitdiff
path: root/drivers/usb/core/generic.c
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2019-10-16 11:39:31 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-02-12 11:01:55 -0800
commit88b7381a939de0fa1f1b1629c56b03dca7077309 (patch)
tree74bb40156ebfcf5b169cb703c6b79821d26913ca /drivers/usb/core/generic.c
parentaeebf2b5466506546c47ca68477d4aa8a96377a6 (diff)
USB: Select better matching USB drivers when available
Now that USB device drivers can reuse code from the generic USB device driver, we need to make sure that they get selected rather than the generic driver. Add an id_table and match vfunc to the usb_device_driver struct, which will get used to select a better matching driver at ->probe time. This is a similar mechanism to that used in the HID drivers, with the generic driver being selected unless there's a better matching one found in the registered drivers (see hid_generic_match() in drivers/hid/hid-generic.c). Signed-off-by: Bastien Nocera <hadess@hadess.net> Acked-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/20191016093933.693-5-hadess@hadess.net Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/core/generic.c')
-rw-r--r--drivers/usb/core/generic.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 28ece4d77749..84da85c13825 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -195,6 +195,34 @@ int usb_choose_configuration(struct usb_device *udev)
}
EXPORT_SYMBOL_GPL(usb_choose_configuration);
+static int __check_usb_generic(struct device_driver *drv, void *data)
+{
+ struct usb_device *udev = data;
+ struct usb_device_driver *udrv;
+
+ if (!is_usb_device_driver(drv))
+ return 0;
+ udrv = to_usb_device_driver(drv);
+ if (udrv == &usb_generic_driver)
+ return 0;
+ if (!udrv->id_table)
+ return 0;
+
+ return usb_device_match_id(udev, udrv->id_table) != NULL;
+}
+
+static bool usb_generic_driver_match(struct usb_device *udev)
+{
+ /*
+ * If any other driver wants the device, leave the device to this other
+ * driver.
+ */
+ if (bus_for_each_drv(&usb_bus_type, NULL, udev, __check_usb_generic))
+ return false;
+
+ return true;
+}
+
int usb_generic_driver_probe(struct usb_device *udev)
{
int err, c;
@@ -285,6 +313,7 @@ int usb_generic_driver_resume(struct usb_device *udev, pm_message_t msg)
struct usb_device_driver usb_generic_driver = {
.name = "usb",
+ .match = usb_generic_driver_match,
.probe = usb_generic_driver_probe,
.disconnect = usb_generic_driver_disconnect,
#ifdef CONFIG_PM