Skip to content

Commit

Permalink
USB: Make it possible to "subclass" usb_device_driver
Browse files Browse the repository at this point in the history
The kernel currenly has only 2 usb_device_drivers, one generic one, one
that completely replaces the generic one to make USB devices usable over
a network.

Use the newly exported generic driver functions when a driver declares
to want them run, in addition to its own code. This makes it possible to
write drivers that extend the generic USB driver.

Note that this patch is not enough for another driver to automatically
get selected.

Signed-off-by: Bastien Nocera <hadess@hadess.net>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Link: https://lore.kernel.org/r/20191016093933.693-3-hadess@hadess.net
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Bastien Nocera authored and Greg Kroah-Hartman committed Feb 12, 2020
1 parent ef0f7d1 commit c9d5033
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 5 deletions.
26 changes: 21 additions & 5 deletions drivers/usb/core/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,16 @@ static int usb_probe_device(struct device *dev)
*/
if (!udriver->supports_autosuspend)
error = usb_autoresume_device(udev);
if (error)
return error;

if (!error)
error = udriver->probe(udev);
if (udriver->generic_subclass)
error = usb_generic_driver_probe(udev);
if (error)
return error;

error = udriver->probe(udev);
/* TODO: fallback to generic driver in case of error */
return error;
}

Expand All @@ -273,7 +280,10 @@ static int usb_unbind_device(struct device *dev)
struct usb_device *udev = to_usb_device(dev);
struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);

udriver->disconnect(udev);
if (udriver->disconnect)
udriver->disconnect(udev);
if (udriver->generic_subclass)
usb_generic_driver_disconnect(udev);
if (!udriver->supports_autosuspend)
usb_autosuspend_device(udev);
return 0;
Expand Down Expand Up @@ -1149,7 +1159,10 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
udev->do_remote_wakeup = 0;
udriver = &usb_generic_driver;
}
status = udriver->suspend(udev, msg);
if (udriver->suspend)
status = udriver->suspend(udev, msg);
if (status == 0 && udriver->generic_subclass)
status = usb_generic_driver_suspend(udev, msg);

done:
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
Expand Down Expand Up @@ -1181,7 +1194,10 @@ static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
udev->reset_resume = 1;

udriver = to_usb_device_driver(udev->dev.driver);
status = udriver->resume(udev, msg);
if (udriver->generic_subclass)
status = usb_generic_driver_resume(udev, msg);
if (status == 0 && udriver->resume)
status = udriver->resume(udev, msg);

done:
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
Expand Down
4 changes: 4 additions & 0 deletions include/linux/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -1228,6 +1228,9 @@ struct usb_driver {
* @drvwrap: Driver-model core structure wrapper.
* @supports_autosuspend: if set to 0, the USB core will not allow autosuspend
* for devices bound to this driver.
* @generic_subclass: if set to 1, the generic USB driver's probe, disconnect,
* resume and suspend functions will be called in addition to the driver's
* own, so this part of the setup does not need to be replicated.
*
* USB drivers must provide all the fields listed above except drvwrap.
*/
Expand All @@ -1242,6 +1245,7 @@ struct usb_device_driver {
const struct attribute_group **dev_groups;
struct usbdrv_wrap drvwrap;
unsigned int supports_autosuspend:1;
unsigned int generic_subclass:1;
};
#define to_usb_device_driver(d) container_of(d, struct usb_device_driver, \
drvwrap.driver)
Expand Down

0 comments on commit c9d5033

Please sign in to comment.