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
|
/* Request wait states -- after submitting a request, we enter EP0_REQ
|
||||||
* (or EP0_REQ_CTRLWRITE for control writes). EP0_REQ is also used for
|
* (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,
|
||||||
EP0_REQ_CTRLWRITE,
|
EP0_REQ_CTRLWRITE,
|
||||||
|
EP0_REQ_CANCELLED,
|
||||||
|
|
||||||
/* Waiting for a data phase to complete. */
|
/* Waiting for a data phase to complete. */
|
||||||
EP0_DATA_IN, EP0_FIRST_CNAK_STATE = EP0_DATA_IN,
|
EP0_DATA_IN,
|
||||||
EP0_DATA_OUT,
|
EP0_DATA_OUT,
|
||||||
|
|
||||||
/* Waiting for the status phase */
|
/* 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(" bRequestType=%02x bRequest=%02x", req->bRequestType, req->bRequest);
|
||||||
logf(" wValue=%04x wIndex=%u wLength=%u", req->wValue, req->wIndex, req->wLength);
|
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) {
|
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_DATA_IN:
|
||||||
case EP0_STATUS_IN:
|
case EP0_STATUS_IN:
|
||||||
case EP0_DATA_OUT:
|
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,
|
static void usb_dw_control_response(enum usb_control_response resp,
|
||||||
void* data, int length)
|
void* data, int length)
|
||||||
{
|
{
|
||||||
|
@ -931,6 +938,15 @@ static void usb_dw_control_response(enum usb_control_response resp,
|
||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
panicf("%s: bad state=%s", __func__, dw_state_str[ep0.state]);
|
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)
|
#if defined(NO_UNCACHED_ADDR) && defined(POST_DMA_FLUSH)
|
||||||
DISCARD_DCACHE_RANGE(ep0_buffer, 64);
|
DISCARD_DCACHE_RANGE(ep0_buffer, 64);
|
||||||
#endif
|
#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_ep0_recv();
|
||||||
|
|
||||||
usb_dw_control_received(&ep0.pending_req);
|
usb_dw_control_received(&req);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USB_DW_SHARED_FIFO
|
#ifdef USB_DW_SHARED_FIFO
|
||||||
|
|
Loading…
Reference in a new issue