static void dwc3_ep0_do_control_data(struct dwc3 *dwc, const struct dwc3_event_depevt *event) { struct dwc3_ep *dep; struct dwc3_request *req; int ret; dep = dwc->eps[0]; dwc->ep0state = EP0_DATA_PHASE; if (dwc->ep0_status_pending) { dwc3_ep0_send_status_response(dwc); return; } if (list_empty(&dep->request_list)) { dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n"); dep->flags |= DWC3_EP_PENDING_REQUEST; if (event->endpoint_number) dep->flags |= DWC3_EP0_DIR_IN; return; } req = next_request(&dep->request_list); req->direction = !!event->endpoint_number; dwc->ep0state = EP0_DATA_PHASE; if (req->request.length == 0) { ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, dwc->ctrl_req_addr, 0, DWC3_TRBCTL_CONTROL_DATA); } else if ((req->request.length % dep->endpoint.maxpacket) && (event->endpoint_number == 0)) { dwc3_map_buffer_to_dma(req); WARN_ON(req->request.length > dep->endpoint.maxpacket); dwc->ep0_bounced = true; /* * REVISIT in case request length is bigger than EP0 * wMaxPacketSize, we will need two chained TRBs to handle * the transfer. */ ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, dwc->ep0_bounce_addr, dep->endpoint.maxpacket, DWC3_TRBCTL_CONTROL_DATA); } else { dwc3_map_buffer_to_dma(req); ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, req->request.dma, req->request.length, DWC3_TRBCTL_CONTROL_DATA); } WARN_ON(ret < 0); }
/* * ch 9.4.5 */ static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { struct dwc3_ep *dep; u32 recip; u16 usb_status = 0; __le16 *response_pkt; recip = ctrl->bRequestType & USB_RECIP_MASK; switch (recip) { case USB_RECIP_DEVICE: /* * We are self-powered. U1/U2/LTM will be set later * once we handle this states. RemoteWakeup is 0 on SS */ usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED; break; case USB_RECIP_INTERFACE: /* * Function Remote Wake Capable D0 * Function Remote Wakeup D1 */ break; case USB_RECIP_ENDPOINT: dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); if (!dep) return -EINVAL; if (dep->flags & DWC3_EP_STALL) usb_status = 1 << USB_ENDPOINT_HALT; break; default: return -EINVAL; }; response_pkt = (__le16 *) dwc->setup_buf; *response_pkt = cpu_to_le16(usb_status); dwc->ep0_usb_req.length = sizeof(*response_pkt); dwc3_ep0_send_status_response(dwc); return 0; }