diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2012-12-18 09:25:46 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-01-11 19:16:01 -0500 |
commit | 8d8479db3dde3ef7a9bc803e565842764fa21a53 (patch) | |
tree | 6c4e2b049c675b62be0fd3d65ae606f367dfb56c | |
parent | ece1d77ed73b335319725f1d5ffa72ca3fa9b05c (diff) |
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>
-rw-r--r-- | drivers/usb/core/devices.c | 13 | ||||
-rw-r--r-- | drivers/usb/core/generic.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/message.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/sysfs.c | 31 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 9 |
6 files changed, 44 insertions, 15 deletions
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index cbacea933b18..e33224e23770 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c | |||
@@ -316,17 +316,23 @@ static char *usb_dump_iad_descriptor(char *start, char *end, | |||
316 | */ | 316 | */ |
317 | static char *usb_dump_config_descriptor(char *start, char *end, | 317 | static char *usb_dump_config_descriptor(char *start, char *end, |
318 | const struct usb_config_descriptor *desc, | 318 | const struct usb_config_descriptor *desc, |
319 | int active) | 319 | int active, int speed) |
320 | { | 320 | { |
321 | int mul; | ||
322 | |||
321 | if (start > end) | 323 | if (start > end) |
322 | return start; | 324 | return start; |
325 | if (speed == USB_SPEED_SUPER) | ||
326 | mul = 8; | ||
327 | else | ||
328 | mul = 2; | ||
323 | start += sprintf(start, format_config, | 329 | start += sprintf(start, format_config, |
324 | /* mark active/actual/current cfg. */ | 330 | /* mark active/actual/current cfg. */ |
325 | active ? '*' : ' ', | 331 | active ? '*' : ' ', |
326 | desc->bNumInterfaces, | 332 | desc->bNumInterfaces, |
327 | desc->bConfigurationValue, | 333 | desc->bConfigurationValue, |
328 | desc->bmAttributes, | 334 | desc->bmAttributes, |
329 | desc->bMaxPower * 2); | 335 | desc->bMaxPower * mul); |
330 | return start; | 336 | return start; |
331 | } | 337 | } |
332 | 338 | ||
@@ -342,7 +348,8 @@ static char *usb_dump_config(int speed, char *start, char *end, | |||
342 | if (!config) | 348 | if (!config) |
343 | /* getting these some in 2.3.7; none in 2.3.6 */ | 349 | /* getting these some in 2.3.7; none in 2.3.6 */ |
344 | return start + sprintf(start, "(null Cfg. desc.)\n"); | 350 | return start + sprintf(start, "(null Cfg. desc.)\n"); |
345 | start = usb_dump_config_descriptor(start, end, &config->desc, active); | 351 | start = usb_dump_config_descriptor(start, end, &config->desc, active, |
352 | speed); | ||
346 | for (i = 0; i < USB_MAXIADS; i++) { | 353 | for (i = 0; i < USB_MAXIADS; i++) { |
347 | if (config->intf_assoc[i] == NULL) | 354 | if (config->intf_assoc[i] == NULL) |
348 | break; | 355 | break; |
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index eff2010eb63f..271e761f563e 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c | |||
@@ -100,7 +100,7 @@ int usb_choose_configuration(struct usb_device *udev) | |||
100 | */ | 100 | */ |
101 | 101 | ||
102 | /* Rule out configs that draw too much bus current */ | 102 | /* Rule out configs that draw too much bus current */ |
103 | if (c->desc.bMaxPower * 2 > udev->bus_mA) { | 103 | if (usb_get_max_power(udev, c) > udev->bus_mA) { |
104 | insufficient_power++; | 104 | insufficient_power++; |
105 | continue; | 105 | continue; |
106 | } | 106 | } |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index ae10862fb041..12913306840a 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -4211,7 +4211,7 @@ hub_power_remaining (struct usb_hub *hub) | |||
4211 | /* Unconfigured devices may not use more than 100mA, | 4211 | /* Unconfigured devices may not use more than 100mA, |
4212 | * or 8mA for OTG ports */ | 4212 | * or 8mA for OTG ports */ |
4213 | if (udev->actconfig) | 4213 | if (udev->actconfig) |
4214 | delta = udev->actconfig->desc.bMaxPower * 2; | 4214 | delta = usb_get_max_power(udev, udev->actconfig); |
4215 | else if (port1 != udev->bus->otg_port || hdev->parent) | 4215 | else if (port1 != udev->bus->otg_port || hdev->parent) |
4216 | delta = 100; | 4216 | delta = 100; |
4217 | else | 4217 | else |
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 131f73649b60..444d30e3a78b 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c | |||
@@ -1751,7 +1751,7 @@ free_interfaces: | |||
1751 | } | 1751 | } |
1752 | } | 1752 | } |
1753 | 1753 | ||
1754 | i = dev->bus_mA - cp->desc.bMaxPower * 2; | 1754 | i = dev->bus_mA - usb_get_max_power(dev, cp); |
1755 | if (i < 0) | 1755 | if (i < 0) |
1756 | dev_warn(&dev->dev, "new config #%d exceeds power " | 1756 | dev_warn(&dev->dev, "new config #%d exceeds power " |
1757 | "limit by %dmA\n", | 1757 | "limit by %dmA\n", |
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 818e4a024d0d..3f81a3dc6867 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c | |||
@@ -17,7 +17,7 @@ | |||
17 | #include "usb.h" | 17 | #include "usb.h" |
18 | 18 | ||
19 | /* Active configuration fields */ | 19 | /* Active configuration fields */ |
20 | #define usb_actconfig_show(field, multiplier, format_string) \ | 20 | #define usb_actconfig_show(field, format_string) \ |
21 | static ssize_t show_##field(struct device *dev, \ | 21 | static ssize_t show_##field(struct device *dev, \ |
22 | struct device_attribute *attr, char *buf) \ | 22 | struct device_attribute *attr, char *buf) \ |
23 | { \ | 23 | { \ |
@@ -28,18 +28,31 @@ static ssize_t show_##field(struct device *dev, \ | |||
28 | actconfig = udev->actconfig; \ | 28 | actconfig = udev->actconfig; \ |
29 | if (actconfig) \ | 29 | if (actconfig) \ |
30 | return sprintf(buf, format_string, \ | 30 | return sprintf(buf, format_string, \ |
31 | actconfig->desc.field * multiplier); \ | 31 | actconfig->desc.field); \ |
32 | else \ | 32 | else \ |
33 | return 0; \ | 33 | return 0; \ |
34 | } \ | 34 | } \ |
35 | 35 | ||
36 | #define usb_actconfig_attr(field, multiplier, format_string) \ | 36 | #define usb_actconfig_attr(field, format_string) \ |
37 | usb_actconfig_show(field, multiplier, format_string) \ | 37 | usb_actconfig_show(field, format_string) \ |
38 | static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); | 38 | static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); |
39 | |||
40 | usb_actconfig_attr(bNumInterfaces, "%2d\n") | ||
41 | usb_actconfig_attr(bmAttributes, "%2x\n") | ||
39 | 42 | ||
40 | usb_actconfig_attr(bNumInterfaces, 1, "%2d\n") | 43 | static ssize_t show_bMaxPower(struct device *dev, |
41 | usb_actconfig_attr(bmAttributes, 1, "%2x\n") | 44 | struct device_attribute *attr, char *buf) |
42 | usb_actconfig_attr(bMaxPower, 2, "%3dmA\n") | 45 | { |
46 | struct usb_device *udev; | ||
47 | struct usb_host_config *actconfig; | ||
48 | |||
49 | udev = to_usb_device(dev); | ||
50 | actconfig = udev->actconfig; | ||
51 | if (!actconfig) | ||
52 | return 0; | ||
53 | return sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig)); | ||
54 | } | ||
55 | static DEVICE_ATTR(bMaxPower, S_IRUGO, show_bMaxPower, NULL); | ||
43 | 56 | ||
44 | static ssize_t show_configuration_string(struct device *dev, | 57 | static ssize_t show_configuration_string(struct device *dev, |
45 | struct device_attribute *attr, char *buf) | 58 | struct device_attribute *attr, char *buf) |
@@ -56,7 +69,7 @@ static ssize_t show_configuration_string(struct device *dev, | |||
56 | static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); | 69 | static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); |
57 | 70 | ||
58 | /* configuration value is always present, and r/w */ | 71 | /* configuration value is always present, and r/w */ |
59 | usb_actconfig_show(bConfigurationValue, 1, "%u\n"); | 72 | usb_actconfig_show(bConfigurationValue, "%u\n"); |
60 | 73 | ||
61 | static ssize_t | 74 | static ssize_t |
62 | set_bConfigurationValue(struct device *dev, struct device_attribute *attr, | 75 | set_bConfigurationValue(struct device *dev, struct device_attribute *attr, |
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 1c528c1bf0be..fb7d8fcb4551 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h | |||
@@ -38,6 +38,15 @@ extern char *usb_cache_string(struct usb_device *udev, int index); | |||
38 | extern int usb_set_configuration(struct usb_device *dev, int configuration); | 38 | extern int usb_set_configuration(struct usb_device *dev, int configuration); |
39 | extern int usb_choose_configuration(struct usb_device *udev); | 39 | extern int usb_choose_configuration(struct usb_device *udev); |
40 | 40 | ||
41 | static inline unsigned usb_get_max_power(struct usb_device *udev, | ||
42 | struct usb_host_config *c) | ||
43 | { | ||
44 | /* SuperSpeed power is in 8 mA units; others are in 2 mA units */ | ||
45 | unsigned mul = (udev->speed == USB_SPEED_SUPER ? 8 : 2); | ||
46 | |||
47 | return c->desc.bMaxPower * mul; | ||
48 | } | ||
49 | |||
41 | extern void usb_kick_khubd(struct usb_device *dev); | 50 | extern void usb_kick_khubd(struct usb_device *dev); |
42 | extern int usb_match_one_id_intf(struct usb_device *dev, | 51 | extern int usb_match_one_id_intf(struct usb_device *dev, |
43 | struct usb_host_interface *intf, | 52 | struct usb_host_interface *intf, |