diff options
Diffstat (limited to 'src/portable/linux')
6 files changed, 104 insertions, 12 deletions
diff --git a/src/portable/linux/raw_gadget/raw_gadget_context.c b/src/portable/linux/raw_gadget/raw_gadget_context.c index e45125a57..9d7b1a516 100644 --- a/src/portable/linux/raw_gadget/raw_gadget_context.c +++ b/src/portable/linux/raw_gadget/raw_gadget_context.c @@ -106,6 +106,7 @@ raw_gadget_result_t raw_gadget_context_table_create(size_t context_count) context->available = false; context->initialized = false; context->shutting_down = false; + context->resetting = false; context->event_thread_created = false; context->handle = (raw_gadget_handle_t) index; context->speed = RAW_GADGET_SPEED_INVALID; @@ -210,6 +211,7 @@ void raw_gadget_context_reset(raw_gadget_context_t *context) context->initialized = false; context->configured = false; context->shutting_down = false; + context->resetting = false; context->event_thread_created = false; context->speed = RAW_GADGET_SPEED_INVALID; context->file_descriptor = RAW_GADGET_INVALID_FILE_DESCRIPTOR; diff --git a/src/portable/linux/raw_gadget/raw_gadget_endpoint.c b/src/portable/linux/raw_gadget/raw_gadget_endpoint.c index a7d0aae19..8952e53b1 100644 --- a/src/portable/linux/raw_gadget/raw_gadget_endpoint.c +++ b/src/portable/linux/raw_gadget/raw_gadget_endpoint.c @@ -10,6 +10,7 @@ #include <errno.h> #include <string.h> #include <sys/ioctl.h> +#include <time.h> #include <linux/usb/ch9.h> @@ -61,6 +62,11 @@ static raw_gadget_result_t raw_gadget_endpoint_disable_locked( USB_RAW_IOCTL_EP_DISABLE, (unsigned long)kernel_handle) < 0) { + TU_LOG1("Raw Gadget: EP_DISABLE failed: ep=%02x handle=%u errno=%d (%s)\r\n", + endpoint->address, + kernel_handle, + errno, + strerror(errno)); return RAW_GADGET_RESULT_IO_ERROR; } @@ -120,6 +126,12 @@ raw_gadget_result_t raw_gadget_endpoint_open(raw_gadget_handle_t handle, return RAW_GADGET_RESULT_INTERNAL_ERROR; } + if (context->resetting || context->shutting_down) + { + (void) pthread_mutex_unlock(&context->mutex); + return RAW_GADGET_RESULT_NOT_AVAILABLE; + } + endpoint = raw_gadget_endpoint_get(context, endpoint_address); if (endpoint->enabled) { @@ -231,7 +243,9 @@ raw_gadget_result_t raw_gadget_endpoint_stall(raw_gadget_handle_t handle, raw_gadget_context_t *context; raw_gadget_endpoint_t *endpoint; raw_gadget_result_t result; + uint32_t generation; uint32_t kernel_handle; + int file_descriptor; context = raw_gadget_context_get(handle); result = raw_gadget_endpoint_context_validate(context); @@ -245,6 +259,12 @@ raw_gadget_result_t raw_gadget_endpoint_stall(raw_gadget_handle_t handle, return RAW_GADGET_RESULT_INTERNAL_ERROR; } + if (context->resetting || context->shutting_down) + { + (void) pthread_mutex_unlock(&context->mutex); + return RAW_GADGET_RESULT_NOT_AVAILABLE; + } + if ((endpoint_address & USB_ENDPOINT_NUMBER_MASK) == 0u) { if (!context->ep0_request_active) @@ -284,21 +304,59 @@ raw_gadget_result_t raw_gadget_endpoint_stall(raw_gadget_handle_t handle, } kernel_handle = endpoint->kernel_handle; + generation = context->transfer_generation; + file_descriptor = context->file_descriptor; - if (ioctl(context->file_descriptor, - USB_RAW_IOCTL_EP_SET_HALT, - (unsigned long)kernel_handle) < 0) - { - result = RAW_GADGET_RESULT_IO_ERROR; - } - else + while (true) { - result = RAW_GADGET_RESULT_SUCCESS; - } + int const ioctl_result = + ioctl(file_descriptor, + USB_RAW_IOCTL_EP_SET_HALT, + (unsigned long) kernel_handle); + int const error_number = errno; - (void) pthread_mutex_unlock(&context->mutex); + (void) pthread_mutex_unlock(&context->mutex); - return result; + if (ioctl_result == 0) + { + return RAW_GADGET_RESULT_SUCCESS; + } + + if (error_number != EAGAIN) + { + TU_LOG1("Raw Gadget: EP_SET_HALT failed: ep=%02x errno=%d (%s)\r\n", + endpoint_address, + error_number, + strerror(error_number)); + return RAW_GADGET_RESULT_IO_ERROR; + } + + // dummy_hcd can retain its small-IN FIFO request briefly after reporting completion. + struct timespec retry_delay = { + .tv_sec = 0, + .tv_nsec = 10000000L + }; + while ((nanosleep(&retry_delay, &retry_delay) < 0) && (errno == EINTR)) + { + } + + if (pthread_mutex_lock(&context->mutex) != 0) + { + return RAW_GADGET_RESULT_INTERNAL_ERROR; + } + + if (!context->initialized || + context->resetting || + context->shutting_down || + (context->file_descriptor != file_descriptor) || + (context->transfer_generation != generation) || + !endpoint->enabled || + (endpoint->kernel_handle != kernel_handle)) + { + (void) pthread_mutex_unlock(&context->mutex); + return RAW_GADGET_RESULT_NOT_AVAILABLE; + } + } } raw_gadget_result_t raw_gadget_endpoint_clear_stall( @@ -328,6 +386,12 @@ raw_gadget_result_t raw_gadget_endpoint_clear_stall( return RAW_GADGET_RESULT_INTERNAL_ERROR; } + if (context->resetting || context->shutting_down) + { + (void) pthread_mutex_unlock(&context->mutex); + return RAW_GADGET_RESULT_NOT_AVAILABLE; + } + endpoint = raw_gadget_endpoint_get(context, endpoint_address); if (!endpoint->enabled) { diff --git a/src/portable/linux/raw_gadget/raw_gadget_event.c b/src/portable/linux/raw_gadget/raw_gadget_event.c index 742099723..ec691c74c 100644 --- a/src/portable/linux/raw_gadget/raw_gadget_event.c +++ b/src/portable/linux/raw_gadget/raw_gadget_event.c @@ -357,6 +357,7 @@ void raw_gadget_bus_reset_prepare(raw_gadget_context_t *context) return; } + context->resetting = true; context->configured = false; context->transfer_generation++; context->ep0_request_active = false; @@ -367,5 +368,17 @@ void raw_gadget_bus_reset_prepare(raw_gadget_context_t *context) (void) pthread_mutex_unlock(&context->mutex); - raw_gadget_transfer_cancel_all(context); + raw_gadget_result_t const result = + raw_gadget_endpoint_close_all(context->handle); + + if (pthread_mutex_lock(&context->mutex) == 0) + { + context->resetting = false; + (void) pthread_mutex_unlock(&context->mutex); + } + + if (result != RAW_GADGET_RESULT_SUCCESS) + { + TU_LOG1("Raw Gadget: endpoint reset failed: result=%d\r\n", result); + } } diff --git a/src/portable/linux/raw_gadget/raw_gadget_hal.c b/src/portable/linux/raw_gadget/raw_gadget_hal.c index 9212d219b..faaefc980 100644 --- a/src/portable/linux/raw_gadget/raw_gadget_hal.c +++ b/src/portable/linux/raw_gadget/raw_gadget_hal.c @@ -292,6 +292,12 @@ raw_gadget_result_t raw_gadget_configure(raw_gadget_handle_t handle) return RAW_GADGET_RESULT_INTERNAL_ERROR; } + if (context->resetting || context->shutting_down) + { + (void) pthread_mutex_unlock(&context->mutex); + return RAW_GADGET_RESULT_NOT_AVAILABLE; + } + if (context->configured) { (void) pthread_mutex_unlock(&context->mutex); diff --git a/src/portable/linux/raw_gadget/raw_gadget_private.h b/src/portable/linux/raw_gadget/raw_gadget_private.h index eedc43c9e..f36d0871e 100644 --- a/src/portable/linux/raw_gadget/raw_gadget_private.h +++ b/src/portable/linux/raw_gadget/raw_gadget_private.h @@ -73,6 +73,7 @@ typedef struct bool available; bool initialized; bool shutting_down; + bool resetting; bool event_thread_created; raw_gadget_handle_t handle; diff --git a/src/portable/linux/raw_gadget/raw_gadget_transfer.c b/src/portable/linux/raw_gadget/raw_gadget_transfer.c index aa1a6f4b7..9525ce28e 100644 --- a/src/portable/linux/raw_gadget/raw_gadget_transfer.c +++ b/src/portable/linux/raw_gadget/raw_gadget_transfer.c @@ -330,6 +330,12 @@ raw_gadget_result_t raw_gadget_endpoint_transfer(raw_gadget_handle_t handle, return RAW_GADGET_RESULT_INTERNAL_ERROR; } + if (context->resetting || context->shutting_down) + { + (void) pthread_mutex_unlock(&context->mutex); + return RAW_GADGET_RESULT_NOT_AVAILABLE; + } + if (endpoint_zero && context->ep0_request_active) { ep0_status_stage = (length == 0u) && |
