summaryrefslogtreecommitdiff
path: root/src/portable/linux
diff options
context:
space:
mode:
Diffstat (limited to 'src/portable/linux')
-rw-r--r--src/portable/linux/raw_gadget/raw_gadget_context.c2
-rw-r--r--src/portable/linux/raw_gadget/raw_gadget_endpoint.c86
-rw-r--r--src/portable/linux/raw_gadget/raw_gadget_event.c15
-rw-r--r--src/portable/linux/raw_gadget/raw_gadget_hal.c6
-rw-r--r--src/portable/linux/raw_gadget/raw_gadget_private.h1
-rw-r--r--src/portable/linux/raw_gadget/raw_gadget_transfer.c6
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) &&