summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2021-11-08 21:12:24 +0000
committerAidan MacDonald <amachronic@protonmail.com>2021-11-08 21:46:36 +0000
commit8c954c68e59ca2e644d08524f74e9dc5b728ee6e (patch)
tree5f92fd3cf17b6c8d351d49b09c3ed66fe7a36b15
parentaed113042d7467f1bf0793443e65a6941975394f (diff)
downloadrockbox-8c954c68e59ca2e644d08524f74e9dc5b728ee6e.tar.gz
rockbox-8c954c68e59ca2e644d08524f74e9dc5b728ee6e.zip
usb: Attempt to fix race condition in compatibility layer
Because usb_core_legacy_control_request() is called by an interrupt handler the global variables used to track the current control request at the very least need to be volatile. It might also be necessary to disable IRQs but I'm not sure of that. Change-Id: I0f0bb86d0ad63734e8d3c73cb1c52fedf5a98120
-rw-r--r--firmware/usbstack/usb_core.c24
1 files changed, 14 insertions, 10 deletions
diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c
index 5e87b0ad69..5de892196d 100644
--- a/firmware/usbstack/usb_core.c
+++ b/firmware/usbstack/usb_core.c
@@ -265,9 +265,9 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] =
#ifdef USB_LEGACY_CONTROL_API
static struct usb_ctrlrequest active_request_buf;
-static struct usb_ctrlrequest* active_request = NULL;
-static void* control_write_data = NULL;
-static bool control_write_data_done = false;
+static struct usb_ctrlrequest* volatile active_request = NULL;
+static void* volatile control_write_data = NULL;
+static volatile bool control_write_data_done = false;
#endif
static void usb_core_control_request_handler(struct usb_ctrlrequest* req, void* reqdata);
@@ -956,10 +956,12 @@ void usb_core_transfer_complete(int endpoint, int dir, int status, int length)
#ifdef USB_LEGACY_CONTROL_API
if(endpoint == EP_CONTROL) {
- if(dir == USB_DIR_OUT && active_request && control_write_data_done) {
- completion_event->data[0] = active_request;
- if(control_write_data_done && dir == USB_DIR_OUT)
- completion_event->data[1] = control_write_data;
+ bool cwdd = control_write_data_done;
+ struct usb_ctrlrequest* req = active_request;
+
+ if(dir == USB_DIR_OUT && req && cwdd) {
+ completion_event->data[0] = req;
+ completion_event->data[1] = control_write_data;
} else {
return;
}
@@ -1023,10 +1025,12 @@ void usb_core_legacy_control_request(struct usb_ctrlrequest* req)
void usb_drv_control_response(enum usb_control_response resp,
void* data, int length)
{
- if(!active_request)
+ struct usb_ctrlrequest* req = active_request;
+
+ if(!req)
panicf("null ctrl req");
- if(active_request->wLength == 0)
+ if(req->wLength == 0)
{
active_request = NULL;
@@ -1038,7 +1042,7 @@ void usb_drv_control_response(enum usb_control_response resp,
else
panicf("RECEIVE on non-data req");
}
- else if(active_request->bRequestType & USB_DIR_IN)
+ else if(req->bRequestType & USB_DIR_IN)
{
/* Control read request */
if(resp == USB_CONTROL_ACK)