diff options
author | Aidan MacDonald <amachronic@protonmail.com> | 2021-11-08 21:12:24 +0000 |
---|---|---|
committer | Aidan MacDonald <amachronic@protonmail.com> | 2021-11-08 21:46:36 +0000 |
commit | 8c954c68e59ca2e644d08524f74e9dc5b728ee6e (patch) | |
tree | 5f92fd3cf17b6c8d351d49b09c3ed66fe7a36b15 | |
parent | aed113042d7467f1bf0793443e65a6941975394f (diff) | |
download | rockbox-8c954c68e5.tar.gz rockbox-8c954c68e5.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.c | 24 |
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) |