Commit 55c52718 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[PATCH] USB: Consider power budget when choosing configuration

This patch (as609) changes the way we keep track of power budgeting for
USB hubs and devices, and it updates the choose_configuration routine to
take this information into account.  (This is something we should have
been doing all along.)  A new field in struct usb_device holds the amount
of bus current available from the upstream port, and the usb_hub structure
keeps track of the current available for each downstream port.

Two new rules for configuration selection are added:

	Don't select a self-powered configuration when only bus power
	is available.

	Don't select a configuration requiring more bus power than is
	available.

However the first rule is #if-ed out, because I found that the internal
hub in my HP USB keyboard claims that its only configuration is
self-powered.  The rule would prevent the configuration from being chosen,
leaving the hub & keyboard unconfigured.  Since similar descriptor errors
may turn out to be fairly common, it seemed wise not to include a rule
that would break automatic configuration unnecessarily for such devices.

The second rule may also trigger unnecessarily, although this should be
less common.  More likely it will annoy people by sometimes failing to
accept configurations that should never have been chosen in the first
place.

The patch also changes usbcore's reaction when no configuration is
suitable.  Instead of raising an error and rejecting the device, now
the core will simply leave the device unconfigured.  People can always
work around such problems by installing configurations manually through
sysfs.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 949bf643
...@@ -1825,8 +1825,6 @@ int usb_add_hcd(struct usb_hcd *hcd, ...@@ -1825,8 +1825,6 @@ int usb_add_hcd(struct usb_hcd *hcd,
retval = -ENOMEM; retval = -ENOMEM;
goto err_allocate_root_hub; goto err_allocate_root_hub;
} }
rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
USB_SPEED_FULL;
/* Although in principle hcd->driver->start() might need to use rhdev, /* Although in principle hcd->driver->start() might need to use rhdev,
* none of the current drivers do. * none of the current drivers do.
...@@ -1844,6 +1842,9 @@ int usb_add_hcd(struct usb_hcd *hcd, ...@@ -1844,6 +1842,9 @@ int usb_add_hcd(struct usb_hcd *hcd,
dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
hcd->remote_wakeup = hcd->can_wakeup; hcd->remote_wakeup = hcd->can_wakeup;
rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
USB_SPEED_FULL;
rhdev->bus_mA = min(500u, hcd->power_budget);
if ((retval = register_root_hub(rhdev, hcd)) != 0) if ((retval = register_root_hub(rhdev, hcd)) != 0)
goto err_register_root_hub; goto err_register_root_hub;
......
This diff is collapsed.
...@@ -220,8 +220,9 @@ struct usb_hub { ...@@ -220,8 +220,9 @@ struct usb_hub {
struct usb_hub_descriptor *descriptor; /* class descriptor */ struct usb_hub_descriptor *descriptor; /* class descriptor */
struct usb_tt tt; /* Transaction Translator */ struct usb_tt tt; /* Transaction Translator */
u8 power_budget; /* in 2mA units; or zero */ unsigned mA_per_port; /* current for each child */
unsigned limited_power:1;
unsigned quiescing:1; unsigned quiescing:1;
unsigned activating:1; unsigned activating:1;
unsigned resume_root_hub:1; unsigned resume_root_hub:1;
......
...@@ -1387,6 +1387,12 @@ int usb_set_configuration(struct usb_device *dev, int configuration) ...@@ -1387,6 +1387,12 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
if (dev->state != USB_STATE_ADDRESS) if (dev->state != USB_STATE_ADDRESS)
usb_disable_device (dev, 1); // Skip ep0 usb_disable_device (dev, 1); // Skip ep0
n = dev->bus_mA - cp->desc.bMaxPower * 2;
if (n < 0)
dev_warn(&dev->dev, "new config #%d exceeds power "
"limit by %dmA\n",
configuration, -n);
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_CONFIGURATION, 0, configuration, 0, USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0)
......
...@@ -347,6 +347,8 @@ struct usb_device { ...@@ -347,6 +347,8 @@ struct usb_device {
char **rawdescriptors; /* Raw descriptors for each config */ char **rawdescriptors; /* Raw descriptors for each config */
unsigned short bus_mA; /* Current available from the bus */
int have_langid; /* whether string_langid is valid */ int have_langid; /* whether string_langid is valid */
int string_langid; /* language ID for strings */ int string_langid; /* language ID for strings */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment