Loading drivers/usb/gadget/composite.c +119 −2 Original line number Diff line number Diff line Loading @@ -418,6 +418,114 @@ int usb_interface_id(struct usb_configuration *config, } 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 int 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\n", 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\n", func->name ? func->name : "", ret); return ret; } interface_id = ret; ret = usb_gadget_func_wakeup(gadget, interface_id); if (ret) { if (ret == -EAGAIN) { DBG(func->config->cdev, "Function wakeup for %s could not be complete. Retry is needed.\n", func->name ? func->name : ""); } else { ERROR(func->config->cdev, "Failed to wake function %s from suspend state. interface id: %d, ret=%d. Canceling USB request.\n", func->name ? func->name : "", interface_id, ret); } return ret; } return 0; } EXPORT_SYMBOL(usb_func_wakeup); 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) { if (ret != -EAGAIN) 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; } EXPORT_SYMBOL(usb_func_ep_queue); static u8 encode_bMaxPower(enum usb_device_speed speed, struct usb_configuration *c) { Loading Loading @@ -730,6 +838,10 @@ static void reset_config(struct usb_composite_dev *cdev) if (f->disable) f->disable(f); /* USB 3.0 addition */ f->func_is_suspended = false; f->func_wakeup_allowed = false; bitmap_zero(f->endpoints, 32); } cdev->config = NULL; Loading Loading @@ -1780,8 +1892,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (!f) break; value = 0; if (f->func_suspend) value = f->func_suspend(f, w_index >> 8); if (f->func_suspend) { 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) { ERROR(cdev, "func_suspend() returned error %d\n", Loading include/linux/usb/composite.h +10 −1 Original line number Diff line number Diff line Loading @@ -158,7 +158,11 @@ struct usb_os_desc_table { * @get_status: Returns function status as a reply to * GetStatus() request when the recipient is Interface. * @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 * cases support operation at both full and high speeds. Each function is Loading Loading @@ -229,6 +233,8 @@ struct usb_function { int (*get_status)(struct usb_function *); int (*func_suspend)(struct usb_function *, u8 suspend_opt); unsigned func_is_suspended:1; unsigned func_wakeup_allowed:1; /* private: */ /* internals */ struct list_head list; Loading @@ -244,6 +250,9 @@ int usb_function_deactivate(struct usb_function *); int usb_function_activate(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, struct usb_ep *_ep); Loading include/linux/usb/gadget.h +19 −1 Original line number Diff line number Diff line Loading @@ -402,6 +402,7 @@ struct usb_udc; struct usb_gadget_ops { int (*get_frame)(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 (*vbus_session) (struct usb_gadget *, int is_active); int (*vbus_draw) (struct usb_gadget *, unsigned mA); Loading @@ -415,7 +416,6 @@ struct usb_gadget_ops { struct usb_ep *(*match_ep)(struct usb_gadget *, struct usb_endpoint_descriptor *, struct usb_ss_ep_comp_descriptor *); int (*func_wakeup)(struct usb_gadget *, int interface_id); int (*restart)(struct usb_gadget *); }; Loading Loading @@ -899,6 +899,24 @@ int usb_otg_descriptor_init(struct usb_gadget *gadget, struct usb_descriptor_header *otg_desc); /*-------------------------------------------------------------------------*/ /** * 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 */ extern int usb_gadget_map_request_by_dev(struct device *dev, Loading Loading
drivers/usb/gadget/composite.c +119 −2 Original line number Diff line number Diff line Loading @@ -418,6 +418,114 @@ int usb_interface_id(struct usb_configuration *config, } 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 int 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\n", 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\n", func->name ? func->name : "", ret); return ret; } interface_id = ret; ret = usb_gadget_func_wakeup(gadget, interface_id); if (ret) { if (ret == -EAGAIN) { DBG(func->config->cdev, "Function wakeup for %s could not be complete. Retry is needed.\n", func->name ? func->name : ""); } else { ERROR(func->config->cdev, "Failed to wake function %s from suspend state. interface id: %d, ret=%d. Canceling USB request.\n", func->name ? func->name : "", interface_id, ret); } return ret; } return 0; } EXPORT_SYMBOL(usb_func_wakeup); 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) { if (ret != -EAGAIN) 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; } EXPORT_SYMBOL(usb_func_ep_queue); static u8 encode_bMaxPower(enum usb_device_speed speed, struct usb_configuration *c) { Loading Loading @@ -730,6 +838,10 @@ static void reset_config(struct usb_composite_dev *cdev) if (f->disable) f->disable(f); /* USB 3.0 addition */ f->func_is_suspended = false; f->func_wakeup_allowed = false; bitmap_zero(f->endpoints, 32); } cdev->config = NULL; Loading Loading @@ -1780,8 +1892,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (!f) break; value = 0; if (f->func_suspend) value = f->func_suspend(f, w_index >> 8); if (f->func_suspend) { 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) { ERROR(cdev, "func_suspend() returned error %d\n", Loading
include/linux/usb/composite.h +10 −1 Original line number Diff line number Diff line Loading @@ -158,7 +158,11 @@ struct usb_os_desc_table { * @get_status: Returns function status as a reply to * GetStatus() request when the recipient is Interface. * @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 * cases support operation at both full and high speeds. Each function is Loading Loading @@ -229,6 +233,8 @@ struct usb_function { int (*get_status)(struct usb_function *); int (*func_suspend)(struct usb_function *, u8 suspend_opt); unsigned func_is_suspended:1; unsigned func_wakeup_allowed:1; /* private: */ /* internals */ struct list_head list; Loading @@ -244,6 +250,9 @@ int usb_function_deactivate(struct usb_function *); int usb_function_activate(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, struct usb_ep *_ep); Loading
include/linux/usb/gadget.h +19 −1 Original line number Diff line number Diff line Loading @@ -402,6 +402,7 @@ struct usb_udc; struct usb_gadget_ops { int (*get_frame)(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 (*vbus_session) (struct usb_gadget *, int is_active); int (*vbus_draw) (struct usb_gadget *, unsigned mA); Loading @@ -415,7 +416,6 @@ struct usb_gadget_ops { struct usb_ep *(*match_ep)(struct usb_gadget *, struct usb_endpoint_descriptor *, struct usb_ss_ep_comp_descriptor *); int (*func_wakeup)(struct usb_gadget *, int interface_id); int (*restart)(struct usb_gadget *); }; Loading Loading @@ -899,6 +899,24 @@ int usb_otg_descriptor_init(struct usb_gadget *gadget, struct usb_descriptor_header *otg_desc); /*-------------------------------------------------------------------------*/ /** * 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 */ extern int usb_gadget_map_request_by_dev(struct device *dev, Loading