Skip to content

Commit 88b7381

Browse files
hadessgregkh
authored andcommitted
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 <[email protected]> Acked-by: Alan Stern <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent aeebf2b commit 88b7381

File tree

3 files changed

+44
-2
lines changed

3 files changed

+44
-2
lines changed

drivers/usb/core/driver.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -818,13 +818,24 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
818818
{
819819
/* devices and interfaces are handled separately */
820820
if (is_usb_device(dev)) {
821+
struct usb_device *udev;
822+
struct usb_device_driver *udrv;
821823

822824
/* interface drivers never match devices */
823825
if (!is_usb_device_driver(drv))
824826
return 0;
825827

826-
/* TODO: Add real matching code */
827-
return 1;
828+
udev = to_usb_device(dev);
829+
udrv = to_usb_device_driver(drv);
830+
831+
if (udrv->id_table &&
832+
usb_device_match_id(udev, udrv->id_table) != NULL) {
833+
return 1;
834+
}
835+
836+
if (udrv->match)
837+
return udrv->match(udev);
838+
return 0;
828839

829840
} else if (is_usb_interface(dev)) {
830841
struct usb_interface *intf;

drivers/usb/core/generic.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,34 @@ int usb_choose_configuration(struct usb_device *udev)
195195
}
196196
EXPORT_SYMBOL_GPL(usb_choose_configuration);
197197

198+
static int __check_usb_generic(struct device_driver *drv, void *data)
199+
{
200+
struct usb_device *udev = data;
201+
struct usb_device_driver *udrv;
202+
203+
if (!is_usb_device_driver(drv))
204+
return 0;
205+
udrv = to_usb_device_driver(drv);
206+
if (udrv == &usb_generic_driver)
207+
return 0;
208+
if (!udrv->id_table)
209+
return 0;
210+
211+
return usb_device_match_id(udev, udrv->id_table) != NULL;
212+
}
213+
214+
static bool usb_generic_driver_match(struct usb_device *udev)
215+
{
216+
/*
217+
* If any other driver wants the device, leave the device to this other
218+
* driver.
219+
*/
220+
if (bus_for_each_drv(&usb_bus_type, NULL, udev, __check_usb_generic))
221+
return false;
222+
223+
return true;
224+
}
225+
198226
int usb_generic_driver_probe(struct usb_device *udev)
199227
{
200228
int err, c;
@@ -285,6 +313,7 @@ int usb_generic_driver_resume(struct usb_device *udev, pm_message_t msg)
285313

286314
struct usb_device_driver usb_generic_driver = {
287315
.name = "usb",
316+
.match = usb_generic_driver_match,
288317
.probe = usb_generic_driver_probe,
289318
.disconnect = usb_generic_driver_disconnect,
290319
#ifdef CONFIG_PM

include/linux/usb.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,13 +1237,15 @@ struct usb_driver {
12371237
struct usb_device_driver {
12381238
const char *name;
12391239

1240+
bool (*match) (struct usb_device *udev);
12401241
int (*probe) (struct usb_device *udev);
12411242
void (*disconnect) (struct usb_device *udev);
12421243

12431244
int (*suspend) (struct usb_device *udev, pm_message_t message);
12441245
int (*resume) (struct usb_device *udev, pm_message_t message);
12451246
const struct attribute_group **dev_groups;
12461247
struct usbdrv_wrap drvwrap;
1248+
const struct usb_device_id *id_table;
12471249
unsigned int supports_autosuspend:1;
12481250
unsigned int generic_subclass:1;
12491251
};

0 commit comments

Comments
 (0)