usb/core: consider link speed while looking at bMaxPower
The USB 2.0 specification says that bMaxPower is the maximum power consumption expressed in 2 mA units and the USB 3.0 specification says that it is expressed in 8 mA units. This patch adds a helper function usb_get_max_power() which computes the value based on config & usb_device's speed value. The the device descriptor dump computes the value on its own. Cc: Sarah Sharp <sarah.a.sharp@linux.intel.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
ece1d77ed7
commit
8d8479db3d
|
@ -316,17 +316,23 @@ static char *usb_dump_iad_descriptor(char *start, char *end,
|
||||||
*/
|
*/
|
||||||
static char *usb_dump_config_descriptor(char *start, char *end,
|
static char *usb_dump_config_descriptor(char *start, char *end,
|
||||||
const struct usb_config_descriptor *desc,
|
const struct usb_config_descriptor *desc,
|
||||||
int active)
|
int active, int speed)
|
||||||
{
|
{
|
||||||
|
int mul;
|
||||||
|
|
||||||
if (start > end)
|
if (start > end)
|
||||||
return start;
|
return start;
|
||||||
|
if (speed == USB_SPEED_SUPER)
|
||||||
|
mul = 8;
|
||||||
|
else
|
||||||
|
mul = 2;
|
||||||
start += sprintf(start, format_config,
|
start += sprintf(start, format_config,
|
||||||
/* mark active/actual/current cfg. */
|
/* mark active/actual/current cfg. */
|
||||||
active ? '*' : ' ',
|
active ? '*' : ' ',
|
||||||
desc->bNumInterfaces,
|
desc->bNumInterfaces,
|
||||||
desc->bConfigurationValue,
|
desc->bConfigurationValue,
|
||||||
desc->bmAttributes,
|
desc->bmAttributes,
|
||||||
desc->bMaxPower * 2);
|
desc->bMaxPower * mul);
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,7 +348,8 @@ static char *usb_dump_config(int speed, char *start, char *end,
|
||||||
if (!config)
|
if (!config)
|
||||||
/* getting these some in 2.3.7; none in 2.3.6 */
|
/* getting these some in 2.3.7; none in 2.3.6 */
|
||||||
return start + sprintf(start, "(null Cfg. desc.)\n");
|
return start + sprintf(start, "(null Cfg. desc.)\n");
|
||||||
start = usb_dump_config_descriptor(start, end, &config->desc, active);
|
start = usb_dump_config_descriptor(start, end, &config->desc, active,
|
||||||
|
speed);
|
||||||
for (i = 0; i < USB_MAXIADS; i++) {
|
for (i = 0; i < USB_MAXIADS; i++) {
|
||||||
if (config->intf_assoc[i] == NULL)
|
if (config->intf_assoc[i] == NULL)
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -100,7 +100,7 @@ int usb_choose_configuration(struct usb_device *udev)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Rule out configs that draw too much bus current */
|
/* Rule out configs that draw too much bus current */
|
||||||
if (c->desc.bMaxPower * 2 > udev->bus_mA) {
|
if (usb_get_max_power(udev, c) > udev->bus_mA) {
|
||||||
insufficient_power++;
|
insufficient_power++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4211,7 +4211,7 @@ hub_power_remaining (struct usb_hub *hub)
|
||||||
/* Unconfigured devices may not use more than 100mA,
|
/* Unconfigured devices may not use more than 100mA,
|
||||||
* or 8mA for OTG ports */
|
* or 8mA for OTG ports */
|
||||||
if (udev->actconfig)
|
if (udev->actconfig)
|
||||||
delta = udev->actconfig->desc.bMaxPower * 2;
|
delta = usb_get_max_power(udev, udev->actconfig);
|
||||||
else if (port1 != udev->bus->otg_port || hdev->parent)
|
else if (port1 != udev->bus->otg_port || hdev->parent)
|
||||||
delta = 100;
|
delta = 100;
|
||||||
else
|
else
|
||||||
|
|
|
@ -1751,7 +1751,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i = dev->bus_mA - cp->desc.bMaxPower * 2;
|
i = dev->bus_mA - usb_get_max_power(dev, cp);
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
dev_warn(&dev->dev, "new config #%d exceeds power "
|
dev_warn(&dev->dev, "new config #%d exceeds power "
|
||||||
"limit by %dmA\n",
|
"limit by %dmA\n",
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
|
|
||||||
/* Active configuration fields */
|
/* Active configuration fields */
|
||||||
#define usb_actconfig_show(field, multiplier, format_string) \
|
#define usb_actconfig_show(field, format_string) \
|
||||||
static ssize_t show_##field(struct device *dev, \
|
static ssize_t show_##field(struct device *dev, \
|
||||||
struct device_attribute *attr, char *buf) \
|
struct device_attribute *attr, char *buf) \
|
||||||
{ \
|
{ \
|
||||||
|
@ -28,18 +28,31 @@ static ssize_t show_##field(struct device *dev, \
|
||||||
actconfig = udev->actconfig; \
|
actconfig = udev->actconfig; \
|
||||||
if (actconfig) \
|
if (actconfig) \
|
||||||
return sprintf(buf, format_string, \
|
return sprintf(buf, format_string, \
|
||||||
actconfig->desc.field * multiplier); \
|
actconfig->desc.field); \
|
||||||
else \
|
else \
|
||||||
return 0; \
|
return 0; \
|
||||||
} \
|
} \
|
||||||
|
|
||||||
#define usb_actconfig_attr(field, multiplier, format_string) \
|
#define usb_actconfig_attr(field, format_string) \
|
||||||
usb_actconfig_show(field, multiplier, format_string) \
|
usb_actconfig_show(field, format_string) \
|
||||||
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
|
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
|
||||||
|
|
||||||
usb_actconfig_attr(bNumInterfaces, 1, "%2d\n")
|
usb_actconfig_attr(bNumInterfaces, "%2d\n")
|
||||||
usb_actconfig_attr(bmAttributes, 1, "%2x\n")
|
usb_actconfig_attr(bmAttributes, "%2x\n")
|
||||||
usb_actconfig_attr(bMaxPower, 2, "%3dmA\n")
|
|
||||||
|
static ssize_t show_bMaxPower(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct usb_device *udev;
|
||||||
|
struct usb_host_config *actconfig;
|
||||||
|
|
||||||
|
udev = to_usb_device(dev);
|
||||||
|
actconfig = udev->actconfig;
|
||||||
|
if (!actconfig)
|
||||||
|
return 0;
|
||||||
|
return sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig));
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR(bMaxPower, S_IRUGO, show_bMaxPower, NULL);
|
||||||
|
|
||||||
static ssize_t show_configuration_string(struct device *dev,
|
static ssize_t show_configuration_string(struct device *dev,
|
||||||
struct device_attribute *attr, char *buf)
|
struct device_attribute *attr, char *buf)
|
||||||
|
@ -56,7 +69,7 @@ static ssize_t show_configuration_string(struct device *dev,
|
||||||
static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
|
static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
|
||||||
|
|
||||||
/* configuration value is always present, and r/w */
|
/* configuration value is always present, and r/w */
|
||||||
usb_actconfig_show(bConfigurationValue, 1, "%u\n");
|
usb_actconfig_show(bConfigurationValue, "%u\n");
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
|
set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
|
||||||
|
|
|
@ -38,6 +38,15 @@ extern char *usb_cache_string(struct usb_device *udev, int index);
|
||||||
extern int usb_set_configuration(struct usb_device *dev, int configuration);
|
extern int usb_set_configuration(struct usb_device *dev, int configuration);
|
||||||
extern int usb_choose_configuration(struct usb_device *udev);
|
extern int usb_choose_configuration(struct usb_device *udev);
|
||||||
|
|
||||||
|
static inline unsigned usb_get_max_power(struct usb_device *udev,
|
||||||
|
struct usb_host_config *c)
|
||||||
|
{
|
||||||
|
/* SuperSpeed power is in 8 mA units; others are in 2 mA units */
|
||||||
|
unsigned mul = (udev->speed == USB_SPEED_SUPER ? 8 : 2);
|
||||||
|
|
||||||
|
return c->desc.bMaxPower * mul;
|
||||||
|
}
|
||||||
|
|
||||||
extern void usb_kick_khubd(struct usb_device *dev);
|
extern void usb_kick_khubd(struct usb_device *dev);
|
||||||
extern int usb_match_one_id_intf(struct usb_device *dev,
|
extern int usb_match_one_id_intf(struct usb_device *dev,
|
||||||
struct usb_host_interface *intf,
|
struct usb_host_interface *intf,
|
||||||
|
|
Loading…
Reference in New Issue