From 1b04b4a38dd8cab03eded8002f169cada83e29d8 Mon Sep 17 00:00:00 2001 From: Steven Portley Date: Tue, 3 Feb 2026 17:13:09 -0800 Subject: [PATCH] Make usb_retry_* generic This commit removes the usb_retry_* htool parameters and makes their names more generic so that they also apply to other transports. This commit also switches the USB retry loop to use the new claim API which already contains an internal retry loop. --- examples/htool.c | 9 ++-- examples/htool_usb.c | 74 ++++++--------------------------- transports/libhoth_device.c | 3 ++ transports/libhoth_usb.c | 24 ++++++----- transports/libhoth_usb.h | 2 + transports/libhoth_usb_device.h | 1 + 6 files changed, 37 insertions(+), 76 deletions(-) diff --git a/examples/htool.c b/examples/htool.c index 0ababc5..0b2192f 100644 --- a/examples/htool.c +++ b/examples/htool.c @@ -1796,11 +1796,10 @@ static const struct htool_param GLOBAL_FLAGS[] = { "or 'mtd' transports; for example '0x900000'."}, {HTOOL_FLAG_VALUE, .name = "dbus_hoth_id", .default_value = "", .desc = "The hoth ID associated with the RoT's hothd service."}, - {HTOOL_FLAG_VALUE, .name = "usb_retry_duration", .default_value = "1000ms", - .desc = "Maximum duration to retry opening a busy USB device (e.g., " - "'1s', '1500ms')."}, - {HTOOL_FLAG_VALUE, .name = "usb_retry_delay", .default_value = "50ms", - .desc = "Delay between USB open retries (e.g., '50ms', '10000us')."}, + {HTOOL_FLAG_VALUE, .name = "connect_timeout", .default_value = "1000ms", + .desc = + "Maximum duration to retry opening a busy libhoth transport (e.g., " + "'1s', '1500ms')."}, {HTOOL_FLAG_BOOL, .name = "version", .default_value = "false", .desc = "Print htool version."}, {}}; diff --git a/examples/htool_usb.c b/examples/htool_usb.c index e7f3108..0215af3 100644 --- a/examples/htool_usb.c +++ b/examples/htool_usb.c @@ -307,77 +307,29 @@ struct libhoth_device* htool_libhoth_usb_device(void) { } // Get retry parameters from global flags - const char* duration_str; - const char* delay_str; - if (htool_get_param_string(htool_global_flags(), "usb_retry_duration", - &duration_str) || - htool_get_param_string(htool_global_flags(), "usb_retry_delay", - &delay_str)) { + const char* timeout_str; + if (htool_get_param_string(htool_global_flags(), "connect_timeout", + &timeout_str)) { return NULL; } - int64_t retry_duration_us = parse_time_string_us(duration_str); - int64_t retry_delay_us = parse_time_string_us(delay_str); + int64_t timeout_us = parse_time_string_us(timeout_str); - if (retry_duration_us < 0) { - fprintf(stderr, "Invalid format for --usb_retry_duration: %s\n", - duration_str); + if (timeout_us < 0) { + fprintf(stderr, "Invalid format for --connect_timeout: %s\n", timeout_str); return NULL; } - if (retry_delay_us < 0) { - fprintf(stderr, "Invalid format for --usb_retry_delay: %s\n", delay_str); - return NULL; - } - // Convert duration to milliseconds for comparison with monotonic time helper - uint64_t retry_duration_ms = (uint64_t)retry_duration_us / 1000; uint32_t prng_seed = libhoth_prng_seed(); - struct libhoth_usb_device_init_options opts = { - .usb_device = usb_dev, .usb_ctx = ctx, .prng_seed = prng_seed}; - - int rv = LIBUSB_ERROR_BUSY; // Initialize rv to trigger the loop - uint64_t start_time_ms = libhoth_get_monotonic_ms(); - uint64_t current_time_ms; - - while (rv == LIBUSB_ERROR_BUSY) { - rv = libhoth_usb_open(&opts, &result); - if (rv == LIBUSB_SUCCESS) { - break; // Successfully opened - } - if (rv != LIBUSB_ERROR_BUSY) { - // A different error occurred, report it and exit - fprintf(stderr, "libhoth_usb_open error: %d (%s)\n", rv, - libusb_strerror(rv)); - return NULL; - } - - // Check elapsed time - current_time_ms = libhoth_get_monotonic_ms(); + struct libhoth_usb_device_init_options opts = {.usb_device = usb_dev, + .usb_ctx = ctx, + .prng_seed = prng_seed, + .timeout_us = timeout_us}; - // Handle potential timer wrap-around or error from get_monotonic_ms - if (current_time_ms < start_time_ms) { - fprintf(stderr, "Monotonic clock error detected during retry loop.\n"); - return NULL; - } - - if (current_time_ms - start_time_ms >= retry_duration_ms) { - fprintf(stderr, "libhoth_usb_open timed out after %s (error: %d (%s))\n", - duration_str, rv, libusb_strerror(rv)); - return NULL; // Timeout - } - - // Wait before retrying - // Ensure delay doesn't exceed reasonable limits for usleep (~10s) - useconds_t sleep_us = - (retry_delay_us > 10000000) ? 10000000 : (useconds_t)retry_delay_us; - usleep(sleep_us); - } - - if (rv != LIBUSB_SUCCESS) { - fprintf(stderr, "libhoth_usb_open error: %d (%s)\n", rv, - libusb_strerror(rv)); - result = NULL; + int rv = libhoth_usb_open(&opts, &result); + if (rv != LIBHOTH_OK) { + fprintf(stderr, "libhoth_usb_open failed: %d\n", rv); return NULL; } diff --git a/transports/libhoth_device.c b/transports/libhoth_device.c index 42828b6..7a56c3f 100644 --- a/transports/libhoth_device.c +++ b/transports/libhoth_device.c @@ -15,6 +15,7 @@ #include "transports/libhoth_device.h" #include +#include #include #include @@ -84,6 +85,8 @@ int libhoth_claim_device(struct libhoth_device* dev, uint32_t timeout_us) { if (total_waiting_us >= timeout_us) { // We've exhausted our waiting budget. We couldn't claim the device // within the configured timeout. + fprintf(stderr, "libhoth: timed out claiming transport after %dus\n", + timeout_us); return LIBHOTH_ERR_INTERFACE_BUSY; } diff --git a/transports/libhoth_usb.c b/transports/libhoth_usb.c index 20c4860..1a2dcae 100644 --- a/transports/libhoth_usb.c +++ b/transports/libhoth_usb.c @@ -91,6 +91,7 @@ static int libhoth_usb_release(struct libhoth_device* dev) { static int libhoth_usb_reconnect(struct libhoth_device* dev) { struct libhoth_usb_device* usb_dev = dev->user_ctx; libusb_context* usb_ctx = usb_dev->ctx; + uint64_t timeout_us = usb_dev->claim_timeout_us; struct libusb_device* libusb_dev = libusb_get_device(usb_dev->handle); @@ -142,6 +143,7 @@ static int libhoth_usb_reconnect(struct libhoth_device* dev) { struct libhoth_usb_device_init_options opts; opts.usb_ctx = usb_ctx; opts.usb_device = libusb_dev; + opts.timeout_us = timeout_us; opts.prng_seed = libhoth_prng_seed(); return libhoth_usb_open(&opts, &dev); @@ -196,12 +198,22 @@ int libhoth_usb_open(const struct libhoth_usb_device_init_options* options, } usb_dev->info = info; usb_dev->ctx = options->usb_ctx; + usb_dev->claim_timeout_us = options->timeout_us; status = libusb_open(options->usb_device, &usb_dev->handle); if (status != LIBUSB_SUCCESS) { goto err_out; } - status = libusb_claim_interface(usb_dev->handle, info.interface_id); - if (status != LIBUSB_SUCCESS) { + + dev->send = libhoth_usb_send_request; + dev->receive = libhoth_usb_receive_response; + dev->close = libhoth_usb_close; + dev->claim = libhoth_usb_claim; + dev->release = libhoth_usb_release; + dev->reconnect = libhoth_usb_reconnect; + dev->user_ctx = usb_dev; + + status = libhoth_claim_device(dev, options->timeout_us); + if (status != LIBHOTH_OK) { goto err_out; } @@ -221,14 +233,6 @@ int libhoth_usb_open(const struct libhoth_usb_device_init_options* options, if (status != LIBHOTH_OK) goto err_out; - dev->send = libhoth_usb_send_request; - dev->receive = libhoth_usb_receive_response; - dev->close = libhoth_usb_close; - dev->claim = libhoth_usb_claim; - dev->release = libhoth_usb_release; - dev->reconnect = libhoth_usb_reconnect; - dev->user_ctx = usb_dev; - *out = dev; libusb_free_config_descriptor(config_descriptor); return LIBHOTH_OK; diff --git a/transports/libhoth_usb.h b/transports/libhoth_usb.h index 0625399..0aed958 100644 --- a/transports/libhoth_usb.h +++ b/transports/libhoth_usb.h @@ -36,6 +36,8 @@ struct libhoth_usb_device_init_options { // Seed value to use for Pseudo-random number generator for communicating with // RoT over USB FIFO interface. Must be non-zero uint32_t prng_seed; + // Timeout for connecting to the USB bus + uint32_t timeout_us; }; #define LIBHOTH_NUM_PORTS 16 diff --git a/transports/libhoth_usb_device.h b/transports/libhoth_usb_device.h index 94d26e4..b9c9a46 100644 --- a/transports/libhoth_usb_device.h +++ b/transports/libhoth_usb_device.h @@ -71,6 +71,7 @@ struct libhoth_usb_interface_info { struct libhoth_usb_device { libusb_context* ctx; libusb_device_handle* handle; + uint32_t claim_timeout_us; struct libhoth_usb_interface_info info; union driver_data { struct libhoth_usb_mailbox mailbox;