diff options
Diffstat (limited to 'include/linux/usb/gadget.h')
-rw-r--r-- | include/linux/usb/gadget.h | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 7e84aac39ade..0e61b1f65359 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -24,9 +24,82 @@ #include <linux/types.h> #include <linux/workqueue.h> #include <linux/usb/ch9.h> +#include <linux/pm_runtime.h> struct usb_ep; +enum ep_type { + EP_TYPE_NORMAL = 0, + EP_TYPE_GSI, +}; + +/* Operations codes for GSI enabled EPs */ +enum gsi_ep_op { + GSI_EP_OP_CONFIG = 0, + GSI_EP_OP_STARTXFER, + GSI_EP_OP_STORE_DBL_INFO, + GSI_EP_OP_ENABLE_GSI, + GSI_EP_OP_UPDATEXFER, + GSI_EP_OP_RING_IN_DB, + GSI_EP_OP_ENDXFER, + GSI_EP_OP_GET_CH_INFO, + GSI_EP_OP_GET_XFER_IDX, + GSI_EP_OP_PREPARE_TRBS, + GSI_EP_OP_FREE_TRBS, + GSI_EP_OP_SET_CLR_BLOCK_DBL, + GSI_EP_OP_CHECK_FOR_SUSPEND, + GSI_EP_OP_DISABLE, +}; + +/* + * @buf_base_addr: Base pointer to buffer allocated for each GSI enabled EP. + * TRBs point to buffers that are split from this pool. The size of the + * buffer is num_bufs times buf_len. num_bufs and buf_len are determined + based on desired performance and aggregation size. + * @dma: DMA address corresponding to buf_base_addr. + * @num_bufs: Number of buffers associated with the GSI enabled EP. This + * corresponds to the number of non-zlp TRBs allocated for the EP. + * The value is determined based on desired performance for the EP. + * @buf_len: Size of each individual buffer is determined based on aggregation + * negotiated as per the protocol. In case of no aggregation supported by + * the protocol, we use default values. + */ +struct usb_gsi_request { + void *buf_base_addr; + dma_addr_t dma; + size_t num_bufs; + size_t buf_len; +}; + +/* + * @last_trb_addr: Address (LSB - based on alignment restrictions) of + * last TRB in queue. Used to identify rollover case. + * @const_buffer_size: TRB buffer size in KB (similar to IPA aggregation + * configuration). Must be aligned to Max USB Packet Size. + * Should be 1 <= const_buffer_size <= 31. + * @depcmd_low_addr: Used by GSI hardware to write "Update Transfer" cmd + * @depcmd_hi_addr: Used to write "Update Transfer" command. + * @gevntcount_low_addr: GEVNCOUNT low address for GSI hardware to read and + * clear processed events. + * @gevntcount_hi_addr: GEVNCOUNT high address. + * @xfer_ring_len: length of transfer ring in bytes (must be integral + * multiple of TRB size - 16B for xDCI). + * @xfer_ring_base_addr: physical base address of transfer ring. Address must + * be aligned to xfer_ring_len rounded to power of two. + * @ch_req: Used to pass request specific info for certain operations on GSI EP + */ +struct gsi_channel_info { + u16 last_trb_addr; + u8 const_buffer_size; + u32 depcmd_low_addr; + u8 depcmd_hi_addr; + u32 gevntcount_low_addr; + u8 gevntcount_hi_addr; + u16 xfer_ring_len; + u64 xfer_ring_base_addr; + struct usb_gsi_request *ch_req; +}; + /** * struct usb_request - describes one i/o request * @buf: Buffer used for data. Always provide this; some controllers @@ -46,6 +119,11 @@ struct usb_ep; * by adding a zero length packet as needed; * @short_not_ok: When reading data, makes short packets be * treated as errors (queue stops advancing till cleanup). + * @dma_pre_mapped: Tells the USB core driver whether this request should be + * DMA-mapped before it is queued to the USB HW. When set to true, it means + * that the request has already been mapped in advance and therefore the + * USB core driver does NOT need to do DMA-mapping when the request is + * queued to the USB HW. * @complete: Function called when request completes, so this request and * its buffer may be re-used. The function will always be called with * interrupts disabled, and it must not sleep. @@ -69,6 +147,7 @@ struct usb_ep; * Note that for writes (IN transfers) some data bytes may still * reside in a device-side FIFO when the request is reported as * complete. + * @udc_priv: Vendor private data in usage by the UDC. * * These are allocated/freed through the endpoint they're used with. The * hardware's driver can add extra per-request data to the memory it returns, @@ -101,6 +180,7 @@ struct usb_request { unsigned no_interrupt:1; unsigned zero:1; unsigned short_not_ok:1; + unsigned dma_pre_mapped:1; void (*complete)(struct usb_ep *ep, struct usb_request *req); @@ -109,6 +189,7 @@ struct usb_request { int status; unsigned actual; + unsigned udc_priv; }; /*-------------------------------------------------------------------------*/ @@ -138,6 +219,8 @@ struct usb_ep_ops { int (*fifo_status) (struct usb_ep *ep); void (*fifo_flush) (struct usb_ep *ep); + int (*gsi_ep_op)(struct usb_ep *ep, void *op_data, + enum gsi_ep_op op); }; /** @@ -201,6 +284,10 @@ struct usb_ep_caps { * enabled and remains valid until the endpoint is disabled. * @comp_desc: In case of SuperSpeed support, this is the endpoint companion * descriptor that is used to configure the endpoint + * @ep_type: Used to specify type of EP eg. normal vs h/w accelerated. + * @ep_intr_num: Interrupter number for EP. + * @endless: In case where endless transfer is being initiated, this is set + * to disable usb event interrupt for few events. * * the bus controller driver lists all the general purpose endpoints in * gadget->ep_list. the control endpoint (gadget->ep0) is not in that list, @@ -224,6 +311,10 @@ struct usb_ep { u8 address; const struct usb_endpoint_descriptor *desc; const struct usb_ss_ep_comp_descriptor *comp_desc; + enum ep_type ep_type; + u8 ep_num; + u8 ep_intr_num; + bool endless; }; /*-------------------------------------------------------------------------*/ @@ -526,7 +617,20 @@ static inline void usb_ep_fifo_flush(struct usb_ep *ep) ep->ops->fifo_flush(ep); } +/** + * usb_gsi_ep_op - performs operation on GSI accelerated EP based on EP op code + * + * Operations such as EP configuration, TRB allocation, StartXfer etc. + * See gsi_ep_op for more details. + */ +static inline int usb_gsi_ep_op(struct usb_ep *ep, + struct usb_gsi_request *req, enum gsi_ep_op op) +{ + if (ep->ops->gsi_ep_op) + return ep->ops->gsi_ep_op(ep, req, op); + return -EOPNOTSUPP; +} /*-------------------------------------------------------------------------*/ struct usb_dcd_config_params { @@ -547,10 +651,12 @@ 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); int (*pullup) (struct usb_gadget *, int is_on); + int (*restart)(struct usb_gadget *); int (*ioctl)(struct usb_gadget *, unsigned code, unsigned long param); void (*get_config_params)(struct usb_dcd_config_params *); @@ -646,6 +752,7 @@ struct usb_gadget { unsigned is_selfpowered:1; unsigned deactivated:1; unsigned connected:1; + bool remote_wakeup; }; #define work_to_gadget(w) (container_of((w), struct usb_gadget, work)) @@ -785,6 +892,26 @@ static inline int usb_gadget_wakeup(struct usb_gadget *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. * @gadget:the device being declared as self-powered * @@ -940,6 +1067,20 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget) } /** + * usb_gadget_restart - software-controlled reset of USB peripheral connection + * @gadget:the peripheral being reset + * + * Informs controller driver for Vbus LOW followed by Vbus HIGH notification. + * This performs full hardware reset and re-initialization. + */ +static inline int usb_gadget_restart(struct usb_gadget *gadget) +{ + if (!gadget->ops->restart) + return -EOPNOTSUPP; + return gadget->ops->restart(gadget); +} + +/** * usb_gadget_deactivate - deactivate function which is not ready to work * @gadget: the peripheral being deactivated * @@ -998,6 +1139,129 @@ static inline int usb_gadget_activate(struct usb_gadget *gadget) return 0; } +/** + * usb_gadget_autopm_get - increment PM-usage counter of usb gadget's parent + * device. + * @gadget: usb gadget whose parent device counter is incremented + * + * This routine should be called by function driver when it wants to use + * gadget's parent device and needs to guarantee that it is not suspended. In + * addition, the routine prevents subsequent autosuspends of gadget's parent + * device. However if the autoresume fails then the counter is re-decremented. + * + * This routine can run only in process context. + */ +static inline int usb_gadget_autopm_get(struct usb_gadget *gadget) +{ + int status = -ENODEV; + + if (!gadget || !gadget->dev.parent) + return status; + + status = pm_runtime_get_sync(gadget->dev.parent); + if (status < 0) + pm_runtime_put_sync(gadget->dev.parent); + + if (status > 0) + status = 0; + return status; +} + +/** + * usb_gadget_autopm_get_async - increment PM-usage counter of usb gadget's + * parent device. + * @gadget: usb gadget whose parent device counter is incremented + * + * This routine increments @gadget parent device PM usage counter and queue an + * autoresume request if the device is suspended. It does not autoresume device + * directly (it only queues a request). After a successful call, the device may + * not yet be resumed. + * + * This routine can run in atomic context. + */ +static inline int usb_gadget_autopm_get_async(struct usb_gadget *gadget) +{ + int status = -ENODEV; + + if (!gadget || !gadget->dev.parent) + return status; + + status = pm_runtime_get(gadget->dev.parent); + if (status < 0 && status != -EINPROGRESS) + pm_runtime_put_noidle(gadget->dev.parent); + + if (status > 0 || status == -EINPROGRESS) + status = 0; + return status; +} + +/** + * usb_gadget_autopm_get_noresume - increment PM-usage counter of usb gadget's + * parent device. + * @gadget: usb gadget whose parent device counter is incremented + * + * This routine increments PM-usage count of @gadget parent device but does not + * carry out an autoresume. + * + * This routine can run in atomic context. + */ +static inline void usb_gadget_autopm_get_noresume(struct usb_gadget *gadget) +{ + if (gadget && gadget->dev.parent) + pm_runtime_get_noresume(gadget->dev.parent); +} + +/** + * usb_gadget_autopm_put - decrement PM-usage counter of usb gadget's parent + * device. + * @gadget: usb gadget whose parent device counter is decremented. + * + * This routine should be called by function driver when it is finished using + * @gadget parent device and wants to allow it to autosuspend. It decrements + * PM-usage counter of @gadget parent device, when the counter reaches 0, a + * delayed autosuspend request is attempted. + * + * This routine can run only in process context. + */ +static inline void usb_gadget_autopm_put(struct usb_gadget *gadget) +{ + if (gadget && gadget->dev.parent) + pm_runtime_put_sync(gadget->dev.parent); +} + +/** + * usb_gadget_autopm_put_async - decrement PM-usage counter of usb gadget's + * parent device. + * @gadget: usb gadget whose parent device counter is decremented. + * + * This routine decrements PM-usage counter of @gadget parent device and + * schedules a delayed autosuspend request if the counter is <= 0. + * + * This routine can run in atomic context. + */ +static inline void usb_gadget_autopm_put_async(struct usb_gadget *gadget) +{ + if (gadget && gadget->dev.parent) + pm_runtime_put(gadget->dev.parent); +} + +/** + * usb_gadget_autopm_put_no_suspend - decrement PM-usage counter of usb gadget +'s + * parent device. + * @gadget: usb gadget whose parent device counter is decremented. + * + * This routine decrements PM-usage counter of @gadget parent device but does + * not carry out an autosuspend. + * + * This routine can run in atomic context. + */ +static inline void usb_gadget_autopm_put_no_suspend(struct usb_gadget *gadget) +{ + if (gadget && gadget->dev.parent) + pm_runtime_put_noidle(gadget->dev.parent); +} + /*-------------------------------------------------------------------------*/ /** @@ -1207,6 +1471,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(struct usb_gadget *gadget, @@ -1270,5 +1552,8 @@ extern struct usb_ep *usb_ep_autoconfig_ss(struct usb_gadget *, extern void usb_ep_autoconfig_release(struct usb_ep *); extern void usb_ep_autoconfig_reset(struct usb_gadget *); +extern struct usb_ep *usb_ep_autoconfig_by_name(struct usb_gadget *, + struct usb_endpoint_descriptor *, + const char *ep_name); #endif /* __LINUX_USB_GADGET_H */ |