summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2021-10-18 21:19:19 +0100
committerAidan MacDonald <amachronic@protonmail.com>2021-11-27 09:29:44 -0500
commit9eaa14dc029587bf35ef1c8c9624192cf20ecbef (patch)
tree004dad448936acc2b5ae0c62140b131a80b82f3e /firmware/drivers
parentfd50baa23ff5e17fad7d549ac226e8cf8dc67b86 (diff)
downloadrockbox-9eaa14dc029587bf35ef1c8c9624192cf20ecbef.tar.gz
rockbox-9eaa14dc029587bf35ef1c8c9624192cf20ecbef.zip
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
Diffstat (limited to 'firmware/drivers')
-rw-r--r--firmware/drivers/usb-designware.c34
1 files changed, 26 insertions, 8 deletions
diff --git a/firmware/drivers/usb-designware.c b/firmware/drivers/usb-designware.c
index 37e96aa557..beecb5ea7a 100644
--- a/firmware/drivers/usb-designware.c
+++ b/firmware/drivers/usb-designware.c
@@ -102,12 +102,14 @@ enum usb_dw_ep0_state
102 102
103 /* Request wait states -- after submitting a request, we enter EP0_REQ 103 /* Request wait states -- after submitting a request, we enter EP0_REQ
104 * (or EP0_REQ_CTRLWRITE for control writes). EP0_REQ is also used for 104 * (or EP0_REQ_CTRLWRITE for control writes). EP0_REQ is also used for
105 * the 2nd phase of a control write. */ 105 * the 2nd phase of a control write. EP0_REQ_CANCELLED is entered if we
106 * receive a setup packet before getting a response from the USB stack. */
106 EP0_REQ, 107 EP0_REQ,
107 EP0_REQ_CTRLWRITE, 108 EP0_REQ_CTRLWRITE,
109 EP0_REQ_CANCELLED,
108 110
109 /* Waiting for a data phase to complete. */ 111 /* Waiting for a data phase to complete. */
110 EP0_DATA_IN, EP0_FIRST_CNAK_STATE = EP0_DATA_IN, 112 EP0_DATA_IN,
111 EP0_DATA_OUT, 113 EP0_DATA_OUT,
112 114
113 /* Waiting for the status phase */ 115 /* Waiting for the status phase */
@@ -856,11 +858,15 @@ static void usb_dw_control_received(struct usb_ctrlrequest* req)
856 logf(" bRequestType=%02x bRequest=%02x", req->bRequestType, req->bRequest); 858 logf(" bRequestType=%02x bRequest=%02x", req->bRequestType, req->bRequest);
857 logf(" wValue=%04x wIndex=%u wLength=%u", req->wValue, req->wIndex, req->wLength); 859 logf(" wValue=%04x wIndex=%u wLength=%u", req->wValue, req->wIndex, req->wLength);
858 860
859 /* FIXME: This will implode if we receive a setup packet while waiting
860 * for a response from the USB stack to a previous packet.
861 */
862
863 switch(ep0.state) { 861 switch(ep0.state) {
862 case EP0_REQ:
863 case EP0_REQ_CTRLWRITE:
864 case EP0_REQ_CANCELLED:
865 /* Save the request for later */
866 memcpy(&ep0.pending_req, req, sizeof(*req));
867 ep0.state = EP0_REQ_CANCELLED;
868 break;
869
864 case EP0_DATA_IN: 870 case EP0_DATA_IN:
865 case EP0_STATUS_IN: 871 case EP0_STATUS_IN:
866 case EP0_DATA_OUT: 872 case EP0_DATA_OUT:
@@ -894,6 +900,7 @@ static void usb_dw_control_received(struct usb_ctrlrequest* req)
894 } 900 }
895} 901}
896 902
903/* note: must be called with IRQs disabled */
897static void usb_dw_control_response(enum usb_control_response resp, 904static void usb_dw_control_response(enum usb_control_response resp,
898 void* data, int length) 905 void* data, int length)
899{ 906{
@@ -931,6 +938,15 @@ static void usb_dw_control_response(enum usb_control_response resp,
931 } 938 }
932 break; 939 break;
933 940
941 case EP0_REQ_CANCELLED:
942 /* Terminate the old request */
943 usb_core_control_complete(-3);
944
945 /* Submit the pending request */
946 ep0.state = EP0_SETUP;
947 usb_dw_control_received(&ep0.pending_req);
948 break;
949
934 default: 950 default:
935 panicf("%s: bad state=%s", __func__, dw_state_str[ep0.state]); 951 panicf("%s: bad state=%s", __func__, dw_state_str[ep0.state]);
936 } 952 }
@@ -1063,10 +1079,12 @@ static void usb_dw_handle_setup_received(void)
1063#if defined(NO_UNCACHED_ADDR) && defined(POST_DMA_FLUSH) 1079#if defined(NO_UNCACHED_ADDR) && defined(POST_DMA_FLUSH)
1064 DISCARD_DCACHE_RANGE(ep0_buffer, 64); 1080 DISCARD_DCACHE_RANGE(ep0_buffer, 64);
1065#endif 1081#endif
1066 memcpy(&ep0.pending_req, ep0_buffer, sizeof(struct usb_ctrlrequest)); 1082 struct usb_ctrlrequest req;
1083 memcpy(&req, ep0_buffer, sizeof(struct usb_ctrlrequest));
1084
1067 usb_dw_ep0_recv(); 1085 usb_dw_ep0_recv();
1068 1086
1069 usb_dw_control_received(&ep0.pending_req); 1087 usb_dw_control_received(&req);
1070} 1088}
1071 1089
1072#ifdef USB_DW_SHARED_FIFO 1090#ifdef USB_DW_SHARED_FIFO