>From 08df419517694c4dd9ff328f5644b46a99c2999e Mon Sep 17 00:00:00 2001 From: "Du, Changbin" <changbin.du@xxxxxxxxx> Date: Thu, 23 Jul 2015 20:08:04 +0800 Subject: [PATCH v2] usb/gadget: make composite gadget meet usb compliance for vbus draw USB-IF compliance requirement limits the vbus current according to current state. USB2 Spec requires that un-configured current must be <= 100mA, for USB3 is 150mA, OTG is 2.5mA. So set corresponding vbus draw current according to device mode. Signed-off-by: Du, Changbin <changbin.du@xxxxxxxxx> --- Resend patch since no response for 4 weeks, probably bee missed. Changes from v1: Also update configfs to use new api composite_reset. --- drivers/usb/gadget/composite.c | 39 ++++++++++++++++++++++++++++++++------- drivers/usb/gadget/configfs.c | 2 +- include/linux/usb/composite.h | 1 + include/uapi/linux/usb/ch9.h | 9 +++++++++ 4 files changed, 43 insertions(+), 8 deletions(-) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 4e3447b..b3896e9 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -610,6 +610,21 @@ static void device_qual(struct usb_composite_dev *cdev) qual->bRESERVED = 0; } +static unsigned unconfigured_vbus_draw(struct usb_composite_dev *cdev) +{ + struct usb_gadget *g = cdev->gadget; + unsigned power; + + if (gadget_is_otg(g)) + power = USB_OTG_UNCONF_STATE_VBUS_MAX_DRAW; + else if (g->speed == USB_SPEED_SUPER) + power = USB3_UNCONF_STATE_VBUS_MAX_DRAW; + else + power = USB2_UNCONF_STATE_VBUS_MAX_DRAW; + + return power; +} + /*-------------------------------------------------------------------------*/ static void reset_config(struct usb_composite_dev *cdev) @@ -634,7 +649,7 @@ static int set_config(struct usb_composite_dev *cdev, struct usb_gadget *gadget = cdev->gadget; struct usb_configuration *c = NULL; int result = -EINVAL; - unsigned power = gadget_is_otg(gadget) ? 8 : 100; + unsigned power = unconfigured_vbus_draw(cdev); int tmp; if (number) { @@ -1829,6 +1844,15 @@ done: return value; } +void composite_reset(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev = get_gadget_data(gadget); + + DBG(cdev, "reset\n"); + usb_gadget_vbus_draw(gadget, unconfigured_vbus_draw(cdev)); + composite_disconnect(gadget); +} + void composite_disconnect(struct usb_gadget *gadget) { struct usb_composite_dev *cdev = get_gadget_data(gadget); @@ -2095,7 +2119,7 @@ void composite_suspend(struct usb_gadget *gadget) cdev->suspended = 1; - usb_gadget_vbus_draw(gadget, 2); + usb_gadget_vbus_draw(gadget, USB_SUSPEND_STATE_VBUS_MAX_DRAW); } void composite_resume(struct usb_gadget *gadget) @@ -2117,10 +2141,11 @@ void composite_resume(struct usb_gadget *gadget) } maxpower = cdev->config->MaxPower; - - usb_gadget_vbus_draw(gadget, maxpower ? - maxpower : CONFIG_USB_GADGET_VBUS_DRAW); - } + if (!maxpower) + maxpower = CONFIG_USB_GADGET_VBUS_DRAW; + } else + maxpower = unconfigured_vbus_draw(cdev); + usb_gadget_vbus_draw(gadget, maxpower); cdev->suspended = 0; } @@ -2132,7 +2157,7 @@ static const struct usb_gadget_driver composite_driver_template = { .unbind = composite_unbind, .setup = composite_setup, - .reset = composite_disconnect, + .reset = composite_reset, .disconnect = composite_disconnect, .suspend = composite_suspend, diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 0495c94..e16335d 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1449,7 +1449,7 @@ static const struct usb_gadget_driver configfs_driver_template = { .unbind = configfs_composite_unbind, .setup = composite_setup, - .reset = composite_disconnect, + .reset = composite_reset, .disconnect = composite_disconnect, .suspend = composite_suspend, diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 2511469..825ad39 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -506,6 +506,7 @@ extern struct usb_string *usb_gstrings_attach(struct usb_composite_dev *cdev, extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n); +extern void composite_reset(struct usb_gadget *gadget); extern void composite_disconnect(struct usb_gadget *gadget); extern int composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl); diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h index aa33fd1..ab216bf 100644 --- a/include/uapi/linux/usb/ch9.h +++ b/include/uapi/linux/usb/ch9.h @@ -996,4 +996,13 @@ struct usb_set_sel_req { */ #define USB_SELF_POWER_VBUS_MAX_DRAW 100 +/* + * USB2 compliance requires that un-configured current draw less than 100mA, + * while USB3 requires it <= 150mA, and OTG device requires it <= 2.5mA. + */ +#define USB2_UNCONF_STATE_VBUS_MAX_DRAW 100 +#define USB3_UNCONF_STATE_VBUS_MAX_DRAW 150 +#define USB_OTG_UNCONF_STATE_VBUS_MAX_DRAW 2 +#define USB_SUSPEND_STATE_VBUS_MAX_DRAW 2 + #endif /* _UAPI__LINUX_USB_CH9_H */ -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html