Linux-USB Archive on lore.kernel.org
 help / color / Atom feed
From: Bastien Nocera <hadess@hadess.net>
To: linux-usb@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Benjamin Tissoires <benjamin.tissoires@redhat.com>,
	Bastien Nocera <hadess@hadess.net>,
	Alan Stern <stern@rowland.harvard.edu>
Subject: [PATCH v3 4/6] USB: Select better matching USB drivers when available
Date: Wed, 16 Oct 2019 11:39:31 +0200
Message-ID: <20191016093933.693-5-hadess@hadess.net> (raw)
In-Reply-To: <20191016093933.693-1-hadess@hadess.net>

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>
---
 drivers/usb/core/driver.c  | 15 +++++++++++++--
 drivers/usb/core/generic.c | 29 +++++++++++++++++++++++++++++
 include/linux/usb.h        |  2 ++
 3 files changed, 44 insertions(+), 2 deletions(-)

diff --git drivers/usb/core/driver.c drivers/usb/core/driver.c
index 697898327b44..9d1502a9571d 100644
--- drivers/usb/core/driver.c
+++ drivers/usb/core/driver.c
@@ -818,13 +818,24 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
 {
 	/* devices and interfaces are handled separately */
 	if (is_usb_device(dev)) {
+		struct usb_device *udev;
+		struct usb_device_driver *udrv;
 
 		/* interface drivers never match devices */
 		if (!is_usb_device_driver(drv))
 			return 0;
 
-		/* TODO: Add real matching code */
-		return 1;
+		udev = to_usb_device(dev);
+		udrv = to_usb_device_driver(drv);
+
+		if (udrv->id_table &&
+		    usb_device_match_id(udev, udrv->id_table) != NULL) {
+			return 1;
+		}
+
+		if (udrv->match)
+			return udrv->match(udev);
+		return 0;
 
 	} else if (is_usb_interface(dev)) {
 		struct usb_interface *intf;
diff --git drivers/usb/core/generic.c drivers/usb/core/generic.c
index 28ece4d77749..84da85c13825 100644
--- drivers/usb/core/generic.c
+++ 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
diff --git include/linux/usb.h include/linux/usb.h
index 94bd3b48a485..3663bd7b1fa4 100644
--- include/linux/usb.h
+++ include/linux/usb.h
@@ -1237,6 +1237,7 @@ struct usb_driver {
 struct usb_device_driver {
 	const char *name;
 
+	bool (*match) (struct usb_device *udev);
 	int (*probe) (struct usb_device *udev);
 	void (*disconnect) (struct usb_device *udev);
 
@@ -1244,6 +1245,7 @@ struct usb_device_driver {
 	int (*resume) (struct usb_device *udev, pm_message_t message);
 	const struct attribute_group **dev_groups;
 	struct usbdrv_wrap drvwrap;
+	const struct usb_device_id *id_table;
 	unsigned int supports_autosuspend:1;
 	unsigned int generic_subclass:1;
 };
-- 
2.21.0


  parent reply index

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-16  9:39 [PATCH v3 0/6] Add Apple MFi fastcharge USB device driver Bastien Nocera
2019-10-16  9:39 ` [PATCH v3 1/6] USB: Export generic USB device driver functions Bastien Nocera
2019-10-16  9:39 ` [PATCH v3 2/6] USB: Make it possible to "subclass" usb_device_driver Bastien Nocera
2019-10-16  9:39 ` [PATCH v3 3/6] USB: Implement usb_device_match_id() Bastien Nocera
2019-10-16  9:39 ` Bastien Nocera [this message]
2019-10-16  9:39 ` [PATCH v3 5/6] USB: Fallback to generic driver when specific driver fails Bastien Nocera
2019-10-16  9:39 ` [PATCH v3 6/6] USB: Add driver to control USB fast charge for iOS devices Bastien Nocera
2019-11-21 15:20 ` [PATCH v3 0/6] Add Apple MFi fastcharge USB device driver Bastien Nocera
2020-01-07  8:46   ` Bastien Nocera
2020-01-07  9:35     ` Greg Kroah-Hartman
2020-01-07  9:48       ` Bastien Nocera
2020-02-11  0:21       ` Bastien Nocera
2020-02-12 17:52         ` Greg Kroah-Hartman
2020-02-12 19:06 ` Greg Kroah-Hartman
2020-02-12 23:05   ` Bastien Nocera
2020-02-12 23:17     ` Greg Kroah-Hartman
2020-02-12 23:24       ` Bastien Nocera

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191016093933.693-5-hadess@hadess.net \
    --to=hadess@hadess.net \
    --cc=benjamin.tissoires@redhat.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=stern@rowland.harvard.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Linux-USB Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-usb/0 linux-usb/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-usb linux-usb/ https://lore.kernel.org/linux-usb \
		linux-usb@vger.kernel.org
	public-inbox-index linux-usb

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-usb


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git