Loading drivers/usb/gadget/composite.c +80 −2 Original line number Original line Diff line number Diff line Loading @@ -338,6 +338,75 @@ int usb_interface_id(struct usb_configuration *config, } } EXPORT_SYMBOL_GPL(usb_interface_id); EXPORT_SYMBOL_GPL(usb_interface_id); /** * usb_get_func_interface_id() - Find the interface ID of a function * @function: the function for which want to find the interface ID * Context: single threaded * * Returns the interface ID of the function or -ENODEV if this function * is not part of this configuration */ int usb_get_func_interface_id(struct usb_function *func) { int id; struct usb_configuration *config; if (!func) return -EINVAL; config = func->config; for (id = 0; id < MAX_CONFIG_INTERFACES; id++) { if (config->interface[id] == func) return id; } return -ENODEV; } int usb_func_wakeup(struct usb_function *func) { int ret; unsigned interface_id; struct usb_gadget *gadget; pr_debug("%s function wakeup\n", func->name ? func->name : ""); if (!func || !func->config || !func->config->cdev || !func->config->cdev->gadget) return -EINVAL; gadget = func->config->cdev->gadget; if ((gadget->speed != USB_SPEED_SUPER) || !func->func_wakeup_allowed) { DBG(func->config->cdev, "Function Wakeup is not possible. speed=%u, func_wakeup_allowed=%u", gadget->speed, func->func_wakeup_allowed); return -ENOTSUPP; } ret = usb_get_func_interface_id(func); if (ret < 0) { ERROR(func->config->cdev, "Function %s - Unknown interface id. Canceling USB request. ret=%d", func->name ? func->name : "", ret); return ret; } interface_id = ret; ret = usb_gadget_func_wakeup(gadget, interface_id); if (ret) { ERROR(func->config->cdev, "Failed to wake function %s from suspend state. interface id: %d, ret=%d. Canceling USB request.", func->name ? func->name : "", interface_id, ret); return ret; } return 0; } static u8 encode_bMaxPower(enum usb_device_speed speed, static u8 encode_bMaxPower(enum usb_device_speed speed, struct usb_configuration *c) struct usb_configuration *c) { { Loading Loading @@ -595,6 +664,10 @@ static void reset_config(struct usb_composite_dev *cdev) if (f->disable) if (f->disable) f->disable(f); f->disable(f); /* USB 3.0 addition */ f->func_is_suspended = false; f->func_wakeup_allowed = false; bitmap_zero(f->endpoints, 32); bitmap_zero(f->endpoints, 32); } } cdev->config = NULL; cdev->config = NULL; Loading Loading @@ -1452,8 +1525,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (!f) if (!f) break; break; value = 0; value = 0; if (f->func_suspend) if (f->func_suspend) { value = f->func_suspend(f, w_index >> 8); const u8 suspend_opt = w_index >> 8; value = f->func_suspend(f, suspend_opt); DBG(cdev, "%s function: FUNCTION_SUSPEND(%u)", f->name ? f->name : "", suspend_opt); } if (value < 0) { if (value < 0) { ERROR(cdev, ERROR(cdev, "func_suspend() returned error %d\n", "func_suspend() returned error %d\n", Loading drivers/usb/gadget/udc-core.c +31 −0 Original line number Original line Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <linux/usb/ch9.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> #include <linux/usb/gadget.h> #include <linux/usb/composite.h> /** /** * struct usb_udc - describes one usb device controller * struct usb_udc - describes one usb device controller Loading Loading @@ -437,6 +438,36 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) } } EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver); EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver); int usb_func_ep_queue(struct usb_function *func, struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) { int ret; struct usb_gadget *gadget; if (!func || !ep || !req) { pr_err("Invalid argument. func=%p, ep=%p, req=%p\n", func, ep, req); return -EINVAL; } pr_debug("Function %s queueing new data into ep %u\n", func->name ? func->name : "", ep->address); gadget = func->config->cdev->gadget; if ((gadget->speed == USB_SPEED_SUPER) && func->func_is_suspended) { ret = usb_func_wakeup(func); if (ret) { pr_err("Failed to send function wake up notification. func name:%s, ep:%u\n", func->name ? func->name : "", ep->address); return ret; } } ret = usb_ep_queue(ep, req, gfp_flags); return ret; } /* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ static ssize_t usb_udc_srp_store(struct device *dev, static ssize_t usb_udc_srp_store(struct device *dev, Loading include/linux/usb/composite.h +10 −1 Original line number Original line Diff line number Diff line Loading @@ -94,7 +94,11 @@ struct usb_configuration; * @get_status: Returns function status as a reply to * @get_status: Returns function status as a reply to * GetStatus() request when the recepient is Interface. * GetStatus() request when the recepient is Interface. * @func_suspend: callback to be called when * @func_suspend: callback to be called when * SetFeature(FUNCTION_SUSPEND) is reseived * SetFeature(FUNCTION_SUSPEND) is received * @func_is_suspended: Tells whether the function is currently in * Function Suspend state (used in Super Speed mode only). * @func_wakeup_allowed: Tells whether Function Remote Wakeup has been allowed * by the USB host (used in Super Speed mode only). * * * A single USB function uses one or more interfaces, and should in most * A single USB function uses one or more interfaces, and should in most * cases support operation at both full and high speeds. Each function is * cases support operation at both full and high speeds. Each function is Loading Loading @@ -158,6 +162,8 @@ struct usb_function { int (*get_status)(struct usb_function *); int (*get_status)(struct usb_function *); int (*func_suspend)(struct usb_function *, int (*func_suspend)(struct usb_function *, u8 suspend_opt); u8 suspend_opt); unsigned func_is_suspended:1; unsigned func_wakeup_allowed:1; /* private: */ /* private: */ /* internals */ /* internals */ struct list_head list; struct list_head list; Loading @@ -171,6 +177,9 @@ int usb_function_deactivate(struct usb_function *); int usb_function_activate(struct usb_function *); int usb_function_activate(struct usb_function *); int usb_interface_id(struct usb_configuration *, struct usb_function *); int usb_interface_id(struct usb_configuration *, struct usb_function *); int usb_func_wakeup(struct usb_function *func); int usb_get_func_interface_id(struct usb_function *func); int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f, int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f, struct usb_ep *_ep); struct usb_ep *_ep); Loading include/linux/usb/gadget.h +39 −0 Original line number Original line Diff line number Diff line Loading @@ -471,6 +471,7 @@ struct usb_gadget_driver; struct usb_gadget_ops { struct usb_gadget_ops { int (*get_frame)(struct usb_gadget *); int (*get_frame)(struct usb_gadget *); int (*wakeup)(struct usb_gadget *); int (*wakeup)(struct usb_gadget *); int (*func_wakeup)(struct usb_gadget *, int interface_id); int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered); int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered); int (*vbus_session) (struct usb_gadget *, int is_active); int (*vbus_session) (struct usb_gadget *, int is_active); int (*vbus_draw) (struct usb_gadget *, unsigned mA); int (*vbus_draw) (struct usb_gadget *, unsigned mA); Loading Loading @@ -646,6 +647,26 @@ static inline int usb_gadget_wakeup(struct usb_gadget *gadget) return gadget->ops->wakeup(gadget); return gadget->ops->wakeup(gadget); } } /** * usb_gadget_func_wakeup - send a function remote wakeup up notification * to the host connected to this gadget * @gadget: controller used to wake up the host * @interface_id: the interface which triggered the remote wakeup event * * Returns zero on success. Otherwise, negative error code is returned. */ static inline int usb_gadget_func_wakeup(struct usb_gadget *gadget, int interface_id) { if (gadget->speed != USB_SPEED_SUPER) return -EOPNOTSUPP; if (!gadget->ops->func_wakeup) return -EOPNOTSUPP; return gadget->ops->func_wakeup(gadget, interface_id); } /** /** * usb_gadget_set_selfpowered - sets the device selfpowered feature. * usb_gadget_set_selfpowered - sets the device selfpowered feature. * @gadget:the device being declared as self-powered * @gadget:the device being declared as self-powered Loading Loading @@ -988,6 +1009,24 @@ void usb_free_all_descriptors(struct usb_function *f); /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /** * usb_func_ep_queue - queues (submits) an I/O request to a function endpoint. * This function is similar to the usb_ep_queue function, but in addition it * also checks whether the function is in Super Speed USB Function Suspend * state, and if so a Function Wake notification is sent to the host * (USB 3.0 spec, section 9.2.5.2). * @func: the function which issues the USB I/O request. * @ep:the endpoint associated with the request * @req:the request being submitted * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't * pre-allocate all necessary memory with the request. * */ int usb_func_ep_queue(struct usb_function *func, struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags); /*-------------------------------------------------------------------------*/ /* utility to simplify map/unmap of usb_requests to/from DMA */ /* utility to simplify map/unmap of usb_requests to/from DMA */ extern int usb_gadget_map_request(struct usb_gadget *gadget, extern int usb_gadget_map_request(struct usb_gadget *gadget, Loading Loading
drivers/usb/gadget/composite.c +80 −2 Original line number Original line Diff line number Diff line Loading @@ -338,6 +338,75 @@ int usb_interface_id(struct usb_configuration *config, } } EXPORT_SYMBOL_GPL(usb_interface_id); EXPORT_SYMBOL_GPL(usb_interface_id); /** * usb_get_func_interface_id() - Find the interface ID of a function * @function: the function for which want to find the interface ID * Context: single threaded * * Returns the interface ID of the function or -ENODEV if this function * is not part of this configuration */ int usb_get_func_interface_id(struct usb_function *func) { int id; struct usb_configuration *config; if (!func) return -EINVAL; config = func->config; for (id = 0; id < MAX_CONFIG_INTERFACES; id++) { if (config->interface[id] == func) return id; } return -ENODEV; } int usb_func_wakeup(struct usb_function *func) { int ret; unsigned interface_id; struct usb_gadget *gadget; pr_debug("%s function wakeup\n", func->name ? func->name : ""); if (!func || !func->config || !func->config->cdev || !func->config->cdev->gadget) return -EINVAL; gadget = func->config->cdev->gadget; if ((gadget->speed != USB_SPEED_SUPER) || !func->func_wakeup_allowed) { DBG(func->config->cdev, "Function Wakeup is not possible. speed=%u, func_wakeup_allowed=%u", gadget->speed, func->func_wakeup_allowed); return -ENOTSUPP; } ret = usb_get_func_interface_id(func); if (ret < 0) { ERROR(func->config->cdev, "Function %s - Unknown interface id. Canceling USB request. ret=%d", func->name ? func->name : "", ret); return ret; } interface_id = ret; ret = usb_gadget_func_wakeup(gadget, interface_id); if (ret) { ERROR(func->config->cdev, "Failed to wake function %s from suspend state. interface id: %d, ret=%d. Canceling USB request.", func->name ? func->name : "", interface_id, ret); return ret; } return 0; } static u8 encode_bMaxPower(enum usb_device_speed speed, static u8 encode_bMaxPower(enum usb_device_speed speed, struct usb_configuration *c) struct usb_configuration *c) { { Loading Loading @@ -595,6 +664,10 @@ static void reset_config(struct usb_composite_dev *cdev) if (f->disable) if (f->disable) f->disable(f); f->disable(f); /* USB 3.0 addition */ f->func_is_suspended = false; f->func_wakeup_allowed = false; bitmap_zero(f->endpoints, 32); bitmap_zero(f->endpoints, 32); } } cdev->config = NULL; cdev->config = NULL; Loading Loading @@ -1452,8 +1525,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (!f) if (!f) break; break; value = 0; value = 0; if (f->func_suspend) if (f->func_suspend) { value = f->func_suspend(f, w_index >> 8); const u8 suspend_opt = w_index >> 8; value = f->func_suspend(f, suspend_opt); DBG(cdev, "%s function: FUNCTION_SUSPEND(%u)", f->name ? f->name : "", suspend_opt); } if (value < 0) { if (value < 0) { ERROR(cdev, ERROR(cdev, "func_suspend() returned error %d\n", "func_suspend() returned error %d\n", Loading
drivers/usb/gadget/udc-core.c +31 −0 Original line number Original line Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <linux/usb/ch9.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> #include <linux/usb/gadget.h> #include <linux/usb/composite.h> /** /** * struct usb_udc - describes one usb device controller * struct usb_udc - describes one usb device controller Loading Loading @@ -437,6 +438,36 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) } } EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver); EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver); int usb_func_ep_queue(struct usb_function *func, struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) { int ret; struct usb_gadget *gadget; if (!func || !ep || !req) { pr_err("Invalid argument. func=%p, ep=%p, req=%p\n", func, ep, req); return -EINVAL; } pr_debug("Function %s queueing new data into ep %u\n", func->name ? func->name : "", ep->address); gadget = func->config->cdev->gadget; if ((gadget->speed == USB_SPEED_SUPER) && func->func_is_suspended) { ret = usb_func_wakeup(func); if (ret) { pr_err("Failed to send function wake up notification. func name:%s, ep:%u\n", func->name ? func->name : "", ep->address); return ret; } } ret = usb_ep_queue(ep, req, gfp_flags); return ret; } /* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ static ssize_t usb_udc_srp_store(struct device *dev, static ssize_t usb_udc_srp_store(struct device *dev, Loading
include/linux/usb/composite.h +10 −1 Original line number Original line Diff line number Diff line Loading @@ -94,7 +94,11 @@ struct usb_configuration; * @get_status: Returns function status as a reply to * @get_status: Returns function status as a reply to * GetStatus() request when the recepient is Interface. * GetStatus() request when the recepient is Interface. * @func_suspend: callback to be called when * @func_suspend: callback to be called when * SetFeature(FUNCTION_SUSPEND) is reseived * SetFeature(FUNCTION_SUSPEND) is received * @func_is_suspended: Tells whether the function is currently in * Function Suspend state (used in Super Speed mode only). * @func_wakeup_allowed: Tells whether Function Remote Wakeup has been allowed * by the USB host (used in Super Speed mode only). * * * A single USB function uses one or more interfaces, and should in most * A single USB function uses one or more interfaces, and should in most * cases support operation at both full and high speeds. Each function is * cases support operation at both full and high speeds. Each function is Loading Loading @@ -158,6 +162,8 @@ struct usb_function { int (*get_status)(struct usb_function *); int (*get_status)(struct usb_function *); int (*func_suspend)(struct usb_function *, int (*func_suspend)(struct usb_function *, u8 suspend_opt); u8 suspend_opt); unsigned func_is_suspended:1; unsigned func_wakeup_allowed:1; /* private: */ /* private: */ /* internals */ /* internals */ struct list_head list; struct list_head list; Loading @@ -171,6 +177,9 @@ int usb_function_deactivate(struct usb_function *); int usb_function_activate(struct usb_function *); int usb_function_activate(struct usb_function *); int usb_interface_id(struct usb_configuration *, struct usb_function *); int usb_interface_id(struct usb_configuration *, struct usb_function *); int usb_func_wakeup(struct usb_function *func); int usb_get_func_interface_id(struct usb_function *func); int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f, int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f, struct usb_ep *_ep); struct usb_ep *_ep); Loading
include/linux/usb/gadget.h +39 −0 Original line number Original line Diff line number Diff line Loading @@ -471,6 +471,7 @@ struct usb_gadget_driver; struct usb_gadget_ops { struct usb_gadget_ops { int (*get_frame)(struct usb_gadget *); int (*get_frame)(struct usb_gadget *); int (*wakeup)(struct usb_gadget *); int (*wakeup)(struct usb_gadget *); int (*func_wakeup)(struct usb_gadget *, int interface_id); int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered); int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered); int (*vbus_session) (struct usb_gadget *, int is_active); int (*vbus_session) (struct usb_gadget *, int is_active); int (*vbus_draw) (struct usb_gadget *, unsigned mA); int (*vbus_draw) (struct usb_gadget *, unsigned mA); Loading Loading @@ -646,6 +647,26 @@ static inline int usb_gadget_wakeup(struct usb_gadget *gadget) return gadget->ops->wakeup(gadget); return gadget->ops->wakeup(gadget); } } /** * usb_gadget_func_wakeup - send a function remote wakeup up notification * to the host connected to this gadget * @gadget: controller used to wake up the host * @interface_id: the interface which triggered the remote wakeup event * * Returns zero on success. Otherwise, negative error code is returned. */ static inline int usb_gadget_func_wakeup(struct usb_gadget *gadget, int interface_id) { if (gadget->speed != USB_SPEED_SUPER) return -EOPNOTSUPP; if (!gadget->ops->func_wakeup) return -EOPNOTSUPP; return gadget->ops->func_wakeup(gadget, interface_id); } /** /** * usb_gadget_set_selfpowered - sets the device selfpowered feature. * usb_gadget_set_selfpowered - sets the device selfpowered feature. * @gadget:the device being declared as self-powered * @gadget:the device being declared as self-powered Loading Loading @@ -988,6 +1009,24 @@ void usb_free_all_descriptors(struct usb_function *f); /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /** * usb_func_ep_queue - queues (submits) an I/O request to a function endpoint. * This function is similar to the usb_ep_queue function, but in addition it * also checks whether the function is in Super Speed USB Function Suspend * state, and if so a Function Wake notification is sent to the host * (USB 3.0 spec, section 9.2.5.2). * @func: the function which issues the USB I/O request. * @ep:the endpoint associated with the request * @req:the request being submitted * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't * pre-allocate all necessary memory with the request. * */ int usb_func_ep_queue(struct usb_function *func, struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags); /*-------------------------------------------------------------------------*/ /* utility to simplify map/unmap of usb_requests to/from DMA */ /* utility to simplify map/unmap of usb_requests to/from DMA */ extern int usb_gadget_map_request(struct usb_gadget *gadget, extern int usb_gadget_map_request(struct usb_gadget *gadget, Loading