diff options
Diffstat (limited to 'lib/libusb')
-rw-r--r-- | lib/libusb/libusb-1.0.pc.in | 2 | ||||
-rw-r--r-- | lib/libusb/libusb.3 | 81 | ||||
-rw-r--r-- | lib/libusb/libusb.h | 58 | ||||
-rw-r--r-- | lib/libusb/libusb01.c | 2 | ||||
-rw-r--r-- | lib/libusb/libusb10.c | 261 | ||||
-rw-r--r-- | lib/libusb/libusb10.h | 49 | ||||
-rw-r--r-- | lib/libusb/libusb10_desc.c | 62 | ||||
-rw-r--r-- | lib/libusb/libusb10_hotplug.c | 205 | ||||
-rw-r--r-- | lib/libusb/libusb10_io.c | 52 | ||||
-rw-r--r-- | lib/libusb/libusb20.3 | 1 | ||||
-rw-r--r-- | lib/libusb/libusb20.h | 1 | ||||
-rw-r--r-- | lib/libusb/libusb20_desc.h | 6 |
12 files changed, 661 insertions, 119 deletions
diff --git a/lib/libusb/libusb-1.0.pc.in b/lib/libusb/libusb-1.0.pc.in index 7dbf746e773e..3a2f27cc52b8 100644 --- a/lib/libusb/libusb-1.0.pc.in +++ b/lib/libusb/libusb-1.0.pc.in @@ -6,6 +6,6 @@ includedir=@includedir@ Name: libusb-1.0 Description: Library that abstracts ways to access USB devices (v1.0) -Version: 1.0.13 +Version: 1.0.16 Libs: -L${libdir} -lusb Cflags: -I${includedir} diff --git a/lib/libusb/libusb.3 b/lib/libusb/libusb.3 index 43afa55380a8..607a7f645d95 100644 --- a/lib/libusb/libusb.3 +++ b/lib/libusb/libusb.3 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd January, 26, 2023 +.Dd July 9, 2025 .Dt LIBUSB 3 .Os .Sh NAME @@ -106,6 +106,19 @@ Get the ASCII representation of the error given by the argument. This function does not return NULL. .Pp +.Ft int +.Fn libusb_setlocale "const char *locale" +Set locale for the error message when using +.Fn libusb_strerror +to +.Ft locale . +Note other +.Nm +implementations only support the first two bytes, that means +.Ql en-US +is equivalent to +.Ql en-CA . +.Pp .Ft const char * .Fn libusb_error_name "int code" Get the ASCII representation of the error enum given by the @@ -117,7 +130,7 @@ This function does not return NULL. .Fn libusb_set_debug "libusb_context *ctx" "int level" Set the debug level to .Fa level . -.Pp +.Sh DEVICE HANDLING AND ENUMERATION .Ft ssize_t .Fn libusb_get_device_list "libusb_context *ctx" "libusb_device ***list" Populate @@ -196,6 +209,14 @@ Decrement the reference counter of the device .Fa dev . .Pp .Ft int +.Fn libusb_wrap_sys_device "libusb_context *ctx" "intptr_t sys_dev" "libusb_device_handle **dev_handle" +This function creates a libusb handler from a previously opened fd +.Fa sys_dev . +This function is provided for compatibility and is currently unimplemented. +It always returns +.Dv LIBUSB_ERROR_NOT_SUPPORTED . +.Pp +.Ft int .Fn libusb_open "libusb_device *dev" "libusb_device_handle **devh" Open a device and obtain a device_handle. Returns 0 on success, @@ -220,6 +241,11 @@ Close a device handle. Get the device contained by devh. Returns NULL on error. .Pp +.Ft libusb_device * +.Fn libusb_get_parent "libusb_device *dev" +Get dev's parent device. +Returns NULL if the device has no parent (i.e. is a root device). +.Pp .Ft int .Fn libusb_get_configuration "libusb_device_handle *devh" "int *config" Returns the value of the current configuration. @@ -348,6 +374,23 @@ argument is non-zero the feature is enabled. Else disabled. Returns 0 on success and a LIBUSB_ERROR code on failure. +.Pp +.Ft unsigned char * +.Fn libusb_dev_mem_alloc "libusb_device_handle *devh" +This function attempts to allocate a DMA memory block from the given +.Fa devh +so that we can enjoy the zero-copy transfer from kernel. +This function is provided for compatibility and is currently unimplemented and always returns NULL. +.Pp +.Ft int +.Fn libusb_dev_mem_free "libusb_device_handle *devh" "unsigned char *buffer" "size_t size" +This function frees the DMA memory in +.Fa devh +from the given +.Fa buffer +with +.Fa size . +This function is unimplemented and always returns LIBUSB_ERROR_NOT_SUPPORTED. .Sh USB DESCRIPTORS .Ft int .Fn libusb_get_device_descriptor "libusb_device *dev" "libusb_device_descriptor *desc" @@ -501,6 +544,21 @@ libusb_free_container_id_descriptor function. .Fn libusb_free_container_id_descriptor "struct libusb_container_id_descriptor *container_id" This function is NULL safe and frees a parsed container ID descriptor given by .Fa container_id . +.Pp +.Ft int +.Fn libusb_get_platform_descriptor "struct libusb_context *ctx" "struct libusb_bos_dev_capability_descriptor *dev_cap" "struct libusb_platform_descriptor **platform_descriptor" +This function parses the platform descriptor from the descriptor given by +.Fa dev_cap +and stores a pointer to the parsed descriptor into +.Fa platform_descriptor . +Returns zero on success and a LIBUSB_ERROR code on failure. +On success the parsed platform descriptor must be freed using the +libusb_free_platform_descriptor function. +.Pp +.Ft void +.Fn libusb_free_platform_descriptor "struct libusb_platform_descriptor *platform_descriptor" +This function is NULL safe and frees a parsed platform descriptor given by +.Fa platform_descriptor . .Sh USB ASYNCHRONOUS I/O .Ft struct libusb_transfer * .Fn libusb_alloc_transfer "int iso_packets" @@ -699,6 +757,14 @@ another thread is already doing so. Must be called with the event lock held. .Pp .Ft int +.Fn libusb_pollfds_handle_timeouts "libusb_context *ctx" +This function determines whether applications maintaining libusb events using +.Fn libusb_get_pollfds +are responsible for handling timeout events themselves. +Returns 1 if libusb handles the timeout internally, 0 if the application +needs to set a dedicated timer to handle it. +.Pp +.Ft int .Fn libusb_get_next_timeout "libusb_context *ctx" "struct timeval *tv" Determine the next internal timeout that libusb needs to handle. Returns 0 @@ -757,6 +823,17 @@ argument can be either of LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED or LIBUSB_HOTPLUG_ .Ft void .Fn libusb_hotplug_deregister_callback "libusb_context *ctx" "libusb_hotplug_callback_handle handle" This function unregisters a hotplug filter. +.Pp +.Ft void +.Fn libusb_free_pollfds "const struct libusb_pollfd **pollfds" +This function releases the memory storage in +.Fa pollfds , +and is safe to call when the argument is NULL. +.Pp void * +.Fn libusb_hotplug_get_user_data "struct libusb_context *ctx" "libusb_hotplug_callback_handle callback_handle" +This function returns the user data from the opaque +.Fa callback_handle , +or returns NULL if no matching handle is found. .Sh LIBUSB VERSION 0.1 COMPATIBILITY The library is also compliant with LibUSB version 0.1.12. .Pp diff --git a/lib/libusb/libusb.h b/lib/libusb/libusb.h index 022b5562a819..623b56fb273b 100644 --- a/lib/libusb/libusb.h +++ b/lib/libusb/libusb.h @@ -66,6 +66,7 @@ enum libusb_class_code { LIBUSB_CLASS_PERSONAL_HEALTHCARE = 15, LIBUSB_CLASS_DIAGNOSTIC_DEVICE = 0xdc, LIBUSB_CLASS_WIRELESS = 0xe0, + LIBUSB_CLASS_MISCELLANEOUS = 0xef, LIBUSB_CLASS_APPLICATION = 0xfe, LIBUSB_CLASS_VENDOR_SPEC = 0xff, }; @@ -106,6 +107,7 @@ enum libusb_device_capability_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 #define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f #define LIBUSB_ENDPOINT_DIR_MASK 0x80 @@ -122,6 +124,7 @@ enum libusb_transfer_type { LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1, LIBUSB_TRANSFER_TYPE_BULK = 2, LIBUSB_TRANSFER_TYPE_INTERRUPT = 3, + LIBUSB_TRANSFER_TYPE_BULK_STREAM = 4, }; enum libusb_standard_request { @@ -171,11 +174,23 @@ enum libusb_iso_usage_type { LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 2, }; +enum libusb_usb_2_0_extension_attributes { + LIBUSB_BM_LPM_SUPPORT = 0x2, +}; + +enum libusb_supported_speed { + LIBUSB_LOW_SPEED_OPERATION = (1 << 0), + LIBUSB_FULL_SPEED_OPERATION = (1 << 1), + LIBUSB_HIGH_SPEED_OPERATION = (1 << 2), + LIBUSB_SUPER_SPEED_OPERATION = (1 << 3), +}; + enum libusb_bos_type { LIBUSB_BT_WIRELESS_USB_DEVICE_CAPABILITY = 1, LIBUSB_BT_USB_2_0_EXTENSION = 2, LIBUSB_BT_SS_USB_DEVICE_CAPABILITY = 3, LIBUSB_BT_CONTAINER_ID = 4, + LIBUSB_BT_PLATFORM_DESCRIPTOR = 5, }; enum libusb_capability { @@ -210,12 +225,15 @@ enum libusb_error { LIBUSB_ERROR_OTHER = -99, }; +#define LIBUSB_ERROR_COUNT 14 + enum libusb_speed { LIBUSB_SPEED_UNKNOWN = 0, LIBUSB_SPEED_LOW = 1, LIBUSB_SPEED_FULL = 2, LIBUSB_SPEED_HIGH = 3, LIBUSB_SPEED_SUPER = 4, + LIBUSB_SPEED_SUPER_PLUS = 5, }; enum libusb_transfer_status { @@ -242,17 +260,6 @@ enum libusb_log_level { LIBUSB_LOG_LEVEL_DEBUG }; -/* XXX */ -/* libusb_set_debug should take parameters from libusb_log_level - * above according to - * http://libusb.sourceforge.net/api-1.0/group__lib.html - */ -enum libusb_debug_level { - LIBUSB_DEBUG_NO=0, - LIBUSB_DEBUG_FUNCTION=1, - LIBUSB_DEBUG_TRANSFER=2, -}; - #define LIBUSB_HOTPLUG_MATCH_ANY -1 typedef enum { @@ -417,7 +424,10 @@ typedef struct libusb_bos_descriptor { uint8_t bLength; uint8_t bDescriptorType; uint16_t wTotalLength; - uint8_t bNumDeviceCapabilities; +#ifndef bNumDeviceCapabilities +#define bNumDeviceCapabilities bNumDeviceCaps +#endif + uint8_t bNumDeviceCaps; struct libusb_usb_2_0_device_capability_descriptor *usb_2_0_ext_cap; struct libusb_ss_usb_device_capability_descriptor *ss_usb_cap; struct libusb_bos_dev_capability_descriptor **dev_capability; @@ -438,6 +448,15 @@ typedef struct libusb_container_id_descriptor { uint8_t ContainerID[16]; } libusb_container_id_descriptor __aligned(sizeof(void *)); +typedef struct libusb_platform_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t bReserved; + uint8_t PlatformCapabilityUUID[16]; + uint8_t CapabilityData[]; +} libusb_platform_descriptor __aligned(sizeof(void *)); + typedef struct libusb_control_setup { uint8_t bmRequestType; uint8_t bRequest; @@ -482,6 +501,7 @@ int libusb_init(libusb_context ** context); int libusb_init_context(libusb_context **, const struct libusb_init_option [], int num_options); void libusb_exit(struct libusb_context *ctx); int libusb_has_capability(uint32_t capability); +int libusb_setlocale(const char *locale); /* Device handling and enumeration */ @@ -498,10 +518,12 @@ int libusb_get_max_packet_size(libusb_device * dev, uint8_t endpoint); int libusb_get_max_iso_packet_size(libusb_device * dev, uint8_t endpoint); libusb_device *libusb_ref_device(libusb_device * dev); void libusb_unref_device(libusb_device * dev); +int libusb_wrap_sys_device(libusb_context *ctx, intptr_t sys_dev, libusb_device_handle **dev_handle); int libusb_open(libusb_device * dev, libusb_device_handle ** devh); libusb_device_handle *libusb_open_device_with_vid_pid(libusb_context * ctx, uint16_t vendor_id, uint16_t product_id); void libusb_close(libusb_device_handle * devh); libusb_device *libusb_get_device(libusb_device_handle * devh); +libusb_device *libusb_get_parent(libusb_device * dev); int libusb_get_configuration(libusb_device_handle * devh, int *config); int libusb_set_configuration(libusb_device_handle * devh, int configuration); int libusb_claim_interface(libusb_device_handle * devh, int interface_number); @@ -516,6 +538,9 @@ int libusb_detach_kernel_driver(libusb_device_handle * devh, int interface); int libusb_attach_kernel_driver(libusb_device_handle * devh, int interface); int libusb_set_auto_detach_kernel_driver(libusb_device_handle *dev, int enable); int libusb_set_interface_alt_setting(libusb_device_handle * devh, int interface_number, int alternate_setting); +unsigned char *libusb_dev_mem_alloc(libusb_device_handle *devh); +int libusb_dev_mem_free(libusb_device_handle *devh, unsigned char *buffer, + size_t size); /* USB Descriptors */ @@ -540,6 +565,8 @@ int libusb_get_ss_usb_device_capability_descriptor(struct libusb_context *ctx, s void libusb_free_ss_usb_device_capability_descriptor(struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_capability); int libusb_get_container_id_descriptor(struct libusb_context *ctx, struct libusb_bos_dev_capability_descriptor *dev_cap, struct libusb_container_id_descriptor **container_id); void libusb_free_container_id_descriptor(struct libusb_container_id_descriptor *container_id); +int libusb_get_platform_descriptor(libusb_context *ctx, struct libusb_bos_dev_capability_descriptor *dev_cap, struct libusb_platform_descriptor **platform_descriptor); +void libusb_free_platform_descriptor(struct libusb_platform_descriptor *platform_descriptor); /* Asynchronous device I/O */ @@ -555,6 +582,7 @@ struct libusb_control_setup *libusb_control_transfer_get_setup(struct libusb_tra void libusb_fill_control_setup(uint8_t *buf, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength); void libusb_fill_control_transfer(struct libusb_transfer *transfer, libusb_device_handle *devh, uint8_t *buf, libusb_transfer_cb_fn callback, void *user_data, uint32_t timeout); void libusb_fill_bulk_transfer(struct libusb_transfer *transfer, libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf, int length, libusb_transfer_cb_fn callback, void *user_data, uint32_t timeout); +void libusb_fill_bulk_stream_transfer(struct libusb_transfer *transfer, libusb_device_handle *dev_handle, unsigned char endpoint, uint32_t stream_id, unsigned char *buffer, int length, libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout); void libusb_fill_interrupt_transfer(struct libusb_transfer *transfer, libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf, int length, libusb_transfer_cb_fn callback, void *user_data, uint32_t timeout); void libusb_fill_iso_transfer(struct libusb_transfer *transfer, libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf, int length, int npacket, libusb_transfer_cb_fn callback, void *user_data, uint32_t timeout); @@ -574,9 +602,11 @@ int libusb_handle_events_completed(libusb_context * ctx, int *completed); int libusb_handle_events_timeout(libusb_context * ctx, struct timeval *tv); int libusb_handle_events(libusb_context * ctx); int libusb_handle_events_locked(libusb_context * ctx, struct timeval *tv); +int libusb_pollfds_handle_timeouts(libusb_context *ctx); int libusb_get_next_timeout(libusb_context * ctx, struct timeval *tv); void libusb_set_pollfd_notifiers(libusb_context * ctx, libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, void *user_data); -const struct libusb_pollfd **libusb_get_pollfds(libusb_context * ctx); +const struct libusb_pollfd **libusb_get_pollfds(libusb_context *ctx); +void libusb_free_pollfds(const struct libusb_pollfd **pollfds); /* Synchronous device I/O */ @@ -596,6 +626,8 @@ typedef int (*libusb_hotplug_callback_fn)(libusb_context *ctx, int libusb_hotplug_register_callback(libusb_context *ctx, libusb_hotplug_event events, libusb_hotplug_flag flags, int vendor_id, int product_id, int dev_class, libusb_hotplug_callback_fn cb_fn, void *user_data, libusb_hotplug_callback_handle *handle); void libusb_hotplug_deregister_callback(libusb_context *ctx, libusb_hotplug_callback_handle handle); +void *libusb_hotplug_get_user_data(struct libusb_context *ctx, + libusb_hotplug_callback_handle callback_handle); /* Streams support */ diff --git a/lib/libusb/libusb01.c b/lib/libusb/libusb01.c index 7017016693af..f246e74353a6 100644 --- a/lib/libusb/libusb01.c +++ b/lib/libusb/libusb01.c @@ -130,6 +130,8 @@ usb_get_transfer_by_ep_no(usb_dev_handle * dev, uint8_t ep_no) bufsize = 4096; } else if (speed == LIBUSB20_SPEED_SUPER) { bufsize = 65536; + } else if (speed == LIBUSB20_SPEED_SUPER_PLUS) { + bufsize = 131072; } else { bufsize = 16384; } diff --git a/lib/libusb/libusb10.c b/lib/libusb/libusb10.c index 6d9c11910ea0..e226def0b7b6 100644 --- a/lib/libusb/libusb10.c +++ b/lib/libusb/libusb10.c @@ -3,6 +3,8 @@ * * Copyright (c) 2009 Sylvestre Gallon. All rights reserved. * Copyright (c) 2009-2023 Hans Petter Selasky + * Copyright (c) 2024 Aymeric Wibo + * Copyright (c) 2025 ShengYi Hung * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,15 +32,18 @@ #include LIBUSB_GLOBAL_INCLUDE_FILE #else #include <assert.h> +#include <ctype.h> #include <errno.h> #include <poll.h> #include <pthread.h> #include <signal.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <time.h> +#include <sys/eventfd.h> #include <sys/fcntl.h> #include <sys/ioctl.h> #include <sys/queue.h> @@ -46,6 +51,7 @@ #endif #define libusb_device_handle libusb20_device +#define LIBUSB_LOG_BUFFER_SIZE 1024 #include "libusb20.h" #include "libusb20_desc.h" @@ -80,6 +86,52 @@ static const struct libusb_version libusb_version = { .describe = "https://www.freebsd.org" }; +static const struct libusb_language_context libusb_language_ctx[] = { + { + .lang_name = "en", + .err_strs = { + [-LIBUSB_SUCCESS] = "Success", + [-LIBUSB_ERROR_IO] = "I/O error", + [-LIBUSB_ERROR_INVALID_PARAM] = "Invalid parameter", + [-LIBUSB_ERROR_ACCESS] = "Permissions error", + [-LIBUSB_ERROR_NO_DEVICE] = "No device", + [-LIBUSB_ERROR_NOT_FOUND] = "Not found", + [-LIBUSB_ERROR_BUSY] = "Device busy", + [-LIBUSB_ERROR_TIMEOUT] = "Timeout", + [-LIBUSB_ERROR_OVERFLOW] = "Overflow", + [-LIBUSB_ERROR_PIPE] = "Pipe error", + [-LIBUSB_ERROR_INTERRUPTED] = "Interrupted", + [-LIBUSB_ERROR_NO_MEM] = "Out of memory", + [-LIBUSB_ERROR_NOT_SUPPORTED] ="Not supported", + [LIBUSB_ERROR_COUNT - 1] = "Other error", + [LIBUSB_ERROR_COUNT] = "Unknown error", + } + }, + { + .lang_name = "zh", + .err_strs = { + [-LIBUSB_SUCCESS] = "成功", + [-LIBUSB_ERROR_IO] = "I/O 錯誤", + [-LIBUSB_ERROR_INVALID_PARAM] = "不合法的參數", + [-LIBUSB_ERROR_ACCESS] = "權限錯誤", + [-LIBUSB_ERROR_NO_DEVICE] = "裝置不存在", + [-LIBUSB_ERROR_NOT_FOUND] = "不存在", + [-LIBUSB_ERROR_BUSY] = "裝置忙碌中", + [-LIBUSB_ERROR_TIMEOUT] = "逾時", + [-LIBUSB_ERROR_OVERFLOW] = "溢位", + [-LIBUSB_ERROR_PIPE] = "管道錯誤", + [-LIBUSB_ERROR_INTERRUPTED] = "被中斷", + [-LIBUSB_ERROR_NO_MEM] = "記憶體不足", + [-LIBUSB_ERROR_NOT_SUPPORTED] ="不支援", + [LIBUSB_ERROR_COUNT - 1] = "其他錯誤", + [LIBUSB_ERROR_COUNT] = "未知錯誤", + } + }, +}; + +static const struct libusb_language_context *default_language_context = + &libusb_language_ctx[0]; + const struct libusb_version * libusb_get_version(void) { @@ -118,17 +170,15 @@ libusb_set_nonblocking(int f) void libusb_interrupt_event_handler(libusb_context *ctx) { - uint8_t dummy; int err; if (ctx == NULL) return; - dummy = 0; - err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); - if (err < (int)sizeof(dummy)) { + err = eventfd_write(ctx->event, 1); + if (err < 0) { /* ignore error, if any */ - DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "Waking up event loop failed!"); + DPRINTF(ctx, LIBUSB_LOG_LEVEL_ERROR, "Waking up event loop failed!"); } } @@ -145,7 +195,6 @@ libusb_init_context(libusb_context **context, struct libusb_context *ctx; pthread_condattr_t attr; char *debug, *ep; - int ret; if (num_options < 0) return (LIBUSB_ERROR_INVALID_PARAM); @@ -155,6 +204,7 @@ libusb_init_context(libusb_context **context, return (LIBUSB_ERROR_INVALID_PARAM); memset(ctx, 0, sizeof(*ctx)); + ctx->devd_pipe = -1; debug = getenv("LIBUSB_DEBUG"); if (debug != NULL) { @@ -233,19 +283,16 @@ libusb_init_context(libusb_context **context, ctx->ctx_handler = NO_THREAD; ctx->hotplug_handler = NO_THREAD; - ret = pipe(ctx->ctrl_pipe); - if (ret < 0) { + ctx->event = eventfd(0, EFD_NONBLOCK); + if (ctx->event < 0) { pthread_mutex_destroy(&ctx->ctx_lock); pthread_mutex_destroy(&ctx->hotplug_lock); pthread_cond_destroy(&ctx->ctx_cond); free(ctx); return (LIBUSB_ERROR_OTHER); } - /* set non-blocking mode on the control pipe to avoid deadlock */ - libusb_set_nonblocking(ctx->ctrl_pipe[0]); - libusb_set_nonblocking(ctx->ctrl_pipe[1]); - libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN); + libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->event, POLLIN); pthread_mutex_lock(&default_context_lock); if (usbi_default_context == NULL) { @@ -256,7 +303,7 @@ libusb_init_context(libusb_context **context, if (context) *context = ctx; - DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete"); + DPRINTF(ctx, LIBUSB_LOG_LEVEL_INFO, "libusb_init complete"); signal(SIGPIPE, SIG_IGN); @@ -280,6 +327,13 @@ libusb_exit(libusb_context *ctx) HOTPLUG_LOCK(ctx); td = ctx->hotplug_handler; ctx->hotplug_handler = NO_THREAD; + if (ctx->usb_event_mode == usb_event_devd) { + close(ctx->devd_pipe); + ctx->devd_pipe = -1; + } else if (ctx->usb_event_mode == usb_event_netlink) { + close(ctx->ss.fd); + ctx->ss.fd = -1; + } HOTPLUG_UNLOCK(ctx); pthread_join(td, &ptr); @@ -288,8 +342,7 @@ libusb_exit(libusb_context *ctx) /* XXX cleanup devices */ libusb10_remove_pollfd(ctx, &ctx->ctx_poll); - close(ctx->ctrl_pipe[0]); - close(ctx->ctrl_pipe[1]); + close(ctx->event); pthread_mutex_destroy(&ctx->ctx_lock); pthread_mutex_destroy(&ctx->hotplug_lock); pthread_cond_destroy(&ctx->ctx_cond); @@ -309,9 +362,9 @@ ssize_t libusb_get_device_list(libusb_context *ctx, libusb_device ***list) { struct libusb20_backend *usb_backend; - struct libusb20_device *pdev; + struct libusb20_device *pdev, *parent_dev; struct libusb_device *dev; - int i; + int i, j, k; ctx = GET_CONTEXT(ctx); @@ -363,6 +416,9 @@ libusb_get_device_list(libusb_context *ctx, libusb_device ***list) /* set context we belong to */ dev->ctx = ctx; + /* assume we have no parent by default */ + dev->parent_dev = NULL; + /* link together the two structures */ dev->os_priv = pdev; pdev->privLuData = dev; @@ -372,6 +428,25 @@ libusb_get_device_list(libusb_context *ctx, libusb_device ***list) } (*list)[i] = NULL; + /* for each device, find its parent */ + for (j = 0; j < i; j++) { + pdev = (*list)[j]->os_priv; + + for (k = 0; k < i; k++) { + if (k == j) + continue; + + parent_dev = (*list)[k]->os_priv; + + if (parent_dev->bus_number != pdev->bus_number) + continue; + if (parent_dev->device_address == pdev->parent_address) { + (*list)[j]->parent_dev = libusb_ref_device((*list)[k]); + break; + } + } + } + libusb20_be_free(usb_backend); return (i); } @@ -443,6 +518,8 @@ libusb_get_device_speed(libusb_device *dev) return (LIBUSB_SPEED_HIGH); case LIBUSB20_SPEED_SUPER: return (LIBUSB_SPEED_SUPER); + case LIBUSB20_SPEED_SUPER_PLUS: + return (LIBUSB_SPEED_SUPER_PLUS); default: break; } @@ -536,6 +613,7 @@ libusb_unref_device(libusb_device *dev) CTX_UNLOCK(dev->ctx); if (dev->refcnt == 0) { + libusb_unref_device(dev->parent_dev); libusb20_dev_free(dev->os_priv); free(dev); } @@ -597,7 +675,7 @@ libusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id, if (ctx == NULL) return (NULL); /* be NULL safe */ - DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_with_vid_pid enter"); + DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_open_device_with_vid_pid enter"); if ((i = libusb_get_device_list(ctx, &devs)) < 0) return (NULL); @@ -621,7 +699,7 @@ libusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id, } libusb_free_device_list(devs, 1); - DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_with_vid_pid leave"); + DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_open_device_with_vid_pid leave"); return (pdev); } @@ -812,6 +890,12 @@ libusb_set_interface_alt_setting(struct libusb20_device *pdev, return (err ? LIBUSB_ERROR_OTHER : 0); } +libusb_device * +libusb_get_parent(libusb_device *dev) +{ + return (dev->parent_dev); +} + static struct libusb20_transfer * libusb10_get_transfer(struct libusb20_device *pdev, uint8_t endpoint, uint8_t xfer_index) @@ -1072,6 +1156,9 @@ libusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer) case LIBUSB20_SPEED_SUPER: ret = 65536; break; + case LIBUSB20_SPEED_SUPER_PLUS: + ret = 131072; + break; default: ret = 16384; break; @@ -1443,6 +1530,7 @@ found: libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy); break; case LIBUSB_TRANSFER_TYPE_BULK: + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: case LIBUSB_TRANSFER_TYPE_INTERRUPT: libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy); break; @@ -1499,7 +1587,7 @@ libusb_submit_transfer(struct libusb_transfer *uxfer) dev = libusb_get_device(uxfer->dev_handle); - DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter"); + DPRINTF(dev->ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_submit_transfer enter"); sxfer = (struct libusb_super_transfer *)( (uint8_t *)uxfer - sizeof(*sxfer)); @@ -1534,7 +1622,7 @@ libusb_submit_transfer(struct libusb_transfer *uxfer) CTX_UNLOCK(dev->ctx); - DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err); + DPRINTF(dev->ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_submit_transfer leave %d", err); return (err); } @@ -1563,7 +1651,7 @@ libusb_cancel_transfer(struct libusb_transfer *uxfer) dev = libusb_get_device(devh); - DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter"); + DPRINTF(dev->ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_cancel_transfer enter"); sxfer = (struct libusb_super_transfer *)( (uint8_t *)uxfer - sizeof(*sxfer)); @@ -1624,7 +1712,7 @@ libusb_cancel_transfer(struct libusb_transfer *uxfer) CTX_UNLOCK(dev->ctx); - DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); + DPRINTF(dev->ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_cancel_transfer leave"); return (retval); } @@ -1689,38 +1777,26 @@ libusb_le16_to_cpu(uint16_t x) const char * libusb_strerror(int code) { - switch (code) { - case LIBUSB_SUCCESS: - return ("Success"); - case LIBUSB_ERROR_IO: - return ("I/O error"); - case LIBUSB_ERROR_INVALID_PARAM: - return ("Invalid parameter"); - case LIBUSB_ERROR_ACCESS: - return ("Permissions error"); - case LIBUSB_ERROR_NO_DEVICE: - return ("No device"); - case LIBUSB_ERROR_NOT_FOUND: - return ("Not found"); - case LIBUSB_ERROR_BUSY: - return ("Device busy"); - case LIBUSB_ERROR_TIMEOUT: - return ("Timeout"); - case LIBUSB_ERROR_OVERFLOW: - return ("Overflow"); - case LIBUSB_ERROR_PIPE: - return ("Pipe error"); - case LIBUSB_ERROR_INTERRUPTED: - return ("Interrupted"); - case LIBUSB_ERROR_NO_MEM: - return ("Out of memory"); - case LIBUSB_ERROR_NOT_SUPPORTED: - return ("Not supported"); - case LIBUSB_ERROR_OTHER: - return ("Other error"); - default: - return ("Unknown error"); - } + int entry = -code; + + if (code == LIBUSB_ERROR_OTHER) + entry = LIBUSB_ERROR_COUNT - 1; + /* + * The libusb upstream considers all code out of range a + * LIBUSB_ERROR_OTHER. In FreeBSD, it is a special unknown error. We + * preserve the FreeBSD implementation as I think it make sense. + */ + if (entry < 0 || entry >= LIBUSB_ERROR_COUNT) + entry = LIBUSB_ERROR_COUNT; + + /* + * Fall back to English one as the translation may be unimplemented + * when adding new error code. + */ + if (default_language_context->err_strs[entry] == NULL) + return (libusb_language_ctx[0].err_strs[entry]); + + return (default_language_context->err_strs[entry]); } const char * @@ -1774,3 +1850,78 @@ libusb_has_capability(uint32_t capability) return (0); } } + +void +libusb_log_va_args(struct libusb_context *ctx, enum libusb_log_level level, + const char *fmt, ...) +{ + static const char *log_prefix[5] = { + [LIBUSB_LOG_LEVEL_ERROR] = "LIBUSB_ERROR", + [LIBUSB_LOG_LEVEL_WARNING] = "LIBUSB_WARN", + [LIBUSB_LOG_LEVEL_INFO] = "LIBUSB_INFO", + [LIBUSB_LOG_LEVEL_DEBUG] = "LIBUSB_DEBUG", + }; + + char buffer[LIBUSB_LOG_BUFFER_SIZE]; + char new_fmt[LIBUSB_LOG_BUFFER_SIZE]; + va_list args; + + ctx = GET_CONTEXT(ctx); + + if (ctx->debug < level) + return; + + va_start(args, fmt); + + snprintf(new_fmt, sizeof(new_fmt), "%s: %s\n", log_prefix[level], fmt); + vsnprintf(buffer, sizeof(buffer), new_fmt, args); + fputs(buffer, stdout); + + va_end(args); +} + +/* + * Upstream code actually recognizes the first two characters to identify a + * language. We do so to provide API compatibility with setlocale. + */ +int +libusb_setlocale(const char *locale) +{ + size_t idx; + const char *lang; + + if (locale == NULL || strlen(locale) < 2 || + (locale[2] != '\0' && strchr("-_.", locale[2]) == NULL)) + return (LIBUSB_ERROR_INVALID_PARAM); + + for (idx = 0; idx < nitems(libusb_language_ctx); ++idx) { + lang = libusb_language_ctx[idx].lang_name; + if (tolower(locale[0]) == lang[0] && + tolower(locale[1]) == lang[1]) { + default_language_context = &libusb_language_ctx[idx]; + return (LIBUSB_SUCCESS); + } + } + + return (LIBUSB_ERROR_INVALID_PARAM); +} + +unsigned char * +libusb_dev_mem_alloc(libusb_device_handle *devh) +{ + return (NULL); +} + +int +libusb_dev_mem_free(libusb_device_handle *devh, unsigned char *buffer, + size_t size) +{ + return (LIBUSB_ERROR_NOT_SUPPORTED); +} + +int +libusb_wrap_sys_device(libusb_context *ctx, intptr_t sys_dev, + libusb_device_handle **dev_handle) +{ + return (LIBUSB_ERROR_NOT_SUPPORTED); +} diff --git a/lib/libusb/libusb10.h b/lib/libusb/libusb10.h index 544364386061..eced364ef857 100644 --- a/lib/libusb/libusb10.h +++ b/lib/libusb/libusb10.h @@ -29,7 +29,14 @@ #define __LIBUSB10_H__ #ifndef LIBUSB_GLOBAL_INCLUDE_FILE +#include <sys/cdefs.h> #include <sys/queue.h> +#include <netlink/netlink.h> +#include <netlink/netlink_generic.h> +#include <netlink/netlink_snl.h> +#include <netlink/netlink_snl_generic.h> +#include <netlink/netlink_sysevent.h> + #endif #define GET_CONTEXT(ctx) (((ctx) == NULL) ? usbi_default_context : (ctx)) @@ -40,24 +47,11 @@ #define HOTPLUG_LOCK(ctx) pthread_mutex_lock(&(ctx)->hotplug_lock) #define HOTPLUG_UNLOCK(ctx) pthread_mutex_unlock(&(ctx)->hotplug_lock) -#define DPRINTF(ctx, dbg, format, ...) do { \ - switch (dbg) { \ - case LIBUSB_DEBUG_FUNCTION: \ - if ((ctx)->debug & LIBUSB_DEBUG_FUNCTION) { \ - printf("LIBUSB_FUNCTION: " \ - format "\n", ## __VA_ARGS__); \ - } \ - break; \ - case LIBUSB_DEBUG_TRANSFER: \ - if ((ctx)->debug & LIBUSB_DEBUG_TRANSFER) { \ - printf("LIBUSB_TRANSFER: " \ - format "\n", ## __VA_ARGS__); \ - } \ - break; \ - default: \ - break; \ - } \ -} while (0) +void libusb_log_va_args(struct libusb_context *ctx, enum libusb_log_level level, + const char *fmt, ...) __printflike(3, 4); + +#define DPRINTF(ctx, dbg, format, ...) \ + libusb_log_va_args(ctx, dbg, format, ##__VA_ARGS__) /* internal structures */ @@ -90,12 +84,22 @@ struct libusb_hotplug_callback_handle_struct { TAILQ_HEAD(libusb_device_head, libusb_device); +typedef enum { + usb_event_none, + usb_event_scan, + usb_event_devd, + usb_event_netlink +} usb_event_mode_t; + struct libusb_context { int debug; int debug_fixed; - int ctrl_pipe[2]; + int event; int tr_done_ref; int tr_done_gen; + usb_event_mode_t usb_event_mode; + int devd_pipe; + struct snl_state ss; pthread_mutex_t ctx_lock; pthread_mutex_t hotplug_lock; @@ -126,6 +130,7 @@ struct libusb_device { struct libusb_super_pollfd dev_poll; struct libusb_context *ctx; + struct libusb_device *parent_dev; TAILQ_ENTRY(libusb_device) hotplug_entry; @@ -134,6 +139,12 @@ struct libusb_device { struct libusb20_device *os_priv; }; +struct libusb_language_context { + const char *lang_name; + /* All error Plus 1 UNKNOWN */ + const char *err_strs[LIBUSB_ERROR_COUNT + 1]; +}; + extern struct libusb_context *usbi_default_context; void libusb10_add_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd, struct libusb20_device *pdev, int fd, short events); diff --git a/lib/libusb/libusb10_desc.c b/lib/libusb/libusb10_desc.c index 3e36009cbb3a..7da5c84f4ad2 100644 --- a/lib/libusb/libusb10_desc.c +++ b/lib/libusb/libusb10_desc.c @@ -470,10 +470,11 @@ libusb_parse_bos_descriptor(const void *buf, int len, ptr->bDescriptorType = dtype; ptr->wTotalLength = ((const uint8_t *)buf)[2] | (((const uint8_t *)buf)[3] << 8); - ptr->bNumDeviceCapabilities = ((const uint8_t *)buf)[4]; + ptr->bNumDeviceCaps = ((const uint8_t *)buf)[4]; ptr->usb_2_0_ext_cap = NULL; ptr->ss_usb_cap = NULL; - ptr->dev_capability = calloc(ptr->bNumDeviceCapabilities, sizeof(void *)); + ptr->dev_capability = calloc(ptr->bNumDeviceCaps, + sizeof(void *)); if (ptr->dev_capability == NULL) { free(ptr); return (LIBUSB_ERROR_NO_MEM); @@ -485,7 +486,7 @@ libusb_parse_bos_descriptor(const void *buf, int len, if (dlen >= 3 && ptr != NULL && dtype == LIBUSB_DT_DEVICE_CAPABILITY) { - if (index != ptr->bNumDeviceCapabilities) { + if (index != ptr->bNumDeviceCaps) { ptr->dev_capability[index] = malloc(dlen); if (ptr->dev_capability[index] == NULL) { libusb_free_bos_descriptor(ptr); @@ -542,7 +543,7 @@ libusb_parse_bos_descriptor(const void *buf, int len, } if (ptr != NULL) { - ptr->bNumDeviceCapabilities = index; + ptr->bNumDeviceCaps = index; return (0); /* success */ } @@ -557,7 +558,7 @@ libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos) if (bos == NULL) return; - for (i = 0; i != bos->bNumDeviceCapabilities; i++) + for (i = 0; i != bos->bNumDeviceCaps; i++) free(bos->dev_capability[i]); free(bos->dev_capability); free(bos); @@ -710,6 +711,55 @@ void libusb_free_container_id_descriptor( struct libusb_container_id_descriptor *container_id) { - free(container_id); } + +int +libusb_get_platform_descriptor(libusb_context *ctx, + struct libusb_bos_dev_capability_descriptor *bos_cap, + struct libusb_platform_descriptor **pd) +{ + struct libusb_platform_descriptor *desc; + uint8_t *cap_data; + + if (bos_cap == NULL || + bos_cap->bDescriptorType != LIBUSB_BT_PLATFORM_DESCRIPTOR || + pd == NULL) + return (LIBUSB_ERROR_INVALID_PARAM); + + if (bos_cap->bLength < LIBUSB_BT_PLATFORM_DESCRIPTOR_MIN_SIZE) + return (LIBUSB_ERROR_IO); + + cap_data = bos_cap->dev_capability_data; + desc = calloc(1, bos_cap->bLength); + if (desc == NULL) + return (LIBUSB_ERROR_NO_MEM); + + desc->bLength = bos_cap->bLength; + desc->bDescriptorType = LIBUSB_BT_PLATFORM_DESCRIPTOR; + desc->bDevCapabilityType = bos_cap->bDevCapabilityType; + desc->bReserved = cap_data[0]; + memcpy(desc->PlatformCapabilityUUID, cap_data + 1, + sizeof(desc->PlatformCapabilityUUID)); + + /* + * UUID (16 bytes) + bReserved + */ + cap_data += sizeof(desc->PlatformCapabilityUUID) + 1; + /* + * UUID (16 bytes) + bReserved + bLength + bDescriptortype + + * bDevCapabilitytype + */ + memcpy(desc->CapabilityData, cap_data, + bos_cap->bLength - (sizeof(desc->PlatformCapabilityUUID) + 4)); + *pd = desc; + + return (LIBUSB_SUCCESS); +} + +void +libusb_free_platform_descriptor( + struct libusb_platform_descriptor *platform_descriptor) +{ + free(platform_descriptor); +} diff --git a/lib/libusb/libusb10_hotplug.c b/lib/libusb/libusb10_hotplug.c index 9d00b1dbe5a0..9c46d4926bfa 100644 --- a/lib/libusb/libusb10_hotplug.c +++ b/lib/libusb/libusb10_hotplug.c @@ -23,6 +23,7 @@ * SUCH DAMAGE. */ +#include <netlink/netlink_snl_generic.h> #ifdef LIBUSB_GLOBAL_INCLUDE_FILE #include LIBUSB_GLOBAL_INCLUDE_FILE #else @@ -39,6 +40,10 @@ #include <sys/ioctl.h> #include <sys/queue.h> #include <sys/endian.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/module.h> +#include <sys/linker.h> #endif #define libusb_device_handle libusb20_device @@ -49,6 +54,110 @@ #include "libusb.h" #include "libusb10.h" +#define DEVDPIPE "/var/run/devd.seqpacket.pipe" +#define DEVCTL_MAXBUF 1024 + +typedef enum { + broken_event, + invalid_event, + valid_event, +} event_t; + +static bool +netlink_init(libusb_context *ctx) +{ + uint32_t group; + + if (modfind("nlsysevent") < 0) + kldload("nlsysevent"); + if (modfind("nlsysevent") < 0) + return (false); + if (!snl_init(&ctx->ss, NETLINK_GENERIC) || (group = + snl_get_genl_mcast_group(&ctx->ss, "nlsysevent", "USB", NULL)) == 0) + return (false); + + if (setsockopt(ctx->ss.fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, + sizeof(group)) == -1) + return (false); + + ctx->usb_event_mode = usb_event_netlink; + return (true); +} + +static bool +devd_init(libusb_context *ctx) +{ + struct sockaddr_un devd_addr; + + bzero(&devd_addr, sizeof(devd_addr)); + if ((ctx->devd_pipe = socket(PF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK, 0)) < 0) + return (false); + + devd_addr.sun_family = PF_LOCAL; + strlcpy(devd_addr.sun_path, DEVDPIPE, sizeof(devd_addr.sun_path)); + if (connect(ctx->devd_pipe, (struct sockaddr *)&devd_addr, + sizeof(devd_addr)) == -1) { + close(ctx->devd_pipe); + ctx->devd_pipe = -1; + return (false); + } + + ctx->usb_event_mode = usb_event_devd; + return (true); +} + +struct nlevent { + const char *name; + const char *subsystem; + const char *type; + const char *data; +}; + +#define _OUT(_field) offsetof(struct nlevent, _field) +static struct snl_attr_parser ap_nlevent_get[] = { + { .type = NLSE_ATTR_SYSTEM, .off = _OUT(name), .cb = snl_attr_get_string }, + { .type = NLSE_ATTR_SUBSYSTEM, .off = _OUT(subsystem), .cb = snl_attr_get_string }, + { .type = NLSE_ATTR_TYPE, .off = _OUT(type), .cb = snl_attr_get_string }, + { .type = NLSE_ATTR_DATA, .off = _OUT(data), .cb = snl_attr_get_string }, +}; +#undef _OUT + +SNL_DECLARE_GENL_PARSER(nlevent_get_parser, ap_nlevent_get); + +static event_t +verify_event_validity(libusb_context *ctx) +{ + if (ctx->usb_event_mode == usb_event_netlink) { + struct nlmsghdr *hdr; + struct nlevent ne; + + hdr = snl_read_message(&ctx->ss); + if (hdr != NULL && hdr->nlmsg_type != NLMSG_ERROR) { + memset(&ne, 0, sizeof(ne)); + if (!snl_parse_nlmsg(&ctx->ss, hdr, &nlevent_get_parser, &ne)) + return (broken_event); + if (strcmp(ne.subsystem, "DEVICE") == 0) + return (valid_event); + return (invalid_event); + } + if (errno == EBADF) + return (broken_event); + return (invalid_event); + } else if (ctx->usb_event_mode == usb_event_devd) { + char buf[DEVCTL_MAXBUF]; + ssize_t len; + + len = read(ctx->devd_pipe, buf, sizeof(buf)); + if (len == 0 || (len < 0 && errno != EWOULDBLOCK)) + return (broken_event); + if (len > 0 && strstr(buf, "system=USB") != NULL && + strstr(buf, "subsystem=DEVICE") != NULL) + return (valid_event); + return (invalid_event); + } + return (broken_event); +} + static int libusb_hotplug_equal(libusb_device *_adev, libusb_device *_bdev) { @@ -105,6 +214,7 @@ libusb_hotplug_enumerate(libusb_context *ctx, struct libusb_device_head *phead) static void * libusb_hotplug_scan(void *arg) { + struct pollfd pfd; struct libusb_device_head hotplug_devs; libusb_hotplug_callback_handle acbh; libusb_hotplug_callback_handle bcbh; @@ -112,22 +222,71 @@ libusb_hotplug_scan(void *arg) libusb_device *temp; libusb_device *adev; libusb_device *bdev; - unsigned do_loop = 1; + int timeout = INFTIM; + int nfds; - while (do_loop) { - usleep(4000000); + memset(&pfd, 0, sizeof(pfd)); + if (ctx->usb_event_mode == usb_event_devd) { + pfd.fd = ctx->devd_pipe; + pfd.events = POLLIN | POLLERR; + nfds = 1; + } else if (ctx->usb_event_mode == usb_event_netlink) { + pfd.fd = ctx->ss.fd; + pfd.events = POLLIN | POLLERR; + nfds = 1; + } else { + nfds = 0; + timeout = 4000; + } + for (;;) { + pfd.revents = 0; + if (poll(&pfd, nfds, timeout) > 0) { + switch (verify_event_validity(ctx)) { + case invalid_event: + continue; + case valid_event: + break; + case broken_event: + /* There are 2 cases for broken events: + * - devd and netlink sockets are not available + * anymore (devd restarted, nlsysevent unloaded) + * - libusb_exit has been called as it sets NO_THREAD + * this will result in exiting this loop and this thread + * immediately + */ + nfds = 0; + if (ctx->usb_event_mode == usb_event_devd) { + if (ctx->devd_pipe != -1) + close(ctx->devd_pipe); + } else if (ctx->usb_event_mode == usb_event_netlink) { + if (ctx->ss.fd != -1) + close(ctx->ss.fd); + } + ctx->usb_event_mode = usb_event_scan; + timeout = 4000; + break; + } + } HOTPLUG_LOCK(ctx); + if (ctx->hotplug_handler == NO_THREAD) { + while ((adev = TAILQ_FIRST(&ctx->hotplug_devs)) != NULL) { + TAILQ_REMOVE(&ctx->hotplug_devs, adev, hotplug_entry); + libusb_unref_device(adev); + } + if (ctx->usb_event_mode == usb_event_devd) + close(ctx->devd_pipe); + else if (ctx->usb_event_mode == usb_event_netlink) + close(ctx->ss.fd); + HOTPLUG_UNLOCK(ctx); + break; + } TAILQ_INIT(&hotplug_devs); - if (ctx->hotplug_handler != NO_THREAD) { - if (libusb_hotplug_enumerate(ctx, &hotplug_devs) < 0) { - HOTPLUG_UNLOCK(ctx); - continue; - } - } else { - do_loop = 0; + if (libusb_hotplug_enumerate(ctx, &hotplug_devs) < 0) { + HOTPLUG_UNLOCK(ctx); + continue; } /* figure out which devices are gone */ @@ -189,6 +348,13 @@ int libusb_hotplug_register_callback(libusb_context *ctx, ctx = GET_CONTEXT(ctx); + if (ctx->usb_event_mode == usb_event_none) { + HOTPLUG_LOCK(ctx); + if (!netlink_init(ctx) && !devd_init(ctx)) + ctx->usb_event_mode = usb_event_scan; + HOTPLUG_UNLOCK(ctx); + } + if (ctx == NULL || cb_fn == NULL || events == 0 || vendor_id < -1 || vendor_id > 0xffff || product_id < -1 || product_id > 0xffff || @@ -243,7 +409,26 @@ void libusb_hotplug_deregister_callback(libusb_context *ctx, HOTPLUG_LOCK(ctx); TAILQ_REMOVE(&ctx->hotplug_cbh, handle, entry); + libusb_interrupt_event_handler(ctx); HOTPLUG_UNLOCK(ctx); free(handle); } + +void * +libusb_hotplug_get_user_data(struct libusb_context *ctx, + libusb_hotplug_callback_handle callback_handle) +{ + libusb_hotplug_callback_handle handle; + + ctx = GET_CONTEXT(ctx); + + HOTPLUG_LOCK(ctx); + TAILQ_FOREACH(handle, &ctx->hotplug_cbh, entry) { + if (handle == callback_handle) + break; + } + HOTPLUG_UNLOCK(ctx); + + return (handle); +} diff --git a/lib/libusb/libusb10_io.c b/lib/libusb/libusb10_io.c index 59bac60c4672..2047712e9e39 100644 --- a/lib/libusb/libusb10_io.c +++ b/lib/libusb/libusb10_io.c @@ -36,6 +36,7 @@ #include <string.h> #include <time.h> #include <unistd.h> +#include <sys/eventfd.h> #include <sys/queue.h> #include <sys/endian.h> #endif @@ -107,7 +108,7 @@ libusb10_handle_events_sub(struct libusb_context *ctx, struct timeval *tv) int i; int err; - DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb10_handle_events_sub enter"); + DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb10_handle_events_sub enter"); nfds = 0; i = 0; @@ -187,10 +188,8 @@ libusb10_handle_events_sub(struct libusb_context *ctx, struct timeval *tv) CTX_LOCK(ctx); } else { - uint8_t dummy; + eventfd_read(fds[i].fd, &(eventfd_t){0}); - while (read(fds[i].fd, &dummy, 1) == 1) - ; } } @@ -231,6 +230,7 @@ do_done: /* Wakeup other waiters */ pthread_cond_broadcast(&ctx->ctx_cond); + DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb10_handle_events_sub complete"); return (err); } @@ -314,7 +314,7 @@ libusb_wait_for_event(libusb_context *ctx, struct timeval *tv) int err; ctx = GET_CONTEXT(ctx); - DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_wait_for_event enter"); + DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_wait_for_event enter"); if (tv == NULL) { pthread_cond_wait(&ctx->ctx_cond, @@ -358,7 +358,7 @@ libusb_handle_events_timeout_completed(libusb_context *ctx, ctx = GET_CONTEXT(ctx); - DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout_completed enter"); + DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_handle_events_timeout_completed enter"); libusb_lock_events(ctx); @@ -374,7 +374,7 @@ libusb_handle_events_timeout_completed(libusb_context *ctx, libusb_unlock_events(ctx); - DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout_completed exit"); + DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_handle_events_timeout_completed exit"); return (err); } @@ -422,6 +422,12 @@ libusb_get_next_timeout(libusb_context *ctx, struct timeval *tv) return (0); } +int +libusb_pollfds_handle_timeouts(libusb_context *ctx) +{ + return (1); +} + void libusb_set_pollfd_notifiers(libusb_context *ctx, libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, @@ -523,7 +529,7 @@ libusb10_do_transfer_cb(struct libusb_transfer *transfer) ctx = libusb10_get_context_by_device_handle(transfer->dev_handle); - DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "sync I/O done"); + DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "sync I/O done"); pdone = transfer->user_data; *pdone = 1; @@ -613,12 +619,12 @@ libusb_bulk_transfer(libusb_device_handle *devh, ctx = libusb10_get_context_by_device_handle(devh); - DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer enter"); + DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_bulk_transfer enter"); ret = libusb10_do_transfer(devh, endpoint, data, length, transferred, timeout, LIBUSB_TRANSFER_TYPE_BULK); - DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer leave"); + DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_bulk_transfer leave"); return (ret); } @@ -632,12 +638,12 @@ libusb_interrupt_transfer(libusb_device_handle *devh, ctx = libusb10_get_context_by_device_handle(devh); - DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer enter"); + DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_interrupt_transfer enter"); ret = libusb10_do_transfer(devh, endpoint, data, length, transferred, timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT); - DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer leave"); + DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_interrupt_transfer leave"); return (ret); } @@ -781,6 +787,19 @@ libusb_fill_interrupt_transfer(struct libusb_transfer *transfer, } void +libusb_fill_bulk_stream_transfer(struct libusb_transfer *transfer, + libusb_device_handle *dev_handle, unsigned char endpoint, + uint32_t stream_id, unsigned char *buffer, int length, + libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) +{ + libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, + length, callback, user_data, timeout); + transfer->type = LIBUSB_TRANSFER_TYPE_BULK_STREAM; + + libusb_transfer_set_stream_id(transfer, stream_id); +} + +void libusb_fill_iso_transfer(struct libusb_transfer *transfer, libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf, int length, int npacket, libusb_transfer_cb_fn callback, @@ -842,3 +861,12 @@ libusb_transfer_get_stream_id(struct libusb_transfer *transfer) /* get stream ID */ return (sxfer->stream_id); } + +void +libusb_free_pollfds(const struct libusb_pollfd **pollfds) +{ + if (pollfds == NULL) + return; + + free(pollfds); +} diff --git a/lib/libusb/libusb20.3 b/lib/libusb/libusb20.3 index 1d07db8f32a4..7854b0f8ed7e 100644 --- a/lib/libusb/libusb20.3 +++ b/lib/libusb/libusb20.3 @@ -858,6 +858,7 @@ returns the current speed of the given USB device. .It LIBUSB20_SPEED_HIGH .It LIBUSB20_SPEED_VARIABLE .It LIBUSB20_SPEED_SUPER +.It LIBUSB20_SPEED_SUPER_PLUS .El . .Pp diff --git a/lib/libusb/libusb20.h b/lib/libusb/libusb20.h index 7bca2f7508c7..c132c58a9f69 100644 --- a/lib/libusb/libusb20.h +++ b/lib/libusb/libusb20.h @@ -159,6 +159,7 @@ enum { LIBUSB20_SPEED_HIGH, LIBUSB20_SPEED_VARIABLE, LIBUSB20_SPEED_SUPER, + LIBUSB20_SPEED_SUPER_PLUS, }; /** \ingroup misc diff --git a/lib/libusb/libusb20_desc.h b/lib/libusb/libusb20_desc.h index 017148a34b1c..0f7c9294ebc8 100644 --- a/lib/libusb/libusb20_desc.h +++ b/lib/libusb/libusb20_desc.h @@ -298,11 +298,15 @@ LIBUSB20_MAKE_STRUCT(LIBUSB20_USB_20_DEVCAP_DESC); LIBUSB20_MAKE_STRUCT(LIBUSB20_SS_USB_DEVCAP_DESC); +#ifndef bNumDeviceCapabilities +#define bNumDeviceCapabilities bNumDeviceCaps +#endif + #define LIBUSB20_BOS_DESCRIPTOR(m,n) \ m(n, UINT8_T, bLength, ) \ m(n, UINT8_T, bDescriptorType, ) \ m(n, UINT16_T, wTotalLength, ) \ - m(n, UINT8_T, bNumDeviceCapabilities, ) \ + m(n, UINT8_T, bNumDeviceCaps, ) \ LIBUSB20_MAKE_STRUCT(LIBUSB20_BOS_DESCRIPTOR); |