/** * cdns3_ep0_run_transfer - Do transfer on default endpoint hardware * @priv_dev: extended gadget object * @dma_addr: physical address where data is/will be stored * @length: data length * @erdy: set it to 1 when ERDY packet should be sent - * exit from flow control state * @zlp: add zero length packet
*/ staticvoid cdns3_ep0_run_transfer(struct cdns3_device *priv_dev,
dma_addr_t dma_addr, unsignedint length, int erdy, int zlp)
{ struct cdns3_usb_regs __iomem *regs = priv_dev->regs; struct cdns3_endpoint *priv_ep = priv_dev->eps[0];
/* TRB should be prepared before starting transfer. */
writel(EP_CMD_DRDY, ®s->ep_cmd);
/* Resume controller before arming transfer. */
__cdns3_gadget_wakeup(priv_dev);
if (erdy)
writel(EP_CMD_ERDY, &priv_dev->regs->ep_cmd);
}
/** * cdns3_ep0_delegate_req - Returns status of handling setup packet * Setup is handled by gadget driver * @priv_dev: extended gadget object * @ctrl_req: pointer to received setup packet * * Returns zero on success or negative value on failure
*/ staticint cdns3_ep0_delegate_req(struct cdns3_device *priv_dev, struct usb_ctrlrequest *ctrl_req)
{ int ret;
/** * cdns3_req_ep0_get_status - Handling of GET_STATUS standard USB request * @priv_dev: extended gadget object * @ctrl: pointer to received setup packet * * Returns 0 if success, error code on error
*/ staticint cdns3_req_ep0_get_status(struct cdns3_device *priv_dev, struct usb_ctrlrequest *ctrl)
{ struct cdns3_endpoint *priv_ep;
__le16 *response_pkt;
u16 usb_status = 0;
u32 recip;
u8 index;
recip = ctrl->bRequestType & USB_RECIP_MASK;
switch (recip) { case USB_RECIP_DEVICE: /* self powered */ if (priv_dev->is_selfpowered)
usb_status = BIT(USB_DEVICE_SELF_POWERED);
if (priv_dev->wake_up_flag)
usb_status |= BIT(USB_DEVICE_REMOTE_WAKEUP);
if (priv_dev->gadget.speed != USB_SPEED_SUPER) break;
if (priv_dev->u1_allowed)
usb_status |= BIT(USB_DEV_STAT_U1_ENABLED);
if (priv_dev->u2_allowed)
usb_status |= BIT(USB_DEV_STAT_U2_ENABLED);
break; case USB_RECIP_INTERFACE: return cdns3_ep0_delegate_req(priv_dev, ctrl); case USB_RECIP_ENDPOINT:
index = cdns3_ep_addr_to_index(le16_to_cpu(ctrl->wIndex));
priv_ep = priv_dev->eps[index];
/* check if endpoint is stalled or stall is pending */
cdns3_select_ep(priv_dev, le16_to_cpu(ctrl->wIndex)); if (EP_STS_STALL(readl(&priv_dev->regs->ep_sts)) ||
(priv_ep->flags & EP_STALL_PENDING))
usb_status = BIT(USB_ENDPOINT_HALT); break; default: return -EINVAL;
}
if (set)
__cdns3_gadget_ep_set_halt(priv_ep); elseif (!(priv_ep->flags & EP_WEDGE))
ret = __cdns3_gadget_ep_clear_halt(priv_ep);
cdns3_select_ep(priv_dev, 0x00);
return ret;
}
/** * cdns3_req_ep0_handle_feature - * Handling of GET/SET_FEATURE standard USB request * * @priv_dev: extended gadget object * @ctrl: pointer to received setup packet * @set: must be set to 1 for SET_FEATURE request * * Returns 0 if success, error code on error
*/ staticint cdns3_req_ep0_handle_feature(struct cdns3_device *priv_dev, struct usb_ctrlrequest *ctrl, int set)
{ int ret = 0;
u32 recip;
recip = ctrl->bRequestType & USB_RECIP_MASK;
switch (recip) { case USB_RECIP_DEVICE:
ret = cdns3_ep0_feature_handle_device(priv_dev, ctrl, set); break; case USB_RECIP_INTERFACE:
ret = cdns3_ep0_feature_handle_intf(priv_dev, ctrl, set); break; case USB_RECIP_ENDPOINT:
ret = cdns3_ep0_feature_handle_endpoint(priv_dev, ctrl, set); break; default: return -EINVAL;
}
return ret;
}
/** * cdns3_req_ep0_set_sel - Handling of SET_SEL standard USB request * @priv_dev: extended gadget object * @ctrl_req: pointer to received setup packet * * Returns 0 if success, error code on error
*/ staticint cdns3_req_ep0_set_sel(struct cdns3_device *priv_dev, struct usb_ctrlrequest *ctrl_req)
{ if (priv_dev->gadget.state < USB_STATE_ADDRESS) return -EINVAL;
if (le16_to_cpu(ctrl_req->wLength) != 6) {
dev_err(priv_dev->dev, "Set SEL should be 6 bytes, got %d\n",
ctrl_req->wLength); return -EINVAL;
}
/** * cdns3_ep0_standard_request - Handling standard USB requests * @priv_dev: extended gadget object * @ctrl_req: pointer to received setup packet * * Returns 0 if success, error code on error
*/ staticint cdns3_ep0_standard_request(struct cdns3_device *priv_dev, struct usb_ctrlrequest *ctrl_req)
{ int ret;
switch (ctrl_req->bRequest) { case USB_REQ_SET_ADDRESS:
ret = cdns3_req_ep0_set_address(priv_dev, ctrl_req); break; case USB_REQ_SET_CONFIGURATION:
ret = cdns3_req_ep0_set_configuration(priv_dev, ctrl_req); break; case USB_REQ_GET_STATUS:
ret = cdns3_req_ep0_get_status(priv_dev, ctrl_req); break; case USB_REQ_CLEAR_FEATURE:
ret = cdns3_req_ep0_handle_feature(priv_dev, ctrl_req, 0); break; case USB_REQ_SET_FEATURE:
ret = cdns3_req_ep0_handle_feature(priv_dev, ctrl_req, 1); break; case USB_REQ_SET_SEL:
ret = cdns3_req_ep0_set_sel(priv_dev, ctrl_req); break; case USB_REQ_SET_ISOCH_DELAY:
ret = cdns3_req_ep0_set_isoch_delay(priv_dev, ctrl_req); break; default:
ret = cdns3_ep0_delegate_req(priv_dev, ctrl_req); break;
}
if (le16_to_cpu(ctrl->wLength))
priv_dev->ep0_stage = CDNS3_DATA_STAGE; else
priv_dev->ep0_stage = CDNS3_STATUS_STAGE;
if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
result = cdns3_ep0_standard_request(priv_dev, ctrl); else
result = cdns3_ep0_delegate_req(priv_dev, ctrl);
/** * cdns3_check_new_setup - Check if controller receive new SETUP packet. * @priv_dev: extended gadget object * * The SETUP packet can be kept in on-chip memory or in system memory.
*/ staticbool cdns3_check_new_setup(struct cdns3_device *priv_dev)
{
u32 ep_sts_reg;
/** * cdns3_check_ep0_interrupt_proceed - Processes interrupt related to endpoint 0 * @priv_dev: extended gadget object * @dir: USB_DIR_IN for IN direction, USB_DIR_OUT for OUT direction
*/ void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir)
{
u32 ep_sts_reg;
if (ep_sts_reg & EP_STS_DESCMIS) { if (dir == 0 && !priv_dev->setup_pending)
cdns3_prepare_setup_packet(priv_dev);
}
}
/** * cdns3_gadget_ep0_enable * @ep: pointer to endpoint zero object * @desc: pointer to usb endpoint descriptor * * Function shouldn't be called by gadget driver, * endpoint 0 is allways active
*/ staticint cdns3_gadget_ep0_enable(struct usb_ep *ep, conststruct usb_endpoint_descriptor *desc)
{ return -EINVAL;
}
/** * cdns3_gadget_ep0_disable * @ep: pointer to endpoint zero object * * Function shouldn't be called by gadget driver, * endpoint 0 is allways active
*/ staticint cdns3_gadget_ep0_disable(struct usb_ep *ep)
{ return -EINVAL;
}
/** * cdns3_gadget_ep0_set_halt * @ep: pointer to endpoint zero object * @value: 1 for set stall, 0 for clear stall * * Returns 0
*/ staticint cdns3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
{ /* TODO */ return 0;
}
/** * cdns3_gadget_ep0_queue - Transfer data on endpoint zero * @ep: pointer to endpoint zero object * @request: pointer to request object * @gfp_flags: gfp flags * * Returns 0 on success, error code elsewhere
*/ staticint cdns3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
gfp_t gfp_flags)
{ struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); struct cdns3_device *priv_dev = priv_ep->cdns3_dev; unsignedlong flags; int ret = 0;
u8 zlp = 0; int i;
/* cancel the request if controller receive new SETUP packet. */ if (cdns3_check_new_setup(priv_dev)) {
spin_unlock_irqrestore(&priv_dev->lock, flags); return -ECONNRESET;
}
/* send STATUS stage. Should be called only for SET_CONFIGURATION */ if (priv_dev->ep0_stage == CDNS3_STATUS_STAGE) {
u32 val;
cdns3_select_ep(priv_dev, 0x00);
/* * Configure all non-control EPs which are not enabled by class driver
*/ for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++) {
priv_ep = priv_dev->eps[i]; if (priv_ep && priv_ep->flags & EP_CLAIMED &&
!(priv_ep->flags & EP_ENABLED))
cdns3_ep_config(priv_ep, 0);
}
cdns3_set_hw_configuration(priv_dev);
cdns3_ep0_complete_setup(priv_dev, 0, 1); /* wait until configuration set */
ret = readl_poll_timeout_atomic(&priv_dev->regs->usb_sts, val,
val & USB_STS_CFGSTS_MASK, 1, 100); if (ret == -ETIMEDOUT)
dev_warn(priv_dev->dev, "timeout for waiting configuration set\n");
/* * Since there is no completion interrupt for status stage, * it needs to call ->completion in software after * ep0_queue is back.
*/
queue_work(system_freezable_wq, &priv_dev->pending_status_wq); return ret;
}
if (!list_empty(&priv_ep->pending_req_list)) {
dev_err(priv_dev->dev, "can't handle multiple requests for ep0\n");
spin_unlock_irqrestore(&priv_dev->lock, flags); return -EBUSY;
}
ret = usb_gadget_map_request_by_dev(priv_dev->sysdev, request,
priv_dev->ep0_data_dir); if (ret) {
spin_unlock_irqrestore(&priv_dev->lock, flags);
dev_err(priv_dev->dev, "failed to map request\n"); return -EINVAL;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.