Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: gadget: Set self-powered based on MaxPower and bmAttributes

Currently the USB gadget will be set as bus-powered based solely
on whether its bMaxPower is greater than 100mA, but this may miss
devices that may legitimately draw less than 100mA but still want
to report as bus-powered. Similarly during suspend & resume, USB
gadget is incorrectly marked as bus/self powered without checking
the bmAttributes field. Fix these by configuring the USB gadget
as self or bus powered based on bmAttributes, and explicitly set
it as bus-powered if it draws more than 100mA.

Cc: stable <stable@kernel.org>
Fixes: 5e5caf4fa8d3 ("usb: gadget: composite: Inform controller driver of self-powered")
Signed-off-by: Prashanth K <prashanth.k@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20250217120328.2446639-1-prashanth.k@oss.qualcomm.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Prashanth K and committed by
Greg Kroah-Hartman
40e89ff5 17c2c87c

+11 -5
+11 -5
drivers/usb/gadget/composite.c
··· 1050 1050 else 1051 1051 usb_gadget_set_remote_wakeup(gadget, 0); 1052 1052 done: 1053 - if (power <= USB_SELF_POWER_VBUS_MAX_DRAW) 1054 - usb_gadget_set_selfpowered(gadget); 1055 - else 1053 + if (power > USB_SELF_POWER_VBUS_MAX_DRAW || 1054 + !(c->bmAttributes & USB_CONFIG_ATT_SELFPOWER)) 1056 1055 usb_gadget_clear_selfpowered(gadget); 1056 + else 1057 + usb_gadget_set_selfpowered(gadget); 1057 1058 1058 1059 usb_gadget_vbus_draw(gadget, power); 1059 1060 if (result >= 0 && cdev->delayed_status) ··· 2616 2615 2617 2616 cdev->suspended = 1; 2618 2617 2619 - usb_gadget_set_selfpowered(gadget); 2618 + if (cdev->config->bmAttributes & USB_CONFIG_ATT_SELFPOWER) 2619 + usb_gadget_set_selfpowered(gadget); 2620 + 2620 2621 usb_gadget_vbus_draw(gadget, 2); 2621 2622 } 2622 2623 ··· 2652 2649 else 2653 2650 maxpower = min(maxpower, 900U); 2654 2651 2655 - if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW) 2652 + if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW || 2653 + !(cdev->config->bmAttributes & USB_CONFIG_ATT_SELFPOWER)) 2656 2654 usb_gadget_clear_selfpowered(gadget); 2655 + else 2656 + usb_gadget_set_selfpowered(gadget); 2657 2657 2658 2658 usb_gadget_vbus_draw(gadget, maxpower); 2659 2659 } else {