usb-designware: fix setup packet error handling
This handles the case where the host sends a new setup packet in the middle of an ongoing control transfer. Change-Id: I1d2e02467e9b813c9827cc0699cb87a500515e31
This commit is contained in:
parent
fd50baa23f
commit
9eaa14dc02
1 changed files with 26 additions and 8 deletions
|
@ -102,12 +102,14 @@ enum usb_dw_ep0_state
|
|||
|
||||
/* Request wait states -- after submitting a request, we enter EP0_REQ
|
||||
* (or EP0_REQ_CTRLWRITE for control writes). EP0_REQ is also used for
|
||||
* the 2nd phase of a control write. */
|
||||
* the 2nd phase of a control write. EP0_REQ_CANCELLED is entered if we
|
||||
* receive a setup packet before getting a response from the USB stack. */
|
||||
EP0_REQ,
|
||||
EP0_REQ_CTRLWRITE,
|
||||
EP0_REQ_CANCELLED,
|
||||
|
||||
/* Waiting for a data phase to complete. */
|
||||
EP0_DATA_IN, EP0_FIRST_CNAK_STATE = EP0_DATA_IN,
|
||||
EP0_DATA_IN,
|
||||
EP0_DATA_OUT,
|
||||
|
||||
/* Waiting for the status phase */
|
||||
|
@ -856,11 +858,15 @@ static void usb_dw_control_received(struct usb_ctrlrequest* req)
|
|||
logf(" bRequestType=%02x bRequest=%02x", req->bRequestType, req->bRequest);
|
||||
logf(" wValue=%04x wIndex=%u wLength=%u", req->wValue, req->wIndex, req->wLength);
|
||||
|
||||
/* FIXME: This will implode if we receive a setup packet while waiting
|
||||
* for a response from the USB stack to a previous packet.
|
||||
*/
|
||||
|
||||
switch(ep0.state) {
|
||||
case EP0_REQ:
|
||||
case EP0_REQ_CTRLWRITE:
|
||||
case EP0_REQ_CANCELLED:
|
||||
/* Save the request for later */
|
||||
memcpy(&ep0.pending_req, req, sizeof(*req));
|
||||
ep0.state = EP0_REQ_CANCELLED;
|
||||
break;
|
||||
|
||||
case EP0_DATA_IN:
|
||||
case EP0_STATUS_IN:
|
||||
case EP0_DATA_OUT:
|
||||
|
@ -894,6 +900,7 @@ static void usb_dw_control_received(struct usb_ctrlrequest* req)
|
|||
}
|
||||
}
|
||||
|
||||
/* note: must be called with IRQs disabled */
|
||||
static void usb_dw_control_response(enum usb_control_response resp,
|
||||
void* data, int length)
|
||||
{
|
||||
|
@ -931,6 +938,15 @@ static void usb_dw_control_response(enum usb_control_response resp,
|
|||
}
|
||||
break;
|
||||
|
||||
case EP0_REQ_CANCELLED:
|
||||
/* Terminate the old request */
|
||||
usb_core_control_complete(-3);
|
||||
|
||||
/* Submit the pending request */
|
||||
ep0.state = EP0_SETUP;
|
||||
usb_dw_control_received(&ep0.pending_req);
|
||||
break;
|
||||
|
||||
default:
|
||||
panicf("%s: bad state=%s", __func__, dw_state_str[ep0.state]);
|
||||
}
|
||||
|
@ -1063,10 +1079,12 @@ static void usb_dw_handle_setup_received(void)
|
|||
#if defined(NO_UNCACHED_ADDR) && defined(POST_DMA_FLUSH)
|
||||
DISCARD_DCACHE_RANGE(ep0_buffer, 64);
|
||||
#endif
|
||||
memcpy(&ep0.pending_req, ep0_buffer, sizeof(struct usb_ctrlrequest));
|
||||
struct usb_ctrlrequest req;
|
||||
memcpy(&req, ep0_buffer, sizeof(struct usb_ctrlrequest));
|
||||
|
||||
usb_dw_ep0_recv();
|
||||
|
||||
usb_dw_control_received(&ep0.pending_req);
|
||||
usb_dw_control_received(&req);
|
||||
}
|
||||
|
||||
#ifdef USB_DW_SHARED_FIFO
|
||||
|
|
Loading…
Reference in a new issue