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
This commit is contained in:
Aidan MacDonald 2021-11-08 21:12:24 +00:00
parent aed113042d
commit 8c954c68e5

View file

@ -265,9 +265,9 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] =
#ifdef USB_LEGACY_CONTROL_API #ifdef USB_LEGACY_CONTROL_API
static struct usb_ctrlrequest active_request_buf; static struct usb_ctrlrequest active_request_buf;
static struct usb_ctrlrequest* active_request = NULL; static struct usb_ctrlrequest* volatile active_request = NULL;
static void* control_write_data = NULL; static void* volatile control_write_data = NULL;
static bool control_write_data_done = false; static volatile bool control_write_data_done = false;
#endif #endif
static void usb_core_control_request_handler(struct usb_ctrlrequest* req, void* reqdata); 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 #ifdef USB_LEGACY_CONTROL_API
if(endpoint == EP_CONTROL) { if(endpoint == EP_CONTROL) {
if(dir == USB_DIR_OUT && active_request && control_write_data_done) { bool cwdd = control_write_data_done;
completion_event->data[0] = active_request; struct usb_ctrlrequest* req = active_request;
if(control_write_data_done && dir == USB_DIR_OUT)
completion_event->data[1] = control_write_data; if(dir == USB_DIR_OUT && req && cwdd) {
completion_event->data[0] = req;
completion_event->data[1] = control_write_data;
} else { } else {
return; 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 usb_drv_control_response(enum usb_control_response resp,
void* data, int length) void* data, int length)
{ {
if(!active_request) struct usb_ctrlrequest* req = active_request;
if(!req)
panicf("null ctrl req"); panicf("null ctrl req");
if(active_request->wLength == 0) if(req->wLength == 0)
{ {
active_request = NULL; active_request = NULL;
@ -1038,7 +1042,7 @@ void usb_drv_control_response(enum usb_control_response resp,
else else
panicf("RECEIVE on non-data req"); panicf("RECEIVE on non-data req");
} }
else if(active_request->bRequestType & USB_DIR_IN) else if(req->bRequestType & USB_DIR_IN)
{ {
/* Control read request */ /* Control read request */
if(resp == USB_CONTROL_ACK) if(resp == USB_CONTROL_ACK)