diff options
author | Aidan MacDonald <amachronic@protonmail.com> | 2021-10-18 21:19:19 +0100 |
---|---|---|
committer | Aidan MacDonald <amachronic@protonmail.com> | 2021-11-27 09:29:44 -0500 |
commit | 9eaa14dc029587bf35ef1c8c9624192cf20ecbef (patch) | |
tree | 004dad448936acc2b5ae0c62140b131a80b82f3e /firmware | |
parent | fd50baa23ff5e17fad7d549ac226e8cf8dc67b86 (diff) | |
download | rockbox-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')
-rw-r--r-- | firmware/drivers/usb-designware.c | 34 |
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 */ | ||
897 | static void usb_dw_control_response(enum usb_control_response resp, | 904 | static 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 |