summaryrefslogtreecommitdiff
path: root/include/linux/usb/gadget.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/linux/usb/gadget.h')
-rw-r--r--include/linux/usb/gadget.h286
1 files changed, 286 insertions, 0 deletions
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index abf9887322a1..8874ed16c836 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;
};
/*-------------------------------------------------------------------------*/
@@ -536,7 +627,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 {
@@ -557,10 +661,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 *);
@@ -656,6 +762,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))
@@ -797,6 +904,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
*
@@ -952,6 +1079,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
*
@@ -1010,6 +1151,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);
+}
+
/*-------------------------------------------------------------------------*/
/**
@@ -1204,6 +1468,7 @@ struct usb_descriptor_header **usb_copy_descriptors(
static inline void usb_free_descriptors(struct usb_descriptor_header **v)
{
kfree(v);
+ v = NULL;
}
struct usb_function;
@@ -1219,6 +1484,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,
@@ -1282,5 +1565,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 */