From c889a98734455cf5ba2873bbacfbb9042dc0ac61 Mon Sep 17 00:00:00 2001 From: Martin Gysel Date: Tue, 22 Oct 2024 20:37:54 +0200 Subject: [PATCH] update libusb to v1.0.27 --- libusb/AUTHORS | 22 ++ libusb/libusb/core.c | 550 ++++++++++++++++++++----------- libusb/libusb/descriptor.c | 292 +++++++++++++++- libusb/libusb/hotplug.c | 9 +- libusb/libusb/hotplug.h | 105 ------ libusb/libusb/io.c | 133 ++++---- libusb/libusb/libusb.h | 321 +++++++++++++----- libusb/libusb/libusbi.h | 48 ++- libusb/libusb/os/events_posix.c | 40 +++ libusb/libusb/os/events_posix.h | 3 + libusb/libusb/os/linux_usbfs.c | 43 ++- libusb/libusb/os/threads_posix.c | 6 +- libusb/libusb/strerror.c | 10 +- libusb/libusb/sync.c | 43 +-- libusb/libusb/version.h | 2 +- libusb/libusb/version_nano.h | 2 +- 16 files changed, 1121 insertions(+), 508 deletions(-) delete mode 100644 libusb/libusb/hotplug.h diff --git a/libusb/AUTHORS b/libusb/AUTHORS index 8f91512..50b9c5e 100644 --- a/libusb/AUTHORS +++ b/libusb/AUTHORS @@ -13,15 +13,18 @@ Copyright © 2013-2018 Chris Dickens Other contributors: Aaron Luft Adam Korcz +Addison Crump Adrian Bunk Adrien Destugues Akshay Jaggi Alan Ott Alan Stern Aleksandr Mezin +Alexander Mot Alexander Pyhalov Alexander Schlarb Alexander Stein +Alex Feinman Alex Vatchenko Andrew Aldridge Andrew Fernandes @@ -44,6 +47,7 @@ Bence Csokas Benjamin Berg Benjamin Dobell Bohdan Tymkiv +Brad Smith Brent Rector Bruno Harbulot Carl Karsten @@ -59,7 +63,9 @@ David Moore Dmitry Fleytman Dmitry Kostjuchenko Dmitry Zakablukov +Dominik Boehi Doug Johnston +Edgar Fuß Evan Hunter Evan Miller Fabrice Fontaine @@ -68,6 +74,7 @@ Felipe Balbi Florian Albrechtskirchinger Francesco Montorsi Francisco Facioni +Francis Hart Frank Li Frederik Carlier Freek Dijkstra @@ -84,6 +91,7 @@ Ido Yariv Igor Anokhin Ihor Dutchak Ilya Konstantinov +Ingvar Stepanyan Jakub Klama James Hanko Jeffrey Nichols @@ -98,6 +106,7 @@ Joost Muller Josh Gao Joshua Blake Joshua Hou +Joshua M. Clulow Juan Cruz Viotti Julian Scheel Justin Bischoff @@ -112,11 +121,13 @@ Lars Wirzenius Lei Chen Léo Lam Liang Yunwang +Lonnie Abelbeck Luca Longinotti Luz Paz Mac Wang Marco Trevisan (Treviño) Marcus Meissner +Mario Kleiner Mark Kuo Markus Heidelberg Martin Ettl @@ -136,20 +147,26 @@ Moritz Fischer Nancy Li Nia Alarie Nicholas Corgan +Niklas Gürtler Omri Iluz +Orhan aib Kavrakoglu Orin Eman Ozkan Sezer +Pablo Prietz Patrick Stewart Paul Cercueil Paul Fertser Paul Qureshi Pekka Nikander +Petr Pazourek Philémon Favrod Pino Toscano Rob Walker Romain Vimont Roman Kalashnikov +Rosen Penev Ryan Hileman +Ryan Metcalfe Ryan Schmidt Saleem Rashid Sameeh Jubran @@ -158,6 +175,7 @@ Sebastian Pipping Sebastian von Ohr Sergey Serb Shawn Hoffman +Simon Chan Simon Haggett Simon Newton Slash Gordon @@ -165,6 +183,7 @@ Stefan Agner Stefan Tauner Steinar H. Gunderson Stephen Groat +Sylvain Fasel Theo Buehler Thomas Röfer Tim Hutt @@ -187,6 +206,7 @@ William Orr William Skellenger Xiaofan Chen Yegor Yefremov +Zeng Guang Zhiqiang Liu Zoltán Kovács Сергей Валерьевич @@ -199,4 +219,6 @@ parafin RipleyTom Seneral saur0n +SomeAlphabetGuy winterrace +xloem diff --git a/libusb/libusb/core.c b/libusb/libusb/core.c index ec429b7..ffe33b7 100644 --- a/libusb/libusb/core.c +++ b/libusb/libusb/core.c @@ -1,7 +1,7 @@ /* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */ /* * Core functions for libusb - * Copyright © 2012-2013 Nathan Hjelm + * Copyright © 2012-2023 Nathan Hjelm * Copyright © 2007-2008 Daniel Drake * Copyright © 2001 Johannes Erdfelt * @@ -34,7 +34,7 @@ static const struct libusb_version libusb_version_internal = { LIBUSB_MAJOR, LIBUSB_MINOR, LIBUSB_MICRO, LIBUSB_NANO, - LIBUSB_RC, "http://libusb.info" }; + LIBUSB_RC, "https://libusb.info" }; static struct timespec timestamp_origin; #if defined(ENABLE_LOGGING) && !defined(USE_SYSTEM_LOGGING_FACILITY) static libusb_log_cb log_handler; @@ -43,6 +43,9 @@ static libusb_log_cb log_handler; struct libusb_context *usbi_default_context; struct libusb_context *usbi_fallback_context; static int default_context_refcnt; +#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING) +static usbi_atomic_t default_debug_level = -1; +#endif static usbi_mutex_static_t default_context_lock = USBI_MUTEX_INITIALIZER; static struct usbi_option default_context_options[LIBUSB_OPTION_MAX]; @@ -57,12 +60,12 @@ struct list_head active_contexts_list; * * libusb is an open source library that allows you to communicate with USB * devices from user space. For more info, see the - * libusb homepage. + * libusb homepage. * * This documentation is aimed at application developers wishing to * communicate with USB peripherals from their own software. After reviewing * this documentation, feedback and questions can be sent to the - * libusb-devel mailing list. + * libusb-devel mailing list. * * This documentation assumes knowledge of how to operate USB devices from * a software standpoint (descriptors, configurations, interfaces, endpoints, @@ -111,17 +114,18 @@ struct list_head active_contexts_list; * libusb uses stderr for all logging. By default, logging is set to NONE, * which means that no output will be produced. However, unless the library * has been compiled with logging disabled, then any application calls to - * libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level), or the setting of the - * environmental variable LIBUSB_DEBUG outside of the application, can result - * in logging being produced. Your application should therefore not close - * stderr, but instead direct it to the null device if its output is - * undesirable. - * - * The libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level) function can be - * used to enable logging of certain messages. Under standard configuration, - * libusb doesn't really log much so you are advised to use this function - * to enable all error/warning/ informational messages. It will help debug - * problems with your software. + * libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level), + * libusb_init_context, or the setting of the environmental variable + * LIBUSB_DEBUG outside of the application, can result in logging being + * produced. Your application should therefore not close stderr, but instead + * direct it to the null device if its output is undesirable. + * + * The libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level) or + * libusb_init_context functions can be used to enable logging of certain + * messages. With the default configuration, libusb will not log much so if + * you are advised to use one of these functions to enable all + * error/warning/informational messages. It will help debug problems with your + * software. * * The logged messages are unstructured. There is no one-to-one correspondence * between messages being logged and success or failure return codes from @@ -137,19 +141,19 @@ struct list_head active_contexts_list; * The LIBUSB_DEBUG environment variable can be used to enable message logging * at run-time. This environment variable should be set to a log level number, * which is interpreted the same as the - * libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level) parameter. When this - * environment variable is set, the message logging verbosity level is fixed - * and libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level) effectively does - * nothing. + * libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level), or + * libusb_init_context(&ctx, &(struct libusb_init_option){.option = LIBUSB_OPTION_LOG_LEVEL, .value = {.ival = level}}, 0). + * When the environment variable is set, the message logging verbosity level is + * fixed and setting the LIBUSB_OPTION_LOG_LEVEL option has no effect. * * libusb can be compiled without any logging functions, useful for embedded - * systems. In this case, libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level) - * and the LIBUSB_DEBUG environment variable have no effects. + * systems. In this case, neither the LIBUSB_OPTION_LOG_LEVEL option, nor the + * LIBUSB_DEBUG environment variable will have any effect. * * libusb can also be compiled with verbose debugging messages always. When * the library is compiled in this way, all messages of all verbosities are - * always logged. libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level) and - * the LIBUSB_DEBUG environment variable have no effects. + * always logged. Again, in this case, neither the LIBUSB_OPTION_LOG_LEVEL + * option, nor the LIBUSB_DEBUG environment variable will have any effect. * * \section remarks Other remarks * @@ -327,23 +331,23 @@ if (cfg != desired) * developed modules may both use libusb. * * libusb is written to allow for these multiple user scenarios. The two - * "instances" of libusb will not interfere: libusb_set_option() calls - * from one user will not affect the same settings for other users, other - * users can continue using libusb after one of them calls libusb_exit(), etc. + * "instances" of libusb will not interfere: an option set by one user will have + * no effect the same option for other users, other users can continue using + * libusb after one of them calls libusb_exit(), etc. * * This is made possible through libusb's context concept. When you - * call libusb_init(), you are (optionally) given a context. You can then pass + * call libusb_init_context(), you are (optionally) given a context. You can then pass * this context pointer back into future libusb functions. * * In order to keep things simple for more simplistic applications, it is * legal to pass NULL to all functions requiring a context pointer (as long as * you're sure no other code will attempt to use libusb from the same process). * When you pass NULL, the default context will be used. The default context - * is created the first time a process calls libusb_init() when no other + * is created the first time a process calls libusb_init_context() when no other * context is alive. Contexts are destroyed during libusb_exit(). * * The default context is reference-counted and can be shared. That means that - * if libusb_init(NULL) is called twice within the same process, the two + * if libusb_init_context(NULL, x, y) is called twice within the same process, the two * users end up sharing the same context. The deinitialization and freeing of * the default context will only happen when the last user calls libusb_exit(). * In other words, the default context is created and initialized when its @@ -413,6 +417,7 @@ if (cfg != desired) * - libusb_get_device_speed() * - libusb_get_iso_packet_buffer() * - libusb_get_iso_packet_buffer_simple() + * - libusb_get_max_alt_packet_size() * - libusb_get_max_iso_packet_size() * - libusb_get_max_packet_size() * - libusb_get_next_timeout() @@ -436,6 +441,7 @@ if (cfg != desired) * - libusb_hotplug_deregister_callback() * - libusb_hotplug_register_callback() * - libusb_init() + * - libusb_init_context() * - libusb_interrupt_event_handler() * - libusb_interrupt_transfer() * - libusb_kernel_driver_active() @@ -931,13 +937,13 @@ uint8_t API_EXPORTED libusb_get_port_number(libusb_device *dev) /** \ingroup libusb_dev * Get the list of all port numbers from root for the specified device * - * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 + * Since version 1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102 * \param dev a device * \param port_numbers the array that should contain the port numbers * \param port_numbers_len the maximum length of the array. As per the USB 3.0 * specs, the current maximum limit for the depth is 7. * \returns the number of elements filled - * \returns LIBUSB_ERROR_OVERFLOW if the array is too small + * \returns \ref LIBUSB_ERROR_OVERFLOW if the array is too small */ int API_EXPORTED libusb_get_port_numbers(libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) @@ -1049,8 +1055,8 @@ static const struct libusb_endpoint_descriptor *find_endpoint( * \param dev a device * \param endpoint address of the endpoint in question * \returns the wMaxPacketSize value - * \returns LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist - * \returns LIBUSB_ERROR_OTHER on other failure + * \returns \ref LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist + * \returns \ref LIBUSB_ERROR_OTHER on other failure */ int API_EXPORTED libusb_get_max_packet_size(libusb_device *dev, unsigned char endpoint) @@ -1079,6 +1085,65 @@ int API_EXPORTED libusb_get_max_packet_size(libusb_device *dev, return r; } +static const struct libusb_endpoint_descriptor *find_alt_endpoint( + struct libusb_config_descriptor *config, + int iface_idx, int altsetting_idx, unsigned char endpoint) +{ + if (iface_idx >= config->bNumInterfaces) { + return NULL; + } + + const struct libusb_interface *iface = &config->interface[iface_idx]; + + if (altsetting_idx >= iface->num_altsetting) { + return NULL; + } + + const struct libusb_interface_descriptor *altsetting + = &iface->altsetting[altsetting_idx]; + int ep_idx; + + for (ep_idx = 0; ep_idx < altsetting->bNumEndpoints; ep_idx++) { + const struct libusb_endpoint_descriptor *ep = + &altsetting->endpoint[ep_idx]; + if (ep->bEndpointAddress == endpoint) + return ep; + } + return NULL; +} + +static int get_endpoint_max_packet_size(libusb_device *dev, + const struct libusb_endpoint_descriptor *ep) +{ + struct libusb_ss_endpoint_companion_descriptor *ss_ep_cmp; + enum libusb_endpoint_transfer_type ep_type; + uint16_t val; + int r = 0; + int speed; + + speed = libusb_get_device_speed(dev); + if (speed >= LIBUSB_SPEED_SUPER) { + r = libusb_get_ss_endpoint_companion_descriptor(dev->ctx, ep, &ss_ep_cmp); + if (r == LIBUSB_SUCCESS) { + r = ss_ep_cmp->wBytesPerInterval; + libusb_free_ss_endpoint_companion_descriptor(ss_ep_cmp); + } + } + + /* If the device isn't a SuperSpeed device or retrieving the SS endpoint didn't worked. */ + if (speed < LIBUSB_SPEED_SUPER || r < 0) { + val = ep->wMaxPacketSize; + ep_type = (enum libusb_endpoint_transfer_type) (ep->bmAttributes & 0x3); + + r = val & 0x07ff; + if (ep_type == LIBUSB_ENDPOINT_TRANSFER_TYPE_ISOCHRONOUS + || ep_type == LIBUSB_ENDPOINT_TRANSFER_TYPE_INTERRUPT) + r *= (1 + ((val >> 11) & 3)); + } + + return r; +} + /** \ingroup libusb_dev * Calculate the maximum packet size which a specific endpoint is capable is * sending or receiving in the duration of 1 microframe @@ -1099,24 +1164,25 @@ int API_EXPORTED libusb_get_max_packet_size(libusb_device *dev, * libusb_set_iso_packet_lengths() in order to set the length field of every * isochronous packet in a transfer. * + * This function only considers the first alternate setting of the interface. + * If the endpoint has different maximum packet sizes for different alternate + * settings, you probably want libusb_get_max_alt_packet_size() instead. + * * Since v1.0.3. * * \param dev a device * \param endpoint address of the endpoint in question * \returns the maximum packet size which can be sent/received on this endpoint - * \returns LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist - * \returns LIBUSB_ERROR_OTHER on other failure + * \returns \ref LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist + * \returns \ref LIBUSB_ERROR_OTHER on other failure + * \see libusb_get_max_alt_packet_size */ int API_EXPORTED libusb_get_max_iso_packet_size(libusb_device *dev, unsigned char endpoint) { struct libusb_config_descriptor *config; const struct libusb_endpoint_descriptor *ep; - struct libusb_ss_endpoint_companion_descriptor *ss_ep_cmp; - enum libusb_endpoint_transfer_type ep_type; - uint16_t val; int r; - int speed; r = libusb_get_active_config_descriptor(dev, &config); if (r < 0) { @@ -1131,26 +1197,68 @@ int API_EXPORTED libusb_get_max_iso_packet_size(libusb_device *dev, goto out; } - speed = libusb_get_device_speed(dev); - if (speed >= LIBUSB_SPEED_SUPER) { - r = libusb_get_ss_endpoint_companion_descriptor(dev->ctx, ep, &ss_ep_cmp); - if (r == LIBUSB_SUCCESS) { - r = ss_ep_cmp->wBytesPerInterval; - libusb_free_ss_endpoint_companion_descriptor(ss_ep_cmp); - } - } + r = get_endpoint_max_packet_size(dev, ep); - /* If the device isn't a SuperSpeed device or retrieving the SS endpoint didn't worked. */ - if (speed < LIBUSB_SPEED_SUPER || r < 0) { - val = ep->wMaxPacketSize; - ep_type = (enum libusb_endpoint_transfer_type) (ep->bmAttributes & 0x3); +out: + libusb_free_config_descriptor(config); + return r; +} - r = val & 0x07ff; - if (ep_type == LIBUSB_ENDPOINT_TRANSFER_TYPE_ISOCHRONOUS - || ep_type == LIBUSB_ENDPOINT_TRANSFER_TYPE_INTERRUPT) - r *= (1 + ((val >> 11) & 3)); +/** \ingroup libusb_dev + * Calculate the maximum packet size which a specific endpoint is capable of + * sending or receiving in the duration of 1 microframe + * + * Only the active configuration is examined. The calculation is based on the + * wMaxPacketSize field in the endpoint descriptor as described in section + * 9.6.6 in the USB 2.0 specifications. + * + * If acting on an isochronous or interrupt endpoint, this function will + * multiply the value found in bits 0:10 by the number of transactions per + * microframe (determined by bits 11:12). Otherwise, this function just + * returns the numeric value found in bits 0:10. For USB 3.0 device, it + * will attempts to retrieve the Endpoint Companion Descriptor to return + * wBytesPerInterval. + * + * This function is useful for setting up isochronous transfers, for example + * you might pass the return value from this function to + * libusb_set_iso_packet_lengths() in order to set the length field of every + * isochronous packet in a transfer. + * + * Since version 1.0.27, \ref LIBUSB_API_VERSION >= 0x0100010A + * + * \param dev a device + * \param interface_number the bInterfaceNumber of the interface + * the endpoint belongs to + * \param alternate_setting the bAlternateSetting of the interface + * \param endpoint address of the endpoint in question + * \returns the maximum packet size which can be sent/received on this endpoint + * \returns \ref LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist + * \returns \ref LIBUSB_ERROR_OTHER on other failure + * \see libusb_get_max_iso_packet_size + */ +int API_EXPORTED libusb_get_max_alt_packet_size(libusb_device *dev, + int interface_number, int alternate_setting, unsigned char endpoint) +{ + struct libusb_config_descriptor *config; + const struct libusb_endpoint_descriptor *ep; + int r; + + r = libusb_get_active_config_descriptor(dev, &config); + if (r < 0) { + usbi_err(DEVICE_CTX(dev), + "could not retrieve active config descriptor"); + return LIBUSB_ERROR_OTHER; + } + + ep = find_alt_endpoint(config, interface_number, + alternate_setting, endpoint); + if (!ep) { + r = LIBUSB_ERROR_NOT_FOUND; + goto out; } + r = get_endpoint_max_packet_size(dev, ep); + out: libusb_free_config_descriptor(config); return r; @@ -1209,10 +1317,10 @@ void API_EXPORTED libusb_unref_device(libusb_device *dev) * handle for the underlying device. The handle allows you to use libusb to * perform I/O on the device in question. * - * Call libusb_set_option(NULL, LIBUSB_OPTION_NO_DEVICE_DISCOVERY) before - * libusb_init() if you want to skip enumeration of USB devices. In particular, - * this might be needed on Android if you don't have authority to access USB - * devices in general. + * Call libusb_init_context with the LIBUSB_OPTION_NO_DEVICE_DISCOVERY + * option if you want to skip enumeration of USB devices. In particular, this + * might be needed on Android if you don't have authority to access USB + * devices in general. Setting this option with libusb_set_option is deprecated. * * On Linux, the system device handle must be a valid file descriptor opened * on the device node. @@ -1233,9 +1341,9 @@ void API_EXPORTED libusb_unref_device(libusb_device *dev) * \param dev_handle output location for the returned device handle pointer. Only * populated when the return code is 0. * \returns 0 on success - * \returns LIBUSB_ERROR_NO_MEM on memory allocation failure - * \returns LIBUSB_ERROR_ACCESS if the user has insufficient permissions - * \returns LIBUSB_ERROR_NOT_SUPPORTED if the operation is not supported on this + * \returns \ref LIBUSB_ERROR_NO_MEM on memory allocation failure + * \returns \ref LIBUSB_ERROR_ACCESS if the user has insufficient permissions + * \returns \ref LIBUSB_ERROR_NOT_SUPPORTED if the operation is not supported on this * platform * \returns another LIBUSB_ERROR code on other failure */ @@ -1289,9 +1397,9 @@ int API_EXPORTED libusb_wrap_sys_device(libusb_context *ctx, intptr_t sys_dev, * \param dev_handle output location for the returned device handle pointer. Only * populated when the return code is 0. * \returns 0 on success - * \returns LIBUSB_ERROR_NO_MEM on memory allocation failure - * \returns LIBUSB_ERROR_ACCESS if the user has insufficient permissions - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns \ref LIBUSB_ERROR_NO_MEM on memory allocation failure + * \returns \ref LIBUSB_ERROR_ACCESS if the user has insufficient permissions + * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected * \returns another LIBUSB_ERROR code on other failure */ int API_EXPORTED libusb_open(libusb_device *dev, @@ -1397,20 +1505,22 @@ static void do_close(struct libusb_context *ctx, for_each_transfer_safe(ctx, itransfer, tmp) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + uint32_t state_flags; if (transfer->dev_handle != dev_handle) continue; usbi_mutex_lock(&itransfer->lock); - if (!(itransfer->state_flags & USBI_TRANSFER_DEVICE_DISAPPEARED)) { + state_flags = itransfer->state_flags; + usbi_mutex_unlock(&itransfer->lock); + if (!(state_flags & USBI_TRANSFER_DEVICE_DISAPPEARED)) { usbi_err(ctx, "Device handle closed while transfer was still being processed, but the device is still connected as far as we know"); - if (itransfer->state_flags & USBI_TRANSFER_CANCELLING) + if (state_flags & USBI_TRANSFER_CANCELLING) usbi_warn(ctx, "A cancellation for an in-flight transfer hasn't completed but closing the device handle"); else usbi_err(ctx, "A cancellation hasn't even been scheduled on the transfer for which the device is closing"); } - usbi_mutex_unlock(&itransfer->lock); /* remove from the list of in-flight transfers and make sure * we don't accidentally use the device handle in the future @@ -1424,7 +1534,7 @@ static void do_close(struct libusb_context *ctx, * the device handle is invalid */ usbi_dbg(ctx, "Removed transfer %p from the in-flight list because device handle %p closed", - transfer, dev_handle); + (void *) transfer, (void *) dev_handle); } usbi_mutex_unlock(&ctx->flying_transfers_lock); @@ -1533,7 +1643,7 @@ libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle) * \param config output location for the bConfigurationValue of the active * configuration (only valid for return code 0) * \returns 0 on success - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected * \returns another LIBUSB_ERROR code on other failure */ int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev_handle, @@ -1584,7 +1694,7 @@ int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev_handle, * endpoint halts cleared, toggles reset). * * Not all backends support setting the configuration from user space, which - * will be indicated by the return code LIBUSB_ERROR_NOT_SUPPORTED. As this + * will be indicated by the return code \ref LIBUSB_ERROR_NOT_SUPPORTED. As this * suggests that the platform is handling the device configuration itself, * this error should generally be safe to ignore. * @@ -1615,11 +1725,11 @@ int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev_handle, * wish to activate, or -1 if you wish to put the device in an unconfigured * state * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the requested configuration does not exist - * \returns LIBUSB_ERROR_BUSY if interfaces are currently claimed - * \returns LIBUSB_ERROR_NOT_SUPPORTED if setting or changing the configuration + * \returns \ref LIBUSB_ERROR_NOT_FOUND if the requested configuration does not exist + * \returns \ref LIBUSB_ERROR_BUSY if interfaces are currently claimed + * \returns \ref LIBUSB_ERROR_NOT_SUPPORTED if setting or changing the configuration * is not supported by the backend - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected * \returns another LIBUSB_ERROR code on other failure * \see libusb_set_auto_detach_kernel_driver() */ @@ -1653,10 +1763,10 @@ int API_EXPORTED libusb_set_configuration(libusb_device_handle *dev_handle, * \param interface_number the bInterfaceNumber of the interface you * wish to claim * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the requested interface does not exist - * \returns LIBUSB_ERROR_BUSY if another program or driver has claimed the + * \returns \ref LIBUSB_ERROR_NOT_FOUND if the requested interface does not exist + * \returns \ref LIBUSB_ERROR_BUSY if another program or driver has claimed the * interface - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected * \returns a LIBUSB_ERROR code on other failure * \see libusb_set_auto_detach_kernel_driver() */ @@ -1699,8 +1809,8 @@ int API_EXPORTED libusb_claim_interface(libusb_device_handle *dev_handle, * \param interface_number the bInterfaceNumber of the * previously-claimed interface * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the interface was not claimed - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns \ref LIBUSB_ERROR_NOT_FOUND if the interface was not claimed + * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected * \returns another LIBUSB_ERROR code on other failure * \see libusb_set_auto_detach_kernel_driver() */ @@ -1744,9 +1854,9 @@ int API_EXPORTED libusb_release_interface(libusb_device_handle *dev_handle, * \param alternate_setting the bAlternateSetting of the alternate * setting to activate * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the interface was not claimed, or the + * \returns \ref LIBUSB_ERROR_NOT_FOUND if the interface was not claimed, or the * requested alternate setting does not exist - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected * \returns another LIBUSB_ERROR code on other failure */ int API_EXPORTED libusb_set_interface_alt_setting(libusb_device_handle *dev_handle, @@ -1760,7 +1870,6 @@ int API_EXPORTED libusb_set_interface_alt_setting(libusb_device_handle *dev_hand return LIBUSB_ERROR_INVALID_PARAM; if (!usbi_atomic_load(&dev_handle->dev->attached)) { - usbi_mutex_unlock(&dev_handle->lock); return LIBUSB_ERROR_NO_DEVICE; } @@ -1787,8 +1896,8 @@ int API_EXPORTED libusb_set_interface_alt_setting(libusb_device_handle *dev_hand * \param dev_handle a device handle * \param endpoint the endpoint to clear halt status * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns \ref LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist + * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected * \returns another LIBUSB_ERROR code on other failure */ int API_EXPORTED libusb_clear_halt(libusb_device_handle *dev_handle, @@ -1809,14 +1918,14 @@ int API_EXPORTED libusb_clear_halt(libusb_device_handle *dev_handle, * If the reset fails, the descriptors change, or the previous state cannot be * restored, the device will appear to be disconnected and reconnected. This * means that the device handle is no longer valid (you should close it) and - * rediscover the device. A return code of LIBUSB_ERROR_NOT_FOUND indicates + * rediscover the device. A return code of \ref LIBUSB_ERROR_NOT_FOUND indicates * when this is the case. * * This is a blocking function which usually incurs a noticeable delay. * * \param dev_handle a handle of the device to reset * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if re-enumeration is required, or if the + * \returns \ref LIBUSB_ERROR_NOT_FOUND if re-enumeration is required, or if the * device has been disconnected * \returns another LIBUSB_ERROR code on other failure */ @@ -1881,7 +1990,7 @@ int API_EXPORTED libusb_alloc_streams(libusb_device_handle *dev_handle, * \param dev_handle a device handle * \param endpoints array of endpoints to free streams on * \param num_endpoints length of the endpoints array - * \returns LIBUSB_SUCCESS, or a LIBUSB_ERROR code on failure + * \returns \ref LIBUSB_SUCCESS, or a LIBUSB_ERROR code on failure */ int API_EXPORTED libusb_free_streams(libusb_device_handle *dev_handle, unsigned char *endpoints, int num_endpoints) @@ -1944,7 +2053,7 @@ unsigned char * LIBUSB_CALL libusb_dev_mem_alloc(libusb_device_handle *dev_handl * \param dev_handle a device handle * \param buffer pointer to the previously allocated memory * \param length size of previously allocated memory - * \returns LIBUSB_SUCCESS, or a LIBUSB_ERROR code on failure + * \returns \ref LIBUSB_SUCCESS, or a LIBUSB_ERROR code on failure */ int API_EXPORTED libusb_dev_mem_free(libusb_device_handle *dev_handle, unsigned char *buffer, size_t length) @@ -1966,8 +2075,8 @@ int API_EXPORTED libusb_dev_mem_free(libusb_device_handle *dev_handle, * \param interface_number the interface to check * \returns 0 if no kernel driver is active * \returns 1 if a kernel driver is active - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality + * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns \ref LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality * is not available * \returns another LIBUSB_ERROR code on other failure * \see libusb_detach_kernel_driver() @@ -1997,15 +2106,15 @@ int API_EXPORTED libusb_kernel_driver_active(libusb_device_handle *dev_handle, * * Note that libusb itself also talks to the device through a special kernel * driver, if this driver is already attached to the device, this call will - * not detach it and return LIBUSB_ERROR_NOT_FOUND. + * not detach it and return \ref LIBUSB_ERROR_NOT_FOUND. * * \param dev_handle a device handle * \param interface_number the interface to detach the driver from * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if no kernel driver was active - * \returns LIBUSB_ERROR_INVALID_PARAM if the interface does not exist - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality + * \returns \ref LIBUSB_ERROR_NOT_FOUND if no kernel driver was active + * \returns \ref LIBUSB_ERROR_INVALID_PARAM if the interface does not exist + * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns \ref LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality * is not available * \returns another LIBUSB_ERROR code on other failure * \see libusb_kernel_driver_active() @@ -2036,12 +2145,12 @@ int API_EXPORTED libusb_detach_kernel_driver(libusb_device_handle *dev_handle, * \param dev_handle a device handle * \param interface_number the interface to attach the driver from * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if no kernel driver was active - * \returns LIBUSB_ERROR_INVALID_PARAM if the interface does not exist - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality + * \returns \ref LIBUSB_ERROR_NOT_FOUND if no kernel driver was active + * \returns \ref LIBUSB_ERROR_INVALID_PARAM if the interface does not exist + * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns \ref LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality * is not available - * \returns LIBUSB_ERROR_BUSY if the driver cannot be attached because the + * \returns \ref LIBUSB_ERROR_BUSY if the driver cannot be attached because the * interface is claimed by a program or driver * \returns another LIBUSB_ERROR code on other failure * \see libusb_kernel_driver_active() @@ -2072,14 +2181,14 @@ int API_EXPORTED libusb_attach_kernel_driver(libusb_device_handle *dev_handle, * handles by default. * * On platforms which do not have LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER - * this function will return LIBUSB_ERROR_NOT_SUPPORTED, and libusb will + * this function will return \ref LIBUSB_ERROR_NOT_SUPPORTED, and libusb will * continue as if this function was never called. * * \param dev_handle a device handle * \param enable whether to enable or disable auto kernel driver detachment * - * \returns LIBUSB_SUCCESS on success - * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality + * \returns \ref LIBUSB_SUCCESS on success + * \returns \ref LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality * is not available * \see libusb_claim_interface() * \see libusb_release_interface() @@ -2096,20 +2205,34 @@ int API_EXPORTED libusb_set_auto_detach_kernel_driver( } /** \ingroup libusb_lib - * \deprecated Use libusb_set_option() instead using the - * \ref LIBUSB_OPTION_LOG_LEVEL option. + * Deprecated. Use libusb_set_option() or libusb_init_context() instead, + * with the \ref LIBUSB_OPTION_LOG_LEVEL option. */ void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level) { -#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING) - ctx = usbi_get_context(ctx); - if (!ctx->debug_fixed) { - level = CLAMP(level, LIBUSB_LOG_LEVEL_NONE, LIBUSB_LOG_LEVEL_DEBUG); - ctx->debug = (enum libusb_log_level)level; + libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level); +} + +static void libusb_set_log_cb_internal(libusb_context *ctx, libusb_log_cb cb, + int mode) +{ +#if defined(ENABLE_LOGGING) && (!defined(ENABLE_DEBUG_LOGGING) || !defined(USE_SYSTEM_LOGGING_FACILITY)) +#if !defined(USE_SYSTEM_LOGGING_FACILITY) + if (mode & LIBUSB_LOG_CB_GLOBAL) + log_handler = cb; +#endif +#if !defined(ENABLE_DEBUG_LOGGING) + if (mode & LIBUSB_LOG_CB_CONTEXT) { + ctx = usbi_get_context(ctx); + ctx->log_handler = cb; } #else UNUSED(ctx); - UNUSED(level); +#endif +#else + UNUSED(ctx); + UNUSED(cb); + UNUSED(mode); #endif } @@ -2139,24 +2262,7 @@ void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level) void API_EXPORTED libusb_set_log_cb(libusb_context *ctx, libusb_log_cb cb, int mode) { -#if defined(ENABLE_LOGGING) && (!defined(ENABLE_DEBUG_LOGGING) || !defined(USE_SYSTEM_LOGGING_FACILITY)) -#if !defined(USE_SYSTEM_LOGGING_FACILITY) - if (mode & LIBUSB_LOG_CB_GLOBAL) - log_handler = cb; -#endif -#if !defined(ENABLE_DEBUG_LOGGING) - if (mode & LIBUSB_LOG_CB_CONTEXT) { - ctx = usbi_get_context(ctx); - ctx->log_handler = cb; - } -#else - UNUSED(ctx); -#endif -#else - UNUSED(ctx); - UNUSED(cb); - UNUSED(mode); -#endif + libusb_set_log_cb_internal(ctx, cb, mode); } /** \ingroup libusb_lib @@ -2176,72 +2282,95 @@ void API_EXPORTED libusb_set_log_cb(libusb_context *ctx, libusb_log_cb cb, * \param option which option to set * \param ... any required arguments for the specified option * - * \returns LIBUSB_SUCCESS on success - * \returns LIBUSB_ERROR_INVALID_PARAM if the option or arguments are invalid - * \returns LIBUSB_ERROR_NOT_SUPPORTED if the option is valid but not supported + * \returns \ref LIBUSB_SUCCESS on success + * \returns \ref LIBUSB_ERROR_INVALID_PARAM if the option or arguments are invalid + * \returns \ref LIBUSB_ERROR_NOT_SUPPORTED if the option is valid but not supported * on this platform - * \returns LIBUSB_ERROR_NOT_FOUND if LIBUSB_OPTION_USE_USBDK is valid on this platform but UsbDk is not available + * \returns \ref LIBUSB_ERROR_NOT_FOUND if LIBUSB_OPTION_USE_USBDK is valid on this platform but UsbDk is not available */ -int API_EXPORTED libusb_set_option(libusb_context *ctx, +int API_EXPORTEDV libusb_set_option(libusb_context *ctx, enum libusb_option option, ...) { int arg = 0, r = LIBUSB_SUCCESS; + libusb_log_cb log_cb = NULL; va_list ap; +#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING) + int is_default_context = (NULL == ctx); +#endif va_start(ap, option); + if (LIBUSB_OPTION_LOG_LEVEL == option) { arg = va_arg(ap, int); if (arg < LIBUSB_LOG_LEVEL_NONE || arg > LIBUSB_LOG_LEVEL_DEBUG) { r = LIBUSB_ERROR_INVALID_PARAM; } } - va_end(ap); - - if (LIBUSB_SUCCESS != r) { - return r; + if (LIBUSB_OPTION_LOG_CB == option) { + log_cb = (libusb_log_cb) va_arg(ap, libusb_log_cb); } - if (option >= LIBUSB_OPTION_MAX) { - return LIBUSB_ERROR_INVALID_PARAM; - } + do { + if (LIBUSB_SUCCESS != r) { + break; + } - if (NULL == ctx) { - usbi_mutex_static_lock(&default_context_lock); - default_context_options[option].is_set = 1; - if (LIBUSB_OPTION_LOG_LEVEL == option) { - default_context_options[option].arg.ival = arg; + if (option >= LIBUSB_OPTION_MAX) { + r = LIBUSB_ERROR_INVALID_PARAM; + break; } - usbi_mutex_static_unlock(&default_context_lock); - } - ctx = usbi_get_context(ctx); - if (NULL == ctx) { - return LIBUSB_SUCCESS; - } + if (NULL == ctx) { + usbi_mutex_static_lock(&default_context_lock); + default_context_options[option].is_set = 1; + if (LIBUSB_OPTION_LOG_LEVEL == option) { + default_context_options[option].arg.ival = arg; + } else if (LIBUSB_OPTION_LOG_CB == option) { + default_context_options[option].arg.log_cbval = log_cb; + libusb_set_log_cb_internal(NULL, log_cb, LIBUSB_LOG_CB_GLOBAL); + } + usbi_mutex_static_unlock(&default_context_lock); + } - switch (option) { - case LIBUSB_OPTION_LOG_LEVEL: + ctx = usbi_get_context(ctx); + if (NULL == ctx) + break; + + switch (option) { + case LIBUSB_OPTION_LOG_LEVEL: #if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING) - if (!ctx->debug_fixed) - ctx->debug = (enum libusb_log_level)arg; + if (!ctx->debug_fixed) { + ctx->debug = (enum libusb_log_level)arg; + if (is_default_context) + usbi_atomic_store(&default_debug_level, CLAMP(arg, LIBUSB_LOG_LEVEL_NONE, LIBUSB_LOG_LEVEL_DEBUG)); + } #endif - break; + break; - /* Handle all backend-specific options here */ - case LIBUSB_OPTION_USE_USBDK: - case LIBUSB_OPTION_NO_DEVICE_DISCOVERY: - if (usbi_backend.set_option) - return usbi_backend.set_option(ctx, option, ap); + /* Handle all backend-specific options here */ + case LIBUSB_OPTION_USE_USBDK: + case LIBUSB_OPTION_NO_DEVICE_DISCOVERY: + if (usbi_backend.set_option) { + r = usbi_backend.set_option(ctx, option, ap); + break; + } - return LIBUSB_ERROR_NOT_SUPPORTED; - break; + r = LIBUSB_ERROR_NOT_SUPPORTED; + break; - case LIBUSB_OPTION_MAX: - default: - return LIBUSB_ERROR_INVALID_PARAM; - } + case LIBUSB_OPTION_LOG_CB: + libusb_set_log_cb_internal(ctx, log_cb, LIBUSB_LOG_CB_CONTEXT); + break; - return LIBUSB_SUCCESS;; + case LIBUSB_OPTION_MAX: /* unreachable */ + default: + r = LIBUSB_ERROR_INVALID_PARAM; + } + } while (0); + + va_end(ap); + + return r; } #if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING) @@ -2264,20 +2393,35 @@ static enum libusb_log_level get_env_debug_level(void) } #endif +/** \ingroup libusb_lib + * Deprecated initialization function. Equivalent to calling libusb_init_context with no options. + * + * \see libusb_init_context + */ +int API_EXPORTED libusb_init(libusb_context **ctx) +{ + return libusb_init_context(ctx, NULL, 0); +} + /** \ingroup libusb_lib * Initialize libusb. This function must be called before calling any other * libusb function. * * If you do not provide an output location for a context pointer, a default * context will be created. If there was already a default context, it will - * be reused (and nothing will be initialized/reinitialized). + * be reused (and nothing will be initialized/reinitialized and options will + * be ignored). If num_options is 0 then options is ignored and may be NULL. + * + * Since version 1.0.27, \ref LIBUSB_API_VERSION >= 0x0100010A * * \param ctx Optional output location for context pointer. * Only valid on return code 0. + * \param options Optional array of options to set on the new context. + * \param num_options Number of elements in the options array. * \returns 0 on success, or a LIBUSB_ERROR code on failure * \see libusb_contexts */ -int API_EXPORTED libusb_init(libusb_context **ctx) +int API_EXPORTED libusb_init_context(libusb_context **ctx, const struct libusb_init_option options[], int num_options) { size_t priv_size = usbi_backend.context_priv_size; struct libusb_context *_ctx; @@ -2293,10 +2437,12 @@ int API_EXPORTED libusb_init(libusb_context **ctx) } /* check for first init */ + usbi_mutex_static_lock(&active_contexts_lock); if (!active_contexts_list.next) { list_init(&active_contexts_list); usbi_get_monotonic_time(×tamp_origin); } + usbi_mutex_static_unlock(&active_contexts_lock); _ctx = calloc(1, PTR_ALIGN(sizeof(*_ctx)) + priv_size); if (!_ctx) { @@ -2305,13 +2451,13 @@ int API_EXPORTED libusb_init(libusb_context **ctx) } #if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING) - if (NULL == ctx && default_context_options[LIBUSB_OPTION_LOG_LEVEL].is_set) { - _ctx->debug = default_context_options[LIBUSB_OPTION_LOG_LEVEL].arg.ival; - } else { + _ctx->debug = LIBUSB_LOG_LEVEL_NONE; + if (getenv("LIBUSB_DEBUG")) { _ctx->debug = get_env_debug_level(); - } - if (_ctx->debug != LIBUSB_LOG_LEVEL_NONE) _ctx->debug_fixed = 1; + } else if (default_context_options[LIBUSB_OPTION_LOG_LEVEL].is_set) { + _ctx->debug = default_context_options[LIBUSB_OPTION_LOG_LEVEL].arg.ival; + } #endif usbi_mutex_init(&_ctx->usb_devs_lock); @@ -2324,7 +2470,29 @@ int API_EXPORTED libusb_init(libusb_context **ctx) if (LIBUSB_OPTION_LOG_LEVEL == option || !default_context_options[option].is_set) { continue; } - r = libusb_set_option(_ctx, option); + if (LIBUSB_OPTION_LOG_CB != option) { + r = libusb_set_option(_ctx, option); + } else { + r = libusb_set_option(_ctx, option, default_context_options[option].arg.log_cbval); + } + if (LIBUSB_SUCCESS != r) + goto err_free_ctx; + } + + /* apply any options provided by the user */ + for (int i = 0 ; i < num_options ; ++i) { + switch(options[i].option) { + case LIBUSB_OPTION_LOG_CB: + r = libusb_set_option(_ctx, options[i].option, options[i].value.log_cbval); + break; + + case LIBUSB_OPTION_LOG_LEVEL: + case LIBUSB_OPTION_USE_USBDK: + case LIBUSB_OPTION_NO_DEVICE_DISCOVERY: + case LIBUSB_OPTION_MAX: + default: + r = libusb_set_option(_ctx, options[i].option, options[i].value.ival); + } if (LIBUSB_SUCCESS != r) goto err_free_ctx; } @@ -2333,6 +2501,9 @@ int API_EXPORTED libusb_init(libusb_context **ctx) if (!ctx) { usbi_default_context = _ctx; default_context_refcnt = 1; +#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING) + usbi_atomic_store(&default_debug_level, _ctx->debug); +#endif usbi_dbg(usbi_default_context, "created default context"); } @@ -2360,8 +2531,12 @@ int API_EXPORTED libusb_init(libusb_context **ctx) *ctx = _ctx; if (!usbi_fallback_context) { +#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING) + if (usbi_atomic_load(&default_debug_level) == -1) + usbi_atomic_store(&default_debug_level, _ctx->debug); +#endif usbi_fallback_context = _ctx; - usbi_warn(usbi_fallback_context, "installing new context as implicit default"); + usbi_dbg(usbi_fallback_context, "installing new context as implicit default"); } } @@ -2432,6 +2607,9 @@ void API_EXPORTED libusb_exit(libusb_context *ctx) list_del(&_ctx->list); usbi_mutex_static_unlock(&active_contexts_lock); + /* Exit hotplug before backend dependency */ + usbi_hotplug_exit(_ctx); + if (usbi_backend.exit) usbi_backend.exit(_ctx); @@ -2445,7 +2623,6 @@ void API_EXPORTED libusb_exit(libusb_context *ctx) /* Don't bother with locking after this point because unless there is * an application bug, nobody will be accessing the context. */ - usbi_hotplug_exit(_ctx); usbi_io_exit(_ctx); for_each_device(_ctx, dev) { @@ -2465,7 +2642,7 @@ void API_EXPORTED libusb_exit(libusb_context *ctx) /** \ingroup libusb_misc * Check at runtime if the loaded library has a given capability. - * This call should be performed after \ref libusb_init(), to ensure the + * This call should be performed after \ref libusb_init_context(), to ensure the * backend has updated its capability set. * * \param capability the \ref libusb_capability to check for @@ -2584,13 +2761,14 @@ static void log_v(struct libusb_context *ctx, enum libusb_log_level level, UNUSED(ctx); #else enum libusb_log_level ctx_level; + long default_level_value; - ctx = ctx ? ctx : usbi_default_context; - ctx = ctx ? ctx : usbi_fallback_context; - if (ctx) + if (ctx) { ctx_level = ctx->debug; - else - ctx_level = get_env_debug_level(); + } else { + default_level_value = usbi_atomic_load(&default_debug_level); + ctx_level = default_level_value < 0 ? get_env_debug_level() : (enum libusb_log_level)default_level_value; + } if (ctx_level < level) return; diff --git a/libusb/libusb/descriptor.c b/libusb/libusb/descriptor.c index 253ef1c..4623ad1 100644 --- a/libusb/libusb/descriptor.c +++ b/libusb/libusb/descriptor.c @@ -521,7 +521,7 @@ static int get_config_descriptor(struct libusb_device *dev, uint8_t config_idx, * * This is a non-blocking function; the device descriptor is cached in memory. * - * Note since libusb-1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102, this + * Note since libusb-1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102, this * function always succeeds. * * \param dev the device @@ -548,7 +548,7 @@ int API_EXPORTED libusb_get_device_descriptor(libusb_device *dev, * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() * after use. * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state + * \returns \ref LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state * \returns another LIBUSB_ERROR code on error * \see libusb_get_config_descriptor */ @@ -588,7 +588,7 @@ int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev, * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() * after use. * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist + * \returns \ref LIBUSB_ERROR_NOT_FOUND if the configuration does not exist * \returns another LIBUSB_ERROR code on error * \see libusb_get_active_config_descriptor() * \see libusb_get_config_descriptor_by_value() @@ -634,7 +634,7 @@ int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev, * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() * after use. * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist + * \returns \ref LIBUSB_ERROR_NOT_FOUND if the configuration does not exist * \returns another LIBUSB_ERROR code on error * \see libusb_get_active_config_descriptor() * \see libusb_get_config_descriptor() @@ -699,7 +699,7 @@ void API_EXPORTED libusb_free_config_descriptor( * descriptor. Only valid if 0 was returned. Must be freed with * libusb_free_ss_endpoint_companion_descriptor() after use. * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist + * \returns \ref LIBUSB_ERROR_NOT_FOUND if the configuration does not exist * \returns another LIBUSB_ERROR code on error */ int API_EXPORTED libusb_get_ss_endpoint_companion_descriptor( @@ -840,7 +840,7 @@ static int parse_bos(struct libusb_context *ctx, * \param bos output location for the BOS descriptor. Only valid if 0 was returned. * Must be freed with \ref libusb_free_bos_descriptor() after use. * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the device doesn't have a BOS descriptor + * \returns \ref LIBUSB_ERROR_NOT_FOUND if the device doesn't have a BOS descriptor * \returns another LIBUSB_ERROR code on error */ int API_EXPORTED libusb_get_bos_descriptor(libusb_device_handle *dev_handle, @@ -1070,6 +1070,70 @@ void API_EXPORTED libusb_free_container_id_descriptor( free(container_id); } +/** \ingroup libusb_desc + * Get a platform descriptor + * + * Since version 1.0.27, \ref LIBUSB_API_VERSION >= 0x0100010A + * + * \param ctx the context to operate on, or NULL for the default context + * \param dev_cap Device Capability descriptor with a bDevCapabilityType of + * \ref libusb_capability_type::LIBUSB_BT_PLATFORM_DESCRIPTOR + * LIBUSB_BT_PLATFORM_DESCRIPTOR + * \param platform_descriptor output location for the Platform descriptor. + * Only valid if 0 was returned. Must be freed with + * libusb_free_platform_descriptor() after use. + * \returns 0 on success + * \returns a LIBUSB_ERROR code on error + */ +int API_EXPORTED libusb_get_platform_descriptor(libusb_context *ctx, + struct libusb_bos_dev_capability_descriptor *dev_cap, + struct libusb_platform_descriptor **platform_descriptor) +{ + struct libusb_platform_descriptor *_platform_descriptor; + + if (dev_cap->bDevCapabilityType != LIBUSB_BT_PLATFORM_DESCRIPTOR) { + usbi_err(ctx, "unexpected bDevCapabilityType 0x%x (expected 0x%x)", + dev_cap->bDevCapabilityType, + LIBUSB_BT_PLATFORM_DESCRIPTOR); + return LIBUSB_ERROR_INVALID_PARAM; + } else if (dev_cap->bLength < LIBUSB_BT_PLATFORM_DESCRIPTOR_MIN_SIZE) { + usbi_err(ctx, "short dev-cap descriptor read %u/%d", + dev_cap->bLength, LIBUSB_BT_PLATFORM_DESCRIPTOR_MIN_SIZE); + return LIBUSB_ERROR_IO; + } + + _platform_descriptor = malloc(dev_cap->bLength); + if (!_platform_descriptor) + return LIBUSB_ERROR_NO_MEM; + + parse_descriptor(dev_cap, "bbbbu", _platform_descriptor); + + /* Capability data is located after reserved byte and 128-bit UUID */ + uint8_t* capability_data = dev_cap->dev_capability_data + 1 + 16; + + /* Capability data length is total descriptor length minus initial fields */ + size_t capability_data_length = _platform_descriptor->bLength - (16 + 4); + + memcpy(_platform_descriptor->CapabilityData, capability_data, capability_data_length); + + *platform_descriptor = _platform_descriptor; + return LIBUSB_SUCCESS; +} + +/** \ingroup libusb_desc + * Free a platform descriptor obtained from + * libusb_get_platform_descriptor(). + * It is safe to call this function with a NULL platform_descriptor parameter, + * in which case the function simply returns. + * + * \param platform_descriptor the Platform descriptor to free + */ +void API_EXPORTED libusb_free_platform_descriptor( + struct libusb_platform_descriptor *platform_descriptor) +{ + free(platform_descriptor); +} + /** \ingroup libusb_desc * Retrieve a string descriptor in C style ASCII. * @@ -1086,7 +1150,7 @@ int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev_ha uint8_t desc_index, unsigned char *data, int length) { union usbi_string_desc_buf str; - int r, si, di; + int r; uint16_t langid, wdata; /* Asking for the zero'th index is special - it returns a string @@ -1122,18 +1186,214 @@ int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev_ha else if ((str.desc.bLength & 1) || str.desc.bLength != r) usbi_warn(HANDLE_CTX(dev_handle), "suspicious bLength %u for string descriptor (read %d)", str.desc.bLength, r); - di = 0; - for (si = 2; si < str.desc.bLength; si += 2) { - if (di >= (length - 1)) - break; + /* Stop one byte before the end to leave room for null termination. */ + int dest_max = length - 1; + + /* The descriptor has this number of wide characters */ + int src_max = (str.desc.bLength - 1 - 1) / 2; - wdata = libusb_le16_to_cpu(str.desc.wData[di]); + /* Neither read nor write more than the smallest buffer */ + int idx_max = MIN(dest_max, src_max); + + int idx; + for (idx = 0; idx < idx_max; ++idx) { + wdata = libusb_le16_to_cpu(str.desc.wData[idx]); if (wdata < 0x80) - data[di++] = (unsigned char)wdata; + data[idx] = (unsigned char)wdata; else - data[di++] = '?'; /* non-ASCII */ + data[idx] = '?'; /* non-ASCII */ + } + + data[idx] = 0; /* null-terminate string */ + return idx; +} + +static int parse_iad_array(struct libusb_context *ctx, + struct libusb_interface_association_descriptor_array *iad_array, + const uint8_t *buffer, int size) +{ + uint8_t i; + struct usbi_descriptor_header header; + int consumed = 0; + const uint8_t *buf = buffer; + struct libusb_interface_association_descriptor *iad; + + if (size < LIBUSB_DT_CONFIG_SIZE) { + usbi_err(ctx, "short config descriptor read %d/%d", + size, LIBUSB_DT_CONFIG_SIZE); + return LIBUSB_ERROR_IO; + } + + // First pass: Iterate through desc list, count number of IADs + iad_array->length = 0; + while (consumed < size) { + parse_descriptor(buf, "bb", &header); + if (header.bLength < 2) { + usbi_err(ctx, "invalid descriptor bLength %d", + header.bLength); + return LIBUSB_ERROR_IO; + } + if (header.bDescriptorType == LIBUSB_DT_INTERFACE_ASSOCIATION) + iad_array->length++; + buf += header.bLength; + consumed += header.bLength; + } + + iad_array->iad = NULL; + if (iad_array->length > 0) { + iad = calloc(iad_array->length, sizeof(*iad)); + if (!iad) + return LIBUSB_ERROR_NO_MEM; + + iad_array->iad = iad; + + // Second pass: Iterate through desc list, fill IAD structures + consumed = 0; + i = 0; + while (consumed < size) { + parse_descriptor(buffer, "bb", &header); + if (header.bDescriptorType == LIBUSB_DT_INTERFACE_ASSOCIATION) + parse_descriptor(buffer, "bbbbbbbb", &iad[i++]); + buffer += header.bLength; + consumed += header.bLength; + } } - data[di] = 0; - return di; + return LIBUSB_SUCCESS; +} + +static int raw_desc_to_iad_array(struct libusb_context *ctx, const uint8_t *buf, + int size, struct libusb_interface_association_descriptor_array **iad_array) +{ + struct libusb_interface_association_descriptor_array *_iad_array + = calloc(1, sizeof(*_iad_array)); + int r; + + if (!_iad_array) + return LIBUSB_ERROR_NO_MEM; + + r = parse_iad_array(ctx, _iad_array, buf, size); + if (r < 0) { + usbi_err(ctx, "parse_iad_array failed with error %d", r); + free(_iad_array); + return r; + } + + *iad_array = _iad_array; + return LIBUSB_SUCCESS; +} + +/** \ingroup libusb_desc + * Get an array of interface association descriptors (IAD) for a given + * configuration. + * This is a non-blocking function which does not involve any requests being + * sent to the device. + * + * \param dev a device + * \param config_index the index of the configuration you wish to retrieve the + * IADs for. + * \param iad_array output location for the array of IADs. Only valid if 0 was + * returned. Must be freed with libusb_free_interface_association_descriptors() + * after use. It's possible that a given configuration contains no IADs. In this + * case the iad_array is still output, but will have 'length' field set to 0, and + * iad field set to NULL. + * \returns 0 on success + * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist + * \returns another LIBUSB_ERROR code on error + * \see libusb_get_active_interface_association_descriptors() + */ +int API_EXPORTED libusb_get_interface_association_descriptors(libusb_device *dev, + uint8_t config_index, struct libusb_interface_association_descriptor_array **iad_array) +{ + union usbi_config_desc_buf _config; + uint16_t config_len; + uint8_t *buf; + int r; + + if (!iad_array) + return LIBUSB_ERROR_INVALID_PARAM; + + usbi_dbg(DEVICE_CTX(dev), "IADs for config index %u", config_index); + if (config_index >= dev->device_descriptor.bNumConfigurations) + return LIBUSB_ERROR_NOT_FOUND; + + r = get_config_descriptor(dev, config_index, _config.buf, sizeof(_config.buf)); + if (r < 0) + return r; + + config_len = libusb_le16_to_cpu(_config.desc.wTotalLength); + buf = malloc(config_len); + if (!buf) + return LIBUSB_ERROR_NO_MEM; + + r = get_config_descriptor(dev, config_index, buf, config_len); + if (r >= 0) + r = raw_desc_to_iad_array(DEVICE_CTX(dev), buf, r, iad_array); + + free(buf); + return r; +} + +/** \ingroup libusb_desc + * Get an array of interface association descriptors (IAD) for the currently + * active configuration. + * This is a non-blocking function which does not involve any requests being + * sent to the device. + * + * \param dev a device + * \param iad_array output location for the array of IADs. Only valid if 0 was + * returned. Must be freed with libusb_free_interface_association_descriptors() + * after use. It's possible that a given configuration contains no IADs. In this + * case the iad_array is still output, but will have 'length' field set to 0, and + * iad field set to NULL. + * \returns 0 on success + * \returns LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state + * \returns another LIBUSB_ERROR code on error + * \see libusb_get_interface_association_descriptors + */ +int API_EXPORTED libusb_get_active_interface_association_descriptors(libusb_device *dev, + struct libusb_interface_association_descriptor_array **iad_array) +{ + union usbi_config_desc_buf _config; + uint16_t config_len; + uint8_t *buf; + int r; + + if (!iad_array) + return LIBUSB_ERROR_INVALID_PARAM; + + r = get_active_config_descriptor(dev, _config.buf, sizeof(_config.buf)); + if (r < 0) + return r; + + config_len = libusb_le16_to_cpu(_config.desc.wTotalLength); + buf = malloc(config_len); + if (!buf) + return LIBUSB_ERROR_NO_MEM; + + r = get_active_config_descriptor(dev, buf, config_len); + if (r >= 0) + r = raw_desc_to_iad_array(DEVICE_CTX(dev), buf, r, iad_array); + free(buf); + return r; +} + +/** \ingroup libusb_desc + * Free an array of interface association descriptors (IADs) obtained from + * libusb_get_interface_association_descriptors() or + * libusb_get_active_interface_association_descriptors(). + * It is safe to call this function with a NULL iad_array parameter, in which + * case the function simply returns. + * + * \param iad_array the IAD array to free + */ +void API_EXPORTED libusb_free_interface_association_descriptors( + struct libusb_interface_association_descriptor_array *iad_array) +{ + if (!iad_array) + return; + + if (iad_array->iad) + free((void*)iad_array->iad); + free(iad_array); } diff --git a/libusb/libusb/hotplug.c b/libusb/libusb/hotplug.c index 6b743c7..3c64f69 100644 --- a/libusb/libusb/hotplug.c +++ b/libusb/libusb/hotplug.c @@ -33,7 +33,7 @@ * * \section hotplug_intro Introduction * - * Version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102, has added support + * Version 1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102, has added support * for hotplug events on some platforms (you should test if your platform * supports hotplug notification by calling \ref libusb_has_capability() with * parameter \ref LIBUSB_CAP_HAS_HOTPLUG). @@ -117,7 +117,7 @@ int main (void) { libusb_hotplug_callback_handle callback_handle; int rc; - libusb_init(NULL); + libusb_init_context(NULL, NULL, 0); rc = libusb_hotplug_register_callback(NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0, 0x045a, 0x5005, @@ -311,7 +311,7 @@ void usbi_hotplug_process(struct libusb_context *ctx, struct list_head *hotplug_ for_each_hotplug_cb_safe(ctx, hotplug_cb, next_cb) { if (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE) { usbi_dbg(ctx, "freeing hotplug cb %p with handle %d", - hotplug_cb, hotplug_cb->handle); + (void *) hotplug_cb, hotplug_cb->handle); list_del(&hotplug_cb->list); free(hotplug_cb); } @@ -377,7 +377,8 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx, usbi_mutex_unlock(&ctx->hotplug_cbs_lock); - usbi_dbg(ctx, "new hotplug cb %p with handle %d", hotplug_cb, hotplug_cb->handle); + usbi_dbg(ctx, "new hotplug cb %p with handle %d", + (void *) hotplug_cb, hotplug_cb->handle); if ((flags & LIBUSB_HOTPLUG_ENUMERATE) && (events & LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED)) { ssize_t i, len; diff --git a/libusb/libusb/hotplug.h b/libusb/libusb/hotplug.h deleted file mode 100644 index 161f7e5..0000000 --- a/libusb/libusb/hotplug.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */ -/* - * Hotplug support for libusb - * Copyright © 2012-2013 Nathan Hjelm - * Copyright © 2012-2013 Peter Stuge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef USBI_HOTPLUG_H -#define USBI_HOTPLUG_H - -#include "libusbi.h" - -enum usbi_hotplug_flags { - /* This callback is interested in device arrivals */ - USBI_HOTPLUG_DEVICE_ARRIVED = LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, - - /* This callback is interested in device removals */ - USBI_HOTPLUG_DEVICE_LEFT = LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, - - /* IMPORTANT: The values for the below entries must start *after* - * the highest value of the above entries!!! - */ - - /* The vendor_id field is valid for matching */ - USBI_HOTPLUG_VENDOR_ID_VALID = (1U << 3), - - /* The product_id field is valid for matching */ - USBI_HOTPLUG_PRODUCT_ID_VALID = (1U << 4), - - /* The dev_class field is valid for matching */ - USBI_HOTPLUG_DEV_CLASS_VALID = (1U << 5), - - /* This callback has been unregistered and needs to be freed */ - USBI_HOTPLUG_NEEDS_FREE = (1U << 6), -}; - -/** \ingroup hotplug - * The hotplug callback structure. The user populates this structure with - * libusb_hotplug_prepare_callback() and then calls libusb_hotplug_register_callback() - * to receive notification of hotplug events. - */ -struct libusb_hotplug_callback { - /** Flags that control how this callback behaves */ - uint8_t flags; - - /** Vendor ID to match (if flags says this is valid) */ - uint16_t vendor_id; - - /** Product ID to match (if flags says this is valid) */ - uint16_t product_id; - - /** Device class to match (if flags says this is valid) */ - uint8_t dev_class; - - /** Callback function to invoke for matching event/device */ - libusb_hotplug_callback_fn cb; - - /** Handle for this callback (used to match on deregister) */ - libusb_hotplug_callback_handle handle; - - /** User data that will be passed to the callback function */ - void *user_data; - - /** List this callback is registered in (ctx->hotplug_cbs) */ - struct list_head list; -}; - -struct libusb_hotplug_message { - /** The hotplug event that occurred */ - libusb_hotplug_event event; - - /** The device for which this hotplug event occurred */ - struct libusb_device *device; - - /** List this message is contained in (ctx->hotplug_msgs) */ - struct list_head list; -}; - -#define for_each_hotplug_cb(ctx, c) \ - for_each_helper(c, &(ctx)->hotplug_cbs, struct libusb_hotplug_callback) - -#define for_each_hotplug_cb_safe(ctx, c, n) \ - for_each_safe_helper(c, n, &(ctx)->hotplug_cbs, struct libusb_hotplug_callback) - -void usbi_hotplug_deregister(struct libusb_context *ctx, int forced); -void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev, - libusb_hotplug_event event); -void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev, - libusb_hotplug_event event); - -#endif diff --git a/libusb/libusb/io.c b/libusb/libusb/io.c index 9e3146c..ab84ba6 100644 --- a/libusb/libusb/io.c +++ b/libusb/libusb/io.c @@ -3,8 +3,8 @@ * I/O functions for libusb * Copyright © 2007-2009 Daniel Drake * Copyright © 2001 Johannes Erdfelt - * Copyright © 2019 Nathan Hjelm - * Copyright © 2019 Google LLC. All rights reserved. + * Copyright © 2019-2022 Nathan Hjelm + * Copyright © 2019-2022 Google LLC. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -313,6 +313,10 @@ if (r == 0 && actual_length == sizeof(data)) { * be invoked, and the callback function should check the transfer status to * determine that it was cancelled. * + * On macOS and iOS it is not possible to cancel a single transfer. In this + * case cancelling one transfer on an endpoint will cause all transfers on + * that endpoint to be cancelled. + * * Freeing the transfer after it has been cancelled but before cancellation * has completed will result in undefined behaviour. * @@ -1240,8 +1244,8 @@ void usbi_io_exit(struct libusb_context *ctx) static void calculate_timeout(struct usbi_transfer *itransfer) { - unsigned int timeout = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer)->timeout; + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + unsigned int timeout = transfer->timeout; if (!timeout) { TIMESPEC_CLEAR(&itransfer->timeout); @@ -1285,30 +1289,25 @@ DEFAULT_VISIBILITY struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer( int iso_packets) { - size_t priv_size; - size_t alloc_size; - unsigned char *ptr; - struct usbi_transfer *itransfer; - struct libusb_transfer *transfer; - assert(iso_packets >= 0); if (iso_packets < 0) return NULL; - priv_size = PTR_ALIGN(usbi_backend.transfer_priv_size); - alloc_size = priv_size - + sizeof(struct usbi_transfer) - + sizeof(struct libusb_transfer) - + (sizeof(struct libusb_iso_packet_descriptor) * (size_t)iso_packets); - ptr = calloc(1, alloc_size); + size_t priv_size = PTR_ALIGN(usbi_backend.transfer_priv_size); + size_t usbi_transfer_size = PTR_ALIGN(sizeof(struct usbi_transfer)); + size_t libusb_transfer_size = PTR_ALIGN(sizeof(struct libusb_transfer)); + size_t iso_packets_size = sizeof(struct libusb_iso_packet_descriptor) * (size_t)iso_packets; + size_t alloc_size = priv_size + usbi_transfer_size + libusb_transfer_size + iso_packets_size; + unsigned char *ptr = calloc(1, alloc_size); if (!ptr) return NULL; - itransfer = (struct usbi_transfer *)(ptr + priv_size); + struct usbi_transfer *itransfer = (struct usbi_transfer *)(ptr + priv_size); itransfer->num_iso_packets = iso_packets; itransfer->priv = ptr; usbi_mutex_init(&itransfer->lock); - transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + return transfer; } @@ -1331,31 +1330,26 @@ struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer( */ void API_EXPORTED libusb_free_transfer(struct libusb_transfer *transfer) { - struct usbi_transfer *itransfer; - size_t priv_size; - unsigned char *ptr; - if (!transfer) return; - usbi_dbg(TRANSFER_CTX(transfer), "transfer %p", transfer); + usbi_dbg(TRANSFER_CTX(transfer), "transfer %p", (void *) transfer); if (transfer->flags & LIBUSB_TRANSFER_FREE_BUFFER) free(transfer->buffer); - itransfer = LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer); + struct usbi_transfer *itransfer = LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer); usbi_mutex_destroy(&itransfer->lock); if (itransfer->dev) libusb_unref_device(itransfer->dev); - priv_size = PTR_ALIGN(usbi_backend.transfer_priv_size); - ptr = (unsigned char *)itransfer - priv_size; + unsigned char *ptr = USBI_TRANSFER_TO_TRANSFER_PRIV(itransfer); assert(ptr == itransfer->priv); free(ptr); } /* iterates through the flying transfers, and rearms the timer based on the * next upcoming timeout. - * must be called with flying_list locked. + * NB: flying_transfers_lock must be held when calling this. * returns 0 on success or a LIBUSB_ERROR code on failure. */ #ifdef HAVE_OS_TIMER @@ -1376,7 +1370,8 @@ static int arm_timer_for_next_timeout(struct libusb_context *ctx) /* act on first transfer that has not already been handled */ if (!(itransfer->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT))) { - usbi_dbg(ctx, "next timeout originally %ums", USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer)->timeout); + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + usbi_dbg(ctx, "next timeout originally %ums", transfer->timeout); return usbi_arm_timer(&ctx->timer, cur_ts); } } @@ -1394,7 +1389,8 @@ static inline int arm_timer_for_next_timeout(struct libusb_context *ctx) /* add a transfer to the (timeout-sorted) active transfers list. * This function will return non 0 if fails to update the timer, - * in which case the transfer is *not* on the flying_transfers list. */ + * in which case the transfer is *not* on the flying_transfers list. + * NB: flying_transfers_lock MUST be held when calling this. */ static int add_to_flying_list(struct usbi_transfer *itransfer) { struct usbi_transfer *cur; @@ -1438,8 +1434,9 @@ static int add_to_flying_list(struct usbi_transfer *itransfer) if (first && usbi_using_timer(ctx) && TIMESPEC_IS_SET(timeout)) { /* if this transfer has the lowest timeout of all active transfers, * rearm the timer with this transfer's timeout */ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); usbi_dbg(ctx, "arm timer for timeout in %ums (first in line)", - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer)->timeout); + transfer->timeout); r = usbi_arm_timer(&ctx->timer, timeout); } #else @@ -1455,20 +1452,19 @@ static int add_to_flying_list(struct usbi_transfer *itransfer) /* remove a transfer from the active transfers list. * This function will *always* remove the transfer from the * flying_transfers list. It will return a LIBUSB_ERROR code - * if it fails to update the timer for the next timeout. */ + * if it fails to update the timer for the next timeout. + * NB: flying_transfers_lock MUST be held when calling this. */ static int remove_from_flying_list(struct usbi_transfer *itransfer) { struct libusb_context *ctx = ITRANSFER_CTX(itransfer); int rearm_timer; int r = 0; - usbi_mutex_lock(&ctx->flying_transfers_lock); rearm_timer = (TIMESPEC_IS_SET(&itransfer->timeout) && list_first_entry(&ctx->flying_transfers, struct usbi_transfer, list) == itransfer); list_del(&itransfer->list); if (rearm_timer) r = arm_timer_for_next_timeout(ctx); - usbi_mutex_unlock(&ctx->flying_transfers_lock); return r; } @@ -1479,11 +1475,11 @@ static int remove_from_flying_list(struct usbi_transfer *itransfer) * * \param transfer the transfer to submit * \returns 0 on success - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_BUSY if the transfer has already been submitted. - * \returns LIBUSB_ERROR_NOT_SUPPORTED if the transfer flags are not supported + * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns \ref LIBUSB_ERROR_BUSY if the transfer has already been submitted. + * \returns \ref LIBUSB_ERROR_NOT_SUPPORTED if the transfer flags are not supported * by the operating system. - * \returns LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than + * \returns \ref LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than * the operating system and/or hardware can support (see \ref asynclimits) * \returns another LIBUSB_ERROR code on other failure */ @@ -1500,7 +1496,7 @@ int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer) itransfer->dev = libusb_ref_device(transfer->dev_handle->dev); ctx = HANDLE_CTX(transfer->dev_handle); - usbi_dbg(ctx, "transfer %p", transfer); + usbi_dbg(ctx, "transfer %p", (void *) transfer); /* * Important note on locking, this function takes / releases locks @@ -1562,8 +1558,11 @@ int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer) } usbi_mutex_unlock(&itransfer->lock); - if (r != LIBUSB_SUCCESS) + if (r != LIBUSB_SUCCESS) { + usbi_mutex_lock(&ctx->flying_transfers_lock); remove_from_flying_list(itransfer); + usbi_mutex_unlock(&ctx->flying_transfers_lock); + } return r; } @@ -1584,21 +1583,23 @@ int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer) * \ref libusb_transfer_status::LIBUSB_TRANSFER_CANCELLED * "LIBUSB_TRANSFER_CANCELLED" for each transfer that was cancelled. - * - Calling this function also sends a \c ClearFeature(ENDPOINT_HALT) request - * for the transfer's endpoint. If the device does not handle this request - * correctly, the data toggle bits for the endpoint can be left out of sync - * between host and device, which can have unpredictable results when the - * next data is sent on the endpoint, including data being silently lost. - * A call to \ref libusb_clear_halt will not resolve this situation, since - * that function uses the same request. Therefore, if your program runs on - * Darwin and uses a device that does not correctly implement - * \c ClearFeature(ENDPOINT_HALT) requests, it may only be safe to cancel - * transfers when followed by a device reset using + * - When built for macOS versions prior to 10.5, this function sends a + * \c ClearFeature(ENDPOINT_HALT) request for the transfer's endpoint. + * (Prior to libusb 1.0.27, this request was sent on all Darwin systems.) + * If the device does not handle this request correctly, the data toggle + * bits for the endpoint can be left out of sync between host and device, + * which can have unpredictable results when the next data is sent on + * the endpoint, including data being silently lost. A call to + * \ref libusb_clear_halt will not resolve this situation, since that + * function uses the same request. Therefore, if your program runs on + * macOS < 10.5 (or libusb < 1.0.27), and uses a device that does not + * correctly implement \c ClearFeature(ENDPOINT_HALT) requests, it may + * only be safe to cancel transfers when followed by a device reset using * \ref libusb_reset_device. * * \param transfer the transfer to cancel * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the transfer is not in progress, + * \returns \ref LIBUSB_ERROR_NOT_FOUND if the transfer is not in progress, * already complete, or already cancelled. * \returns a LIBUSB_ERROR code on failure */ @@ -1609,7 +1610,7 @@ int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer) struct libusb_context *ctx = ITRANSFER_CTX(itransfer); int r; - usbi_dbg(ctx, "transfer %p", transfer ); + usbi_dbg(ctx, "transfer %p", (void *) transfer ); usbi_mutex_lock(&itransfer->lock); if (!(itransfer->state_flags & USBI_TRANSFER_IN_FLIGHT) || (itransfer->state_flags & USBI_TRANSFER_CANCELLING)) { @@ -1689,7 +1690,9 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, uint8_t flags; int r; + usbi_mutex_lock(&ctx->flying_transfers_lock); r = remove_from_flying_list(itransfer); + usbi_mutex_unlock(&ctx->flying_transfers_lock); if (r < 0) usbi_err(ctx, "failed to set timer for next timeout"); @@ -1711,9 +1714,13 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, flags = transfer->flags; transfer->status = status; transfer->actual_length = itransfer->transferred; - usbi_dbg(ctx, "transfer %p has callback %p", transfer, transfer->callback); - if (transfer->callback) + usbi_dbg(ctx, "transfer %p has callback %p", + (void *) transfer, transfer->callback); + if (transfer->callback) { + libusb_lock_event_waiters (ctx); transfer->callback(transfer); + libusb_unlock_event_waiters(ctx); + } /* transfer might have been freed by the above call, do not use from * this point. */ if (flags & LIBUSB_TRANSFER_FREE_TRANSFER) @@ -2013,7 +2020,7 @@ void API_EXPORTED libusb_unlock_event_waiters(libusb_context *ctx) * indicates unlimited timeout. * \returns 0 after a transfer completes or another thread stops event handling * \returns 1 if the timeout expired - * \returns LIBUSB_ERROR_INVALID_PARAM if timeval is invalid + * \returns \ref LIBUSB_ERROR_INVALID_PARAM if timeval is invalid * \ref libusb_mtasync */ int API_EXPORTED libusb_wait_for_event(libusb_context *ctx, struct timeval *tv) @@ -2037,6 +2044,7 @@ int API_EXPORTED libusb_wait_for_event(libusb_context *ctx, struct timeval *tv) return 0; } +// NB: flying_transfers_lock must be held when calling this static void handle_timeout(struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = @@ -2052,6 +2060,7 @@ static void handle_timeout(struct usbi_transfer *itransfer) "async cancel failed %d", r); } +// NB: flying_transfers_lock must be held when calling this static void handle_timeouts_locked(struct libusb_context *ctx) { struct timespec systime; @@ -2332,7 +2341,7 @@ static int get_next_timeout(libusb_context *ctx, struct timeval *tv, * timeval struct for non-blocking mode * \param completed pointer to completion integer to check, or NULL * \returns 0 on success - * \returns LIBUSB_ERROR_INVALID_PARAM if timeval is invalid + * \returns \ref LIBUSB_ERROR_INVALID_PARAM if timeval is invalid * \returns another LIBUSB_ERROR code on other failure * \ref libusb_mtasync */ @@ -2474,7 +2483,7 @@ int API_EXPORTED libusb_handle_events_completed(libusb_context *ctx, * \param tv the maximum time to block waiting for events, or zero for * non-blocking mode * \returns 0 on success - * \returns LIBUSB_ERROR_INVALID_PARAM if timeval is invalid + * \returns \ref LIBUSB_ERROR_INVALID_PARAM if timeval is invalid * \returns another LIBUSB_ERROR code on other failure * \ref libusb_mtasync */ @@ -2558,7 +2567,7 @@ int API_EXPORTED libusb_pollfds_handle_timeouts(libusb_context *ctx) * \param tv output location for a relative time against the current * clock in which libusb must be called into in order to process timeout events * \returns 0 if there are no pending timeouts, 1 if a timeout was returned, - * or LIBUSB_ERROR_OTHER on failure + * or \ref LIBUSB_ERROR_OTHER on failure */ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx, struct timeval *tv) @@ -2619,11 +2628,11 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx, * To remove notifiers, pass NULL values for the function pointers. * * Note that file descriptors may have been added even before you register - * these notifiers (e.g. at libusb_init() time). + * these notifiers (e.g. at libusb_init_context() time). * * Additionally, note that the removal notifier may be called during * libusb_exit() (e.g. when it is closing file descriptors that were opened - * and added to the poll set at libusb_init() time). If you don't want this, + * and added to the poll set at libusb_init_context() time). If you don't want this, * remove the notifiers immediately before calling libusb_exit(). * * \param ctx the context to operate on, or NULL for the default context @@ -2827,7 +2836,8 @@ void usbi_handle_disconnect(struct libusb_device_handle *dev_handle) to_cancel = NULL; usbi_mutex_lock(&ctx->flying_transfers_lock); for_each_transfer(ctx, cur) { - if (USBI_TRANSFER_TO_LIBUSB_TRANSFER(cur)->dev_handle == dev_handle) { + struct libusb_transfer *cur_transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(cur); + if (cur_transfer->dev_handle == dev_handle) { usbi_mutex_lock(&cur->lock); if (cur->state_flags & USBI_TRANSFER_IN_FLIGHT) to_cancel = cur; @@ -2842,8 +2852,9 @@ void usbi_handle_disconnect(struct libusb_device_handle *dev_handle) if (!to_cancel) break; + struct libusb_transfer *transfer_to_cancel = USBI_TRANSFER_TO_LIBUSB_TRANSFER(to_cancel); usbi_dbg(ctx, "cancelling transfer %p from disconnect", - USBI_TRANSFER_TO_LIBUSB_TRANSFER(to_cancel)); + (void *) transfer_to_cancel); usbi_mutex_lock(&to_cancel->lock); usbi_backend.clear_transfer_priv(to_cancel); diff --git a/libusb/libusb/libusb.h b/libusb/libusb/libusb.h index 2592ea7..f4e9203 100644 --- a/libusb/libusb/libusb.h +++ b/libusb/libusb/libusb.h @@ -3,9 +3,9 @@ * Copyright © 2001 Johannes Erdfelt * Copyright © 2007-2008 Daniel Drake * Copyright © 2012 Pete Batard - * Copyright © 2012-2018 Nathan Hjelm + * Copyright © 2012-2023 Nathan Hjelm * Copyright © 2014-2020 Chris Dickens - * For more information, please visit: http://libusb.info + * For more information, please visit: https://libusb.info * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -50,9 +50,9 @@ typedef SSIZE_T ssize_t; #include #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) -#define ZERO_SIZED_ARRAY /* [] - valid C99 code */ +#define LIBUSB_FLEXIBLE_ARRAY /* [] - valid C99 code */ #else -#define ZERO_SIZED_ARRAY 0 /* [0] - non-standard, but usually working code */ +#define LIBUSB_FLEXIBLE_ARRAY 0 /* [0] - non-standard, but usually working code */ #endif /* __STDC_VERSION__ */ /* 'interface' might be defined as a macro on Windows, so we need to @@ -74,6 +74,8 @@ typedef SSIZE_T ssize_t; #define LIBUSB_DEPRECATED_FOR(f) __attribute__ ((deprecated ("Use " #f " instead"))) #elif defined(__GNUC__) && (__GNUC__ >= 3) #define LIBUSB_DEPRECATED_FOR(f) __attribute__ ((deprecated)) +#elif defined(_MSC_VER) +#define LIBUSB_DEPRECATED_FOR(f) __declspec(deprecated("Use " #f " instead")) #else #define LIBUSB_DEPRECATED_FOR(f) #endif /* __GNUC__ */ @@ -118,20 +120,25 @@ typedef SSIZE_T ssize_t; */ #if defined(_WIN32) || defined(__CYGWIN__) #define LIBUSB_CALL WINAPI +#define LIBUSB_CALLV WINAPIV #else #define LIBUSB_CALL +#define LIBUSB_CALLV #endif /* _WIN32 || __CYGWIN__ */ /** \def LIBUSB_API_VERSION * \ingroup libusb_misc * libusb's API version. * - * Since version 1.0.13, to help with feature detection, libusb defines + * Since version 1.0.18, to help with feature detection, libusb defines * a LIBUSB_API_VERSION macro that gets increased every time there is a * significant change to the API, such as the introduction of a new call, * the definition of a new macro/enum member, or any other element that * libusb applications may want to detect at compilation time. * + * Between versions 1.0.13 and 1.0.17 (inclusive) the older spelling of + * LIBUSBX_API_VERSION was used. + * * The macro is typically used in an application as follows: * \code * #if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01001234) @@ -141,10 +148,34 @@ typedef SSIZE_T ssize_t; * * Internally, LIBUSB_API_VERSION is defined as follows: * (libusb major << 24) | (libusb minor << 16) | (16 bit incremental) + * + * The incremental component has changed as follows: + *
    + *
  • libusbx version 1.0.13: LIBUSBX_API_VERSION = 0x01000100 + *
  • libusbx version 1.0.14: LIBUSBX_API_VERSION = 0x010000FF + *
  • libusbx version 1.0.15: LIBUSBX_API_VERSION = 0x01000101 + *
  • libusbx version 1.0.16: LIBUSBX_API_VERSION = 0x01000102 + *
  • libusbx version 1.0.17: LIBUSBX_API_VERSION = 0x01000102 + *
  • libusb version 1.0.18: LIBUSB_API_VERSION = 0x01000102 + *
  • libusb version 1.0.19: LIBUSB_API_VERSION = 0x01000103 + *
  • libusb version 1.0.20: LIBUSB_API_VERSION = 0x01000104 + *
  • libusb version 1.0.21: LIBUSB_API_VERSION = 0x01000105 + *
  • libusb version 1.0.22: LIBUSB_API_VERSION = 0x01000106 + *
  • libusb version 1.0.23: LIBUSB_API_VERSION = 0x01000107 + *
  • libusb version 1.0.24: LIBUSB_API_VERSION = 0x01000108 + *
  • libusb version 1.0.25: LIBUSB_API_VERSION = 0x01000109 + *
  • libusb version 1.0.26: LIBUSB_API_VERSION = 0x01000109 + *
  • libusb version 1.0.27: LIBUSB_API_VERSION = 0x0100010A + *
*/ -#define LIBUSB_API_VERSION 0x01000109 +#define LIBUSB_API_VERSION 0x0100010A -/* The following is kept for compatibility, but will be deprecated in the future */ +/** \def LIBUSBX_API_VERSION + * \ingroup libusb_misc + * + * This is the older spelling, kept for backwards compatibility of code + * needing to test for older library versions where the newer spelling + * did not exist. */ #define LIBUSBX_API_VERSION LIBUSB_API_VERSION #if defined(__cplusplus) @@ -265,6 +296,10 @@ enum libusb_descriptor_type { /** Endpoint descriptor. See libusb_endpoint_descriptor. */ LIBUSB_DT_ENDPOINT = 0x05, + /** Interface Association Descriptor. + * See libusb_interface_association_descriptor */ + LIBUSB_DT_INTERFACE_ASSOCIATION = 0x0b, + /** BOS descriptor */ LIBUSB_DT_BOS = 0x0f, @@ -305,6 +340,7 @@ enum libusb_descriptor_type { #define LIBUSB_BT_USB_2_0_EXTENSION_SIZE 7 #define LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE 10 #define LIBUSB_BT_CONTAINER_ID_SIZE 20 +#define LIBUSB_BT_PLATFORM_DESCRIPTOR_MIN_SIZE 20 /* We unwrap the BOS => define its max size */ #define LIBUSB_DT_BOS_MAX_SIZE \ @@ -523,7 +559,10 @@ enum libusb_bos_type { LIBUSB_BT_SS_USB_DEVICE_CAPABILITY = 0x03, /** Container ID type */ - LIBUSB_BT_CONTAINER_ID = 0x04 + LIBUSB_BT_CONTAINER_ID = 0x04, + + /** Platform descriptor */ + LIBUSB_BT_PLATFORM_DESCRIPTOR = 0x05 }; /** \ingroup libusb_desc @@ -628,6 +667,65 @@ struct libusb_endpoint_descriptor { int extra_length; }; +/** \ingroup libusb_desc + * A structure representing the standard USB interface association descriptor. + * This descriptor is documented in section 9.6.4 of the USB 3.0 specification. + * All multiple-byte fields are represented in host-endian format. + */ +struct libusb_interface_association_descriptor { + /** Size of this descriptor (in bytes) */ + uint8_t bLength; + + /** Descriptor type. Will have value + * \ref libusb_descriptor_type::LIBUSB_DT_INTERFACE_ASSOCIATION + * LIBUSB_DT_INTERFACE_ASSOCIATION in this context. */ + uint8_t bDescriptorType; + + /** Interface number of the first interface that is associated + * with this function */ + uint8_t bFirstInterface; + + /** Number of contiguous interfaces that are associated with + * this function */ + uint8_t bInterfaceCount; + + /** USB-IF class code for this function. + * A value of zero is not allowed in this descriptor. + * If this field is 0xff, the function class is vendor-specific. + * All other values are reserved for assignment by the USB-IF. + */ + uint8_t bFunctionClass; + + /** USB-IF subclass code for this function. + * If this field is not set to 0xff, all values are reserved + * for assignment by the USB-IF + */ + uint8_t bFunctionSubClass; + + /** USB-IF protocol code for this function. + * These codes are qualified by the values of the bFunctionClass + * and bFunctionSubClass fields. + */ + uint8_t bFunctionProtocol; + + /** Index of string descriptor describing this function */ + uint8_t iFunction; +}; + +/** \ingroup libusb_desc + * Structure containing an array of 0 or more interface association + * descriptors + */ +struct libusb_interface_association_descriptor_array { + /** Array of interface association descriptors. The size of this array + * is determined by the length field. + */ + const struct libusb_interface_association_descriptor *iad; + + /** Number of interface association descriptors contained. Read-only. */ + int length; +}; + /** \ingroup libusb_desc * A structure representing the standard USB interface descriptor. This * descriptor is documented in section 9.6.5 of the USB 3.0 specification. @@ -786,7 +884,7 @@ struct libusb_bos_dev_capability_descriptor { uint8_t bDevCapabilityType; /** Device Capability data (bLength - 3 bytes) */ - uint8_t dev_capability_data[ZERO_SIZED_ARRAY]; + uint8_t dev_capability_data[LIBUSB_FLEXIBLE_ARRAY]; }; /** \ingroup libusb_desc @@ -811,7 +909,7 @@ struct libusb_bos_descriptor { uint8_t bNumDeviceCaps; /** bNumDeviceCap Device Capability Descriptors */ - struct libusb_bos_dev_capability_descriptor *dev_capability[ZERO_SIZED_ARRAY]; + struct libusb_bos_dev_capability_descriptor *dev_capability[LIBUSB_FLEXIBLE_ARRAY]; }; /** \ingroup libusb_desc @@ -908,6 +1006,34 @@ struct libusb_container_id_descriptor { uint8_t ContainerID[16]; }; +/** \ingroup libusb_desc + * A structure representing a Platform descriptor. + * This descriptor is documented in section 9.6.2.4 of the USB 3.2 specification. + */ +struct libusb_platform_descriptor { + /** Size of this descriptor (in bytes) */ + uint8_t bLength; + + /** Descriptor type. Will have value + * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY + * LIBUSB_DT_DEVICE_CAPABILITY in this context. */ + uint8_t bDescriptorType; + + /** Capability type. Will have value + * \ref libusb_capability_type::LIBUSB_BT_PLATFORM_DESCRIPTOR + * LIBUSB_BT_CONTAINER_ID in this context. */ + uint8_t bDevCapabilityType; + + /** Reserved field */ + uint8_t bReserved; + + /** 128 bit UUID */ + uint8_t PlatformCapabilityUUID[16]; + + /** Capability data (bLength - 20) */ + uint8_t CapabilityData[LIBUSB_FLEXIBLE_ARRAY]; +}; + /** \ingroup libusb_asyncio * Setup packet for control transfers. */ #if defined(_MSC_VER) || defined(__WATCOMC__) @@ -982,7 +1108,7 @@ struct libusb_version { * libusb_exit() will not destroy resources that the other user is still * using. * - * Sessions are created by libusb_init() and destroyed through libusb_exit(). + * Sessions are created by libusb_init_context() and destroyed through libusb_exit(). * If your application is guaranteed to only ever include a single libusb * user (i.e. you), you do not have to worry about contexts: pass NULL in * every function call where a context is required, and the default context @@ -1187,7 +1313,8 @@ enum libusb_transfer_flags { * * This flag is currently only supported on Linux. * On other systems, libusb_submit_transfer() will return - * LIBUSB_ERROR_NOT_SUPPORTED for every transfer where this flag is set. + * \ref LIBUSB_ERROR_NOT_SUPPORTED for every transfer where this + * flag is set. * * Available since libusb-1.0.9. */ @@ -1284,7 +1411,7 @@ struct libusb_transfer { int num_iso_packets; /** Isochronous packet descriptors, for isochronous transfers only. */ - struct libusb_iso_packet_descriptor iso_packet_desc[ZERO_SIZED_ARRAY]; + struct libusb_iso_packet_descriptor iso_packet_desc[LIBUSB_FLEXIBLE_ARRAY]; }; /** \ingroup libusb_misc @@ -1345,6 +1472,79 @@ enum libusb_log_cb_mode { LIBUSB_LOG_CB_CONTEXT = (1 << 1) }; +/** \ingroup libusb_lib + * Available option values for libusb_set_option() and libusb_init_context(). + */ +enum libusb_option { + /** Set the log message verbosity. + * + * This option must be provided an argument of type \ref libusb_log_level. + * The default level is LIBUSB_LOG_LEVEL_NONE, which means no messages are ever + * printed. If you choose to increase the message verbosity level, ensure + * that your application does not close the stderr file descriptor. + * + * You are advised to use level LIBUSB_LOG_LEVEL_WARNING. libusb is conservative + * with its message logging and most of the time, will only log messages that + * explain error conditions and other oddities. This will help you debug + * your software. + * + * If the LIBUSB_DEBUG environment variable was set when libusb was + * initialized, this option does nothing: the message verbosity is fixed + * to the value in the environment variable. + * + * If libusb was compiled without any message logging, this option does + * nothing: you'll never get any messages. + * + * If libusb was compiled with verbose debug message logging, this option + * does nothing: you'll always get messages from all levels. + */ + LIBUSB_OPTION_LOG_LEVEL = 0, + + /** Use the UsbDk backend for a specific context, if available. + * + * This option should be set at initialization with libusb_init_context() + * otherwise unspecified behavior may occur. + * + * Only valid on Windows. Ignored on all other platforms. + */ + LIBUSB_OPTION_USE_USBDK = 1, + + /** Do not scan for devices + * + * With this option set, libusb will skip scanning devices in + * libusb_init_context(). + * + * Hotplug functionality will also be deactivated. + * + * The option is useful in combination with libusb_wrap_sys_device(), + * which can access a device directly without prior device scanning. + * + * This is typically needed on Android, where access to USB devices + * is limited. + * + * This option should only be used with libusb_init_context() + * otherwise unspecified behavior may occur. + * + * Only valid on Linux. Ignored on all other platforms. + */ + LIBUSB_OPTION_NO_DEVICE_DISCOVERY = 2, + +#define LIBUSB_OPTION_WEAK_AUTHORITY LIBUSB_OPTION_NO_DEVICE_DISCOVERY + + /** Set the context log callback function. + * + * Set the log callback function either on a context or globally. This + * option must be provided an argument of type \ref libusb_log_cb. + * Using this option with a NULL context is equivalent to calling + * libusb_set_log_cb() with mode \ref LIBUSB_LOG_CB_GLOBAL. + * Using it with a non-NULL context is equivalent to calling + * libusb_set_log_cb() with mode \ref LIBUSB_LOG_CB_CONTEXT. + */ + LIBUSB_OPTION_LOG_CB = 3, + + LIBUSB_OPTION_MAX = 4 +}; + /** \ingroup libusb_lib * Callback function for handling log messages. * \param ctx the context which is related to the log message, or NULL if it @@ -1359,10 +1559,25 @@ enum libusb_log_cb_mode { typedef void (LIBUSB_CALL *libusb_log_cb)(libusb_context *ctx, enum libusb_log_level level, const char *str); +/** \ingroup libusb_lib + * Structure used for setting options through \ref libusb_init_context. + * + */ +struct libusb_init_option { + /** Which option to set */ + enum libusb_option option; + /** An integer value used by the option (if applicable). */ + union { + int ival; + libusb_log_cb log_cbval; + } value; +}; + int LIBUSB_CALL libusb_init(libusb_context **ctx); +int LIBUSB_CALL libusb_init_context(libusb_context **ctx, const struct libusb_init_option options[], int num_options); void LIBUSB_CALL libusb_exit(libusb_context *ctx); -LIBUSB_DEPRECATED_FOR(libusb_set_option) void LIBUSB_CALL libusb_set_debug(libusb_context *ctx, int level); +/* may be deprecated in the future in favor of lubusb_init_context()+libusb_set_option() */ void LIBUSB_CALL libusb_set_log_cb(libusb_context *ctx, libusb_log_cb cb, int mode); const struct libusb_version * LIBUSB_CALL libusb_get_version(void); int LIBUSB_CALL libusb_has_capability(uint32_t capability); @@ -1415,6 +1630,11 @@ int LIBUSB_CALL libusb_get_container_id_descriptor(libusb_context *ctx, struct libusb_container_id_descriptor **container_id); void LIBUSB_CALL libusb_free_container_id_descriptor( struct libusb_container_id_descriptor *container_id); +int LIBUSB_CALL libusb_get_platform_descriptor(libusb_context *ctx, + struct libusb_bos_dev_capability_descriptor *dev_cap, + struct libusb_platform_descriptor **platform_descriptor); +void LIBUSB_CALL libusb_free_platform_descriptor( + struct libusb_platform_descriptor *platform_descriptor); uint8_t LIBUSB_CALL libusb_get_bus_number(libusb_device *dev); uint8_t LIBUSB_CALL libusb_get_port_number(libusb_device *dev); int LIBUSB_CALL libusb_get_port_numbers(libusb_device *dev, uint8_t *port_numbers, int port_numbers_len); @@ -1427,6 +1647,15 @@ int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev, unsigned char endpoint); int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev, unsigned char endpoint); +int LIBUSB_CALL libusb_get_max_alt_packet_size(libusb_device *dev, + int interface_number, int alternate_setting, unsigned char endpoint); + +int LIBUSB_CALL libusb_get_interface_association_descriptors(libusb_device *dev, + uint8_t config_index, struct libusb_interface_association_descriptor_array **iad_array); +int LIBUSB_CALL libusb_get_active_interface_association_descriptors(libusb_device *dev, + struct libusb_interface_association_descriptor_array **iad_array); +void LIBUSB_CALL libusb_free_interface_association_descriptors( + struct libusb_interface_association_descriptor_array *iad_array); int LIBUSB_CALL libusb_wrap_sys_device(libusb_context *ctx, intptr_t sys_dev, libusb_device_handle **dev_handle); int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **dev_handle); @@ -2036,7 +2265,7 @@ typedef int (LIBUSB_CALL *libusb_hotplug_callback_fn)(libusb_context *ctx, * \param[in] cb_fn the function to be invoked on a matching event/device * \param[in] user_data user data to pass to the callback function * \param[out] callback_handle pointer to store the handle of the allocated callback (can be NULL) - * \returns LIBUSB_SUCCESS on success LIBUSB_ERROR code on failure + * \returns \ref LIBUSB_SUCCESS on success LIBUSB_ERROR code on failure */ int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context *ctx, int events, int flags, @@ -2069,67 +2298,7 @@ void LIBUSB_CALL libusb_hotplug_deregister_callback(libusb_context *ctx, void * LIBUSB_CALL libusb_hotplug_get_user_data(libusb_context *ctx, libusb_hotplug_callback_handle callback_handle); -/** \ingroup libusb_lib - * Available option values for libusb_set_option(). - */ -enum libusb_option { - /** Set the log message verbosity. - * - * The default level is LIBUSB_LOG_LEVEL_NONE, which means no messages are ever - * printed. If you choose to increase the message verbosity level, ensure - * that your application does not close the stderr file descriptor. - * - * You are advised to use level LIBUSB_LOG_LEVEL_WARNING. libusb is conservative - * with its message logging and most of the time, will only log messages that - * explain error conditions and other oddities. This will help you debug - * your software. - * - * If the LIBUSB_DEBUG environment variable was set when libusb was - * initialized, this function does nothing: the message verbosity is fixed - * to the value in the environment variable. - * - * If libusb was compiled without any message logging, this function does - * nothing: you'll never get any messages. - * - * If libusb was compiled with verbose debug message logging, this function - * does nothing: you'll always get messages from all levels. - */ - LIBUSB_OPTION_LOG_LEVEL = 0, - - /** Use the UsbDk backend for a specific context, if available. - * - * This option should be set immediately after calling libusb_init(), otherwise - * unspecified behavior may occur. - * - * Only valid on Windows. - */ - LIBUSB_OPTION_USE_USBDK = 1, - - /** Do not scan for devices - * - * With this option set, libusb will skip scanning devices in - * libusb_init(). Must be set before calling libusb_init(). - * - * Hotplug functionality will also be deactivated. - * - * The option is useful in combination with libusb_wrap_sys_device(), - * which can access a device directly without prior device scanning. - * - * This is typically needed on Android, where access to USB devices - * is limited. - * - * For LIBUSB_API_VERSION 0x01000108 it was called LIBUSB_OPTION_WEAK_AUTHORITY - * - * Only valid on Linux. - */ - LIBUSB_OPTION_NO_DEVICE_DISCOVERY = 2, - -#define LIBUSB_OPTION_WEAK_AUTHORITY LIBUSB_OPTION_NO_DEVICE_DISCOVERY - - LIBUSB_OPTION_MAX = 3 -}; - -int LIBUSB_CALL libusb_set_option(libusb_context *ctx, enum libusb_option option, ...); +int LIBUSB_CALLV libusb_set_option(libusb_context *ctx, enum libusb_option option, ...); #ifdef _MSC_VER #pragma warning(pop) diff --git a/libusb/libusb/libusbi.h b/libusb/libusb/libusbi.h index b1fc88c..3b0c610 100644 --- a/libusb/libusb/libusbi.h +++ b/libusb/libusb/libusbi.h @@ -73,7 +73,7 @@ #endif /* The following is used to silence warnings for unused variables */ -#if defined(UNREFERENCED_PARAMETER) +#if defined(UNREFERENCED_PARAMETER) && !defined(__GNUC__) #define UNUSED(var) UNREFERENCED_PARAMETER(var) #else #define UNUSED(var) do { (void)(var); } while(0) @@ -128,6 +128,7 @@ typedef atomic_long usbi_atomic_t; * return_type LIBUSB_CALL function_name(params); */ #define API_EXPORTED LIBUSB_CALL DEFAULT_VISIBILITY +#define API_EXPORTEDV LIBUSB_CALLV DEFAULT_VISIBILITY #ifdef __cplusplus extern "C" { @@ -321,10 +322,10 @@ void usbi_log(struct libusb_context *ctx, enum libusb_log_level level, #else /* ENABLE_LOGGING */ -#define usbi_err(ctx, ...) UNUSED(ctx) -#define usbi_warn(ctx, ...) UNUSED(ctx) -#define usbi_info(ctx, ...) UNUSED(ctx) -#define usbi_dbg(ctx, ...) do {} while (0) +#define usbi_err(ctx, ...) do { (void)(ctx); } while(0) +#define usbi_warn(ctx, ...) do { (void)(ctx); } while(0) +#define usbi_info(ctx, ...) do { (void)(ctx); } while(0) +#define usbi_dbg(ctx, ...) do { (void)(ctx); } while(0) #endif /* ENABLE_LOGGING */ @@ -379,7 +380,7 @@ struct libusb_context { struct list_head flying_transfers; /* Note paths taking both this and usbi_transfer->lock must always * take this lock first */ - usbi_mutex_t flying_transfers_lock; + usbi_mutex_t flying_transfers_lock; /* for flying_transfers and timeout_flags */ #if !defined(PLATFORM_WINDOWS) /* user callbacks for pollfd changes */ @@ -533,7 +534,7 @@ static inline void usbi_localize_device_descriptor(struct libusb_device_descript desc->bcdDevice = libusb_le16_to_cpu(desc->bcdDevice); } -#ifdef HAVE_CLOCK_GETTIME +#if defined(HAVE_CLOCK_GETTIME) && !defined(__APPLE__) static inline void usbi_get_monotonic_time(struct timespec *tp) { ASSERT_EQ(clock_gettime(CLOCK_MONOTONIC, tp), 0); @@ -562,8 +563,11 @@ void usbi_get_real_time(struct timespec *tp); * 2. struct usbi_transfer * 3. struct libusb_transfer (which includes iso packets) [variable size] * - * from a libusb_transfer, you can get the usbi_transfer by rewinding the - * appropriate number of bytes. + * You can convert between them with the macros: + * TRANSFER_PRIV_TO_USBI_TRANSFER + * USBI_TRANSFER_TO_TRANSFER_PRIV + * USBI_TRANSFER_TO_LIBUSB_TRANSFER + * LIBUSB_TRANSFER_TO_USBI_TRANSFER */ struct usbi_transfer { @@ -574,7 +578,7 @@ struct usbi_transfer { int transferred; uint32_t stream_id; uint32_t state_flags; /* Protected by usbi_transfer->lock */ - uint32_t timeout_flags; /* Protected by the flying_stransfers_lock */ + uint32_t timeout_flags; /* Protected by the flying_transfers_lock */ /* The device reference is held until destruction for logging * even after dev_handle is set to NULL. */ @@ -616,10 +620,21 @@ enum usbi_transfer_timeout_flags { USBI_TRANSFER_TIMED_OUT = 1U << 2, }; +#define TRANSFER_PRIV_TO_USBI_TRANSFER(transfer_priv) \ + ((struct usbi_transfer *) \ + ((unsigned char *)(transfer_priv) \ + + PTR_ALIGN(sizeof(*transfer_priv)))) + +#define USBI_TRANSFER_TO_TRANSFER_PRIV(itransfer) \ + ((unsigned char *) \ + ((unsigned char *)(itransfer) \ + - PTR_ALIGN(usbi_backend.transfer_priv_size))) + #define USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer) \ ((struct libusb_transfer *) \ ((unsigned char *)(itransfer) \ + PTR_ALIGN(sizeof(struct usbi_transfer)))) + #define LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer) \ ((struct usbi_transfer *) \ ((unsigned char *)(transfer) \ @@ -678,7 +693,7 @@ struct usbi_interface_descriptor { struct usbi_string_descriptor { uint8_t bLength; uint8_t bDescriptorType; - uint16_t wData[ZERO_SIZED_ARRAY]; + uint16_t wData[LIBUSB_FLEXIBLE_ARRAY]; } LIBUSB_PACKED; struct usbi_bos_descriptor { @@ -813,6 +828,7 @@ struct usbi_option { int is_set; union { int ival; + libusb_log_cb log_cbval; } arg; }; @@ -891,7 +907,7 @@ static inline void *usbi_get_transfer_priv(struct usbi_transfer *itransfer) struct discovered_devs { size_t len; size_t capacity; - struct libusb_device *devices[ZERO_SIZED_ARRAY]; + struct libusb_device *devices[LIBUSB_FLEXIBLE_ARRAY]; }; struct discovered_devs *discovered_devs_append( @@ -1180,6 +1196,8 @@ struct usbi_os_backend { * claiming, no other drivers/applications can use the interface because * we now "own" it. * + * This function gets called with dev_handle->lock locked! + * * Return: * - 0 on success * - LIBUSB_ERROR_NOT_FOUND if the interface does not exist @@ -1199,6 +1217,8 @@ struct usbi_os_backend { * You will only ever be asked to release an interface which was * successfully claimed earlier. * + * This function gets called with dev_handle->lock locked! + * * Return: * - 0 on success * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it @@ -1335,7 +1355,7 @@ struct usbi_os_backend { * * This function must not block. * - * This function gets called with the flying_transfers_lock locked! + * This function gets called with itransfer->lock locked! * * Return: * - 0 on success @@ -1349,6 +1369,8 @@ struct usbi_os_backend { * This function must not block. The transfer cancellation must complete * later, resulting in a call to usbi_handle_transfer_cancellation() * from the context of handle_events. + * + * This function gets called with itransfer->lock locked! */ int (*cancel_transfer)(struct usbi_transfer *itransfer); diff --git a/libusb/libusb/os/events_posix.c b/libusb/libusb/os/events_posix.c index 715a2d5..4056dae 100644 --- a/libusb/libusb/os/events_posix.c +++ b/libusb/libusb/os/events_posix.c @@ -28,6 +28,31 @@ #ifdef HAVE_TIMERFD #include #endif + +#ifdef __EMSCRIPTEN__ +/* On Emscripten `pipe` does not conform to the spec and does not block + * until events are available, which makes it unusable for event system + * and often results in deadlocks when `pipe` is in a loop like it is + * in libusb. + * + * Therefore use a custom event system based on browser event emitters. */ +#include +#include +#include + +EM_ASYNC_JS(void, em_libusb_wait_async, (const _Atomic int* ptr, int expected_value, int timeout), { + await Atomics.waitAsync(HEAP32, ptr >> 2, expected_value, timeout).value; +}); + +static void em_libusb_wait(const _Atomic int *ptr, int expected_value, int timeout) +{ + if (emscripten_is_main_runtime_thread()) { + em_libusb_wait_async(ptr, expected_value, timeout); + } else { + emscripten_atomic_wait_u32((int*)ptr, expected_value, 1000000LL * timeout); + } +} +#endif #include #ifdef HAVE_EVENTFD @@ -131,6 +156,10 @@ void usbi_signal_event(usbi_event_t *event) r = write(EVENT_WRITE_FD(event), &dummy, sizeof(dummy)); if (r != sizeof(dummy)) usbi_warn(NULL, "event write failed"); +#ifdef __EMSCRIPTEN__ + event->has_event = 1; + emscripten_atomic_notify(&event->has_event, EMSCRIPTEN_NOTIFY_ALL_WAITERS); +#endif } void usbi_clear_event(usbi_event_t *event) @@ -141,6 +170,9 @@ void usbi_clear_event(usbi_event_t *event) r = read(EVENT_READ_FD(event), &dummy, sizeof(dummy)); if (r != sizeof(dummy)) usbi_warn(NULL, "event read failed"); +#ifdef __EMSCRIPTEN__ + event->has_event = 0; +#endif } #ifdef HAVE_TIMERFD @@ -223,6 +255,14 @@ int usbi_wait_for_events(struct libusb_context *ctx, int internal_fds, num_ready; usbi_dbg(ctx, "poll() %u fds with timeout in %dms", (unsigned int)nfds, timeout_ms); +#ifdef __EMSCRIPTEN__ + // Emscripten's poll doesn't actually block, so we need to use an out-of-band + // waiting signal. + em_libusb_wait(&ctx->event.has_event, 0, timeout_ms); + // Emscripten ignores timeout_ms, but set it to 0 for future-proofing in case + // they ever implement real poll. + timeout_ms = 0; +#endif num_ready = poll(fds, nfds, timeout_ms); usbi_dbg(ctx, "poll() returned %d", num_ready); if (num_ready == 0) { diff --git a/libusb/libusb/os/events_posix.h b/libusb/libusb/os/events_posix.h index d81b5c4..4bd7f0f 100644 --- a/libusb/libusb/os/events_posix.h +++ b/libusb/libusb/os/events_posix.h @@ -36,6 +36,9 @@ typedef struct usbi_event { #else typedef struct usbi_event { int pipefd[2]; +#ifdef __EMSCRIPTEN__ + _Atomic int has_event; +#endif } usbi_event_t; #define USBI_EVENT_OS_HANDLE(e) ((e)->pipefd[0]) #define USBI_EVENT_POLL_EVENTS POLLIN diff --git a/libusb/libusb/os/linux_usbfs.c b/libusb/libusb/os/linux_usbfs.c index 285d9ca..ed8597b 100644 --- a/libusb/libusb/os/linux_usbfs.c +++ b/libusb/libusb/os/linux_usbfs.c @@ -95,9 +95,6 @@ static int sysfs_available = -1; /* how many times have we initted (and not exited) ? */ static int init_count = 0; -/* have no authority to operate usb device directly */ -static int no_enumeration = 0; - /* Serialize scan-devices, event-thread, and poll */ usbi_mutex_static_t linux_hotplug_lock = USBI_MUTEX_INITIALIZER; @@ -119,6 +116,11 @@ struct config_descriptor { size_t actual_len; }; +struct linux_context_priv { + /* no enumeration or hot-plug detection */ + int no_device_discovery; +}; + struct linux_device_priv { char *sysfs_dir; void *descriptors; @@ -187,10 +189,10 @@ static int get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent) int fd; if (usbdev_names) - sprintf(path, USBDEV_PATH "/usbdev%u.%u", + snprintf(path, sizeof(path), USBDEV_PATH "/usbdev%u.%u", dev->bus_number, dev->device_address); else - sprintf(path, USB_DEVTMPFS_PATH "/%03u/%03u", + snprintf(path, sizeof(path), USB_DEVTMPFS_PATH "/%03u/%03u", dev->bus_number, dev->device_address); fd = open(path, mode | O_CLOEXEC); @@ -354,6 +356,7 @@ static int op_init(struct libusb_context *ctx) struct kernel_version kversion; const char *usbfs_path; int r; + struct linux_context_priv *cpriv = usbi_get_context_priv(ctx); if (get_kernel_version(ctx, &kversion) < 0) return LIBUSB_ERROR_OTHER; @@ -397,7 +400,7 @@ static int op_init(struct libusb_context *ctx) } } - if (no_enumeration) { + if (cpriv->no_device_discovery) { return LIBUSB_SUCCESS; } @@ -421,9 +424,9 @@ static int op_init(struct libusb_context *ctx) static void op_exit(struct libusb_context *ctx) { - UNUSED(ctx); + struct linux_context_priv *cpriv = usbi_get_context_priv(ctx); - if (no_enumeration) { + if (cpriv->no_device_discovery) { return; } @@ -436,12 +439,13 @@ static void op_exit(struct libusb_context *ctx) static int op_set_option(struct libusb_context *ctx, enum libusb_option option, va_list ap) { - UNUSED(ctx); UNUSED(ap); if (option == LIBUSB_OPTION_NO_DEVICE_DISCOVERY) { - usbi_dbg(ctx, "no enumeration will be performed"); - no_enumeration = 1; + struct linux_context_priv *cpriv = usbi_get_context_priv(ctx); + + usbi_dbg(ctx, "no device discovery will be performed"); + cpriv->no_device_discovery = 1; return LIBUSB_SUCCESS; } @@ -597,7 +601,7 @@ int linux_get_device_address(struct libusb_context *ctx, int detached, char proc_path[32]; /* try to retrieve the device node from fd */ - sprintf(proc_path, "/proc/self/fd/%d", fd); + snprintf(proc_path, sizeof(proc_path), "/proc/self/fd/%d", fd); r = readlink(proc_path, fd_path, PATH_MAX - 1); if (r > 0) { fd_path[r] = '\0'; @@ -648,7 +652,7 @@ static int seek_to_next_config(struct libusb_context *ctx, while (len > 0) { if (len < 2) { - usbi_err(ctx, "short descriptor read %zu/2", len); + usbi_err(ctx, "remaining descriptor length too small %zu/2", len); return LIBUSB_ERROR_IO; } @@ -656,6 +660,11 @@ static int seek_to_next_config(struct libusb_context *ctx, if (header->bDescriptorType == LIBUSB_DT_CONFIG) return offset; + if (header->bLength < 2) { + usbi_err(ctx, "invalid descriptor bLength %hhu", header->bLength); + return LIBUSB_ERROR_IO; + } + if (len < header->bLength) { usbi_err(ctx, "bLength overflow by %zu bytes", (size_t)header->bLength - len); @@ -1079,8 +1088,9 @@ static int linux_get_parent_info(struct libusb_device *dev, const char *sysfs_di goto retry; } - usbi_dbg(ctx, "dev %p (%s) has parent %p (%s) port %u", dev, sysfs_dir, - dev->parent_dev, parent_sysfs_dir, dev->port_number); + usbi_dbg(ctx, "dev %p (%s) has parent %p (%s) port %u", + (void *) dev, sysfs_dir, (void *) dev->parent_dev, + parent_sysfs_dir, dev->port_number); free(parent_sysfs_dir); @@ -1188,7 +1198,7 @@ static int usbfs_scan_busdir(struct libusb_context *ctx, uint8_t busnum) struct dirent *entry; int r = LIBUSB_ERROR_IO; - sprintf(dirpath, USB_DEVTMPFS_PATH "/%03u", busnum); + snprintf(dirpath, sizeof(dirpath), USB_DEVTMPFS_PATH "/%03u", busnum); usbi_dbg(ctx, "%s", dirpath); dir = opendir(dirpath); if (!dir) { @@ -2801,6 +2811,7 @@ const struct usbi_os_backend usbi_backend = { .handle_events = op_handle_events, + .context_priv_size = sizeof(struct linux_context_priv), .device_priv_size = sizeof(struct linux_device_priv), .device_handle_priv_size = sizeof(struct linux_device_handle_priv), .transfer_priv_size = sizeof(struct linux_transfer_priv), diff --git a/libusb/libusb/os/threads_posix.c b/libusb/libusb/os/threads_posix.c index 0e0e221..0079fd5 100644 --- a/libusb/libusb/os/threads_posix.c +++ b/libusb/libusb/os/threads_posix.c @@ -32,8 +32,6 @@ #elif defined(__NetBSD__) # include #elif defined(__OpenBSD__) -# define _BSD_SOURCE -# include # include #elif defined(__sun__) # include @@ -109,9 +107,7 @@ unsigned int usbi_get_tid(void) #elif defined(__NetBSD__) tid = _lwp_self(); #elif defined(__OpenBSD__) - /* The following only works with OpenBSD > 5.1 as it requires - * real thread support. For 5.1 and earlier, -1 is returned. */ - tid = syscall(SYS_getthrid); + tid = getthrid(); #elif defined(__sun__) tid = _lwp_self(); #else diff --git a/libusb/libusb/strerror.c b/libusb/libusb/strerror.c index 9445fa9..eb35503 100644 --- a/libusb/libusb/strerror.c +++ b/libusb/libusb/strerror.c @@ -28,7 +28,7 @@ *
  • Download the latest \c strerror.c from:
    * https://raw.github.com/libusb/libusb/master/libusb/strerror.c
  • *
  • Open the file in an UTF-8 capable editor
  • - *
  • Add the 2 letter ISO 639-1 + *
  • Add the 2 letter ISO 639-1 * code for your locale at the end of \c usbi_locale_supported[]
    * Eg. for Chinese, you would add "zh" so that: * \code... usbi_locale_supported[] = { "en", "nl", "fr" };\endcode @@ -160,7 +160,7 @@ static const char * const (*usbi_error_strings)[LIBUSB_ERROR_COUNT] = &usbi_loca * If libusb_setlocale() is not called, all messages will be in English. * * The following functions return translatable strings: libusb_strerror(). - * Note that the libusb log messages controlled through libusb_set_debug() + * Note that the libusb log messages controlled through LIBUSB_OPTION_LOG_LEVEL * are not translated, they are always in English. * * For POSIX UTF-8 environments if you want libusb to follow the standard @@ -169,9 +169,9 @@ static const char * const (*usbi_error_strings)[LIBUSB_ERROR_COUNT] = &usbi_loca * * \param locale locale-string in the form of lang[_country_region][.codeset] * or lang[-region], where lang is a 2 letter ISO 639-1 code - * \returns LIBUSB_SUCCESS on success - * \returns LIBUSB_ERROR_INVALID_PARAM if the locale doesn't meet the requirements - * \returns LIBUSB_ERROR_NOT_FOUND if the requested language is not supported + * \returns \ref LIBUSB_SUCCESS on success + * \returns \ref LIBUSB_ERROR_INVALID_PARAM if the locale doesn't meet the requirements + * \returns \ref LIBUSB_ERROR_NOT_FOUND if the requested language is not supported * \returns a LIBUSB_ERROR code on other errors */ diff --git a/libusb/libusb/sync.c b/libusb/libusb/sync.c index 1fa1f0b..146cce2 100644 --- a/libusb/libusb/sync.c +++ b/libusb/libusb/sync.c @@ -34,10 +34,15 @@ static void LIBUSB_CALL sync_transfer_cb(struct libusb_transfer *transfer) { + usbi_dbg(TRANSFER_CTX(transfer), "actual_length=%d", transfer->actual_length); + int *completed = transfer->user_data; *completed = 1; - usbi_dbg(TRANSFER_CTX(transfer), "actual_length=%d", transfer->actual_length); - /* caller interprets result and frees transfer */ + /* + * Right after setting 'completed', another thread might free the transfer, so don't + * access it beyond this point. The instantiating thread (not necessarily the + * current one) interprets the result and frees the transfer. + */ } static void sync_transfer_wait_for_completion(struct libusb_transfer *transfer) @@ -85,12 +90,12 @@ static void sync_transfer_wait_for_completion(struct libusb_transfer *transfer) * before giving up due to no response being received. For an unlimited * timeout, use value 0. * \returns on success, the number of bytes actually transferred - * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out - * \returns LIBUSB_ERROR_PIPE if the control request was not supported by the + * \returns \ref LIBUSB_ERROR_TIMEOUT if the transfer timed out + * \returns \ref LIBUSB_ERROR_PIPE if the control request was not supported by the * device - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_BUSY if called from event handling context - * \returns LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than + * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns \ref LIBUSB_ERROR_BUSY if called from event handling context + * \returns \ref LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than * the operating system and/or hardware can support (see \ref asynclimits) * \returns another LIBUSB_ERROR code on other failures */ @@ -260,14 +265,14 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle, * timeout, use value 0. * * \returns 0 on success (and populates transferred) - * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out (and populates + * \returns \ref LIBUSB_ERROR_TIMEOUT if the transfer timed out (and populates * transferred) - * \returns LIBUSB_ERROR_PIPE if the endpoint halted - * \returns LIBUSB_ERROR_OVERFLOW if the device offered more data, see + * \returns \ref LIBUSB_ERROR_PIPE if the endpoint halted + * \returns \ref LIBUSB_ERROR_OVERFLOW if the device offered more data, see * \ref libusb_packetoverflow - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_BUSY if called from event handling context - * \returns LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than + * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns \ref LIBUSB_ERROR_BUSY if called from event handling context + * \returns \ref LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than * the operating system and/or hardware can support (see \ref asynclimits) * \returns another LIBUSB_ERROR code on other failures */ @@ -315,13 +320,13 @@ int API_EXPORTED libusb_bulk_transfer(libusb_device_handle *dev_handle, * timeout, use value 0. * * \returns 0 on success (and populates transferred) - * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out - * \returns LIBUSB_ERROR_PIPE if the endpoint halted - * \returns LIBUSB_ERROR_OVERFLOW if the device offered more data, see + * \returns \ref LIBUSB_ERROR_TIMEOUT if the transfer timed out + * \returns \ref LIBUSB_ERROR_PIPE if the endpoint halted + * \returns \ref LIBUSB_ERROR_OVERFLOW if the device offered more data, see * \ref libusb_packetoverflow - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_BUSY if called from event handling context - * \returns LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than + * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns \ref LIBUSB_ERROR_BUSY if called from event handling context + * \returns \ref LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than * the operating system and/or hardware can support (see \ref asynclimits) * \returns another LIBUSB_ERROR code on other error */ diff --git a/libusb/libusb/version.h b/libusb/libusb/version.h index fe95d84..ca9df20 100644 --- a/libusb/libusb/version.h +++ b/libusb/libusb/version.h @@ -7,7 +7,7 @@ #define LIBUSB_MINOR 0 #endif #ifndef LIBUSB_MICRO -#define LIBUSB_MICRO 26 +#define LIBUSB_MICRO 27 #endif #ifndef LIBUSB_NANO #define LIBUSB_NANO 0 diff --git a/libusb/libusb/version_nano.h b/libusb/libusb/version_nano.h index dbd5d5f..a6165f3 100644 --- a/libusb/libusb/version_nano.h +++ b/libusb/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 11724 +#define LIBUSB_NANO 11882