diff options
-rw-r--r-- | .clang-tidy | 47 | ||||
-rw-r--r-- | Android.bp | 1 | ||||
-rw-r--r-- | METADATA | 8 | ||||
-rw-r--r-- | Xcode/common.xcconfig | 20 | ||||
-rw-r--r-- | android/examples/unrooted_android.c | 1 | ||||
-rw-r--r-- | examples/testlibusb.c | 1 | ||||
-rw-r--r-- | examples/xusb.c | 77 | ||||
-rw-r--r-- | libusb/core.c | 8 | ||||
-rw-r--r-- | libusb/descriptor.c | 98 | ||||
-rw-r--r-- | libusb/hotplug.c | 35 | ||||
-rw-r--r-- | libusb/io.c | 1 | ||||
-rw-r--r-- | libusb/libusb-1.0.def | 4 | ||||
-rw-r--r-- | libusb/libusb.h | 111 | ||||
-rw-r--r-- | libusb/libusbi.h | 12 | ||||
-rw-r--r-- | libusb/os/darwin_usb.c | 92 | ||||
-rw-r--r-- | libusb/os/emscripten_webusb.cpp | 2 | ||||
-rw-r--r-- | libusb/os/linux_usbfs.c | 1 | ||||
-rw-r--r-- | libusb/os/sunos_usb.c | 8 | ||||
-rw-r--r-- | libusb/os/threads_posix.c | 33 | ||||
-rw-r--r-- | libusb/os/threads_posix.h | 2 | ||||
-rw-r--r-- | libusb/os/threads_windows.h | 4 | ||||
-rw-r--r-- | libusb/os/windows_winusb.c | 7 | ||||
-rw-r--r-- | libusb/sync.c | 13 | ||||
-rw-r--r-- | libusb/version_nano.h | 2 | ||||
-rw-r--r-- | tests/macos.c | 4 |
25 files changed, 480 insertions, 112 deletions
diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..6349aa8 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,47 @@ +--- +Checks: "-*,\ +boost-*,\ +bugprone-*,\ +-bugprone-assignment-in-if-condition,\ +-bugprone-branch-clone,\ +-bugprone-easily-swappable-parameters,\ +-bugprone-implicit-widening-of-multiplication-result,\ +-bugprone-macro-parentheses,\ +-bugprone-misplaced-widening-cast,\ +-bugprone-narrowing-conversions,\ +-bugprone-reserved-identifier,\ +-bugprone-signed-char-misuse,\ +-bugprone-suspicious-string-compare,\ +-bugprone-switch-missing-default-case,\ +-bugprone-unsafe-functions,\ +-bugprone-too-small-loop-variable,\ +clang-analyzer-*,\ +-clang-analyzer-core.NullDereference,\ +-clang-analyzer-deadcode.DeadStores,\ +-clang-analyzer-optin.portability.UnixAPI,\ +-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,\ +-clang-analyzer-security.insecureAPI.strcpy,\ +-clang-analyzer-unix.Malloc,\ +misc-*,\ +-misc-no-recursion,\ +-misc-include-cleaner,\ +modernize-*,\ +-modernize-macro-to-enum,\ +performance-*,\ +-performance-no-int-to-ptr,\ +-performance-type-promotion-in-math-fn,\ +portability-*,\ +readability-*,\ +-readability-braces-around-statements,\ +-readability-else-after-return,\ +-readability-identifier-length,\ +-readability-function-cognitive-complexity,\ +-readability-inconsistent-declaration-parameter-name,\ +-readability-isolate-declaration,\ +-readability-magic-numbers,\ +-readability-non-const-parameter,\ +-readability-uppercase-literal-suffix,\ +-readability-misleading-indentation,\ +" +#WarningsAsErrors: "*" +... @@ -62,6 +62,7 @@ cc_library { "-Wno-error=switch", "-Wno-error=unused-function", "-Wno-unused-parameter", +"-DENABLE_LOGGING=1", ], target: { @@ -1,5 +1,5 @@ # This project was upgraded with external_updater. -# Usage: tools/external_updater/updater.sh update libusb +# Usage: tools/external_updater/updater.sh update external/libusb # For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md name: "libusb" @@ -8,13 +8,13 @@ third_party { license_type: RESTRICTED last_upgrade_date { year: 2024 - month: 2 - day: 9 + month: 5 + day: 21 } homepage: "https://libusb.info/" identifier { type: "Git" value: "https://github.com/libusb/libusb" - version: "v1.0.27" + version: "fef78a96e37936f16c10c43c9a220683f7c2ff74" } } diff --git a/Xcode/common.xcconfig b/Xcode/common.xcconfig index 06108ad..6751445 100644 --- a/Xcode/common.xcconfig +++ b/Xcode/common.xcconfig @@ -65,6 +65,26 @@ CLANG_WARN_INT_CONVERSION = YES CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES CLANG_WARN_STRICT_PROTOTYPES = YES CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES +CLANG_WARN_COMPLETION_HANDLER_MISUSE = YES +CLANG_WARN_IMPLICIT_FALLTHROUGH = YES +CLANG_WARN_FRAMEWORK_INCLUDE_PRIVATE_FROM_PUBLIC = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES +CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES +GCC_WARN_SIGN_COMPARE = YES +CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES +GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES +GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES +CLANG_WARN_ATOMIC_IMPLICIT_SEQ_CST = YES +CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES +CLANG_WARN_OBJC_INTERFACE_IVARS = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_UNREACHABLE_CODE = YES +CLANG_WARN_RANGE_LOOP_ANALYSIS = YES +CLANG_WARN_SUSPICIOUS_MOVE = YES +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES +GCC_WARN_UNDECLARED_SELECTOR = YES // Static analyzer warnings. CLANG_ANALYZER_NONNULL = YES diff --git a/android/examples/unrooted_android.c b/android/examples/unrooted_android.c index 33793c7..5134c54 100644 --- a/android/examples/unrooted_android.c +++ b/android/examples/unrooted_android.c @@ -210,6 +210,7 @@ static void print_device(libusb_device *dev, libusb_device_handle *handle) case LIBUSB_SPEED_HIGH: speed = "480M"; break; case LIBUSB_SPEED_SUPER: speed = "5G"; break; case LIBUSB_SPEED_SUPER_PLUS: speed = "10G"; break; + case LIBUSB_SPEED_SUPER_PLUS_X2: speed = "20G"; break; default: speed = "Unknown"; } diff --git a/examples/testlibusb.c b/examples/testlibusb.c index 394cec5..07d5426 100644 --- a/examples/testlibusb.c +++ b/examples/testlibusb.c @@ -174,6 +174,7 @@ static void print_device(libusb_device *dev, libusb_device_handle *handle) case LIBUSB_SPEED_HIGH: speed = "480M"; break; case LIBUSB_SPEED_SUPER: speed = "5G"; break; case LIBUSB_SPEED_SUPER_PLUS: speed = "10G"; break; + case LIBUSB_SPEED_SUPER_PLUS_X2: speed = "20G"; break; default: speed = "Unknown"; } diff --git a/examples/xusb.c b/examples/xusb.c index 239450c..83e5525 100644 --- a/examples/xusb.c +++ b/examples/xusb.c @@ -37,6 +37,10 @@ // in libusb_config_descriptor => catter for that #define usb_interface interface +#ifndef ARRAYSIZE +#define ARRAYSIZE(array) (sizeof(array) / sizeof(array[0])) +#endif + // Global variables static bool binary_dump = false; static bool extra_info = false; @@ -461,7 +465,7 @@ static int test_mass_storage(libusb_device_handle *handle, uint8_t endpoint_in, double device_size; uint8_t cdb[16]; // SCSI Command Descriptor Block uint8_t buffer[64]; - char vid[9], pid[9], rev[5]; + unsigned char vid[9], pid[9], rev[5]; unsigned char *data; FILE *fd; @@ -560,7 +564,7 @@ static int get_hid_record_size(uint8_t *hid_report_descriptor, int size, int typ uint8_t i, j = 0; uint8_t offset; int record_size[3] = {0, 0, 0}; - int nb_bits = 0, nb_items = 0; + unsigned int nb_bits = 0, nb_items = 0; bool found_record_marker; found_record_marker = false; @@ -575,7 +579,7 @@ static int get_hid_record_size(uint8_t *hid_report_descriptor, int size, int typ case 0x94: // count nb_items = 0; for (j=1; j<offset; j++) { - nb_items = ((uint32_t)hid_report_descriptor[i+j]) << (8*(j-1)); + nb_items = ((unsigned int)hid_report_descriptor[i+j]) << (8U*(j-1U)); } break; case 0x80: // input @@ -623,9 +627,9 @@ static int test_hid(libusb_device_handle *handle, uint8_t endpoint_in) printf(" Failed\n"); return -1; } - display_buffer_hex(hid_report_descriptor, descriptor_size); + display_buffer_hex(hid_report_descriptor, (unsigned int)descriptor_size); if ((binary_dump) && ((fd = fopen(binary_name, "w")) != NULL)) { - if (fwrite(hid_report_descriptor, 1, descriptor_size, fd) != (size_t)descriptor_size) { + if (fwrite(hid_report_descriptor, 1, (size_t)descriptor_size, fd) != (size_t)descriptor_size) { printf(" Error writing descriptor to file\n"); } fclose(fd); @@ -634,8 +638,10 @@ static int test_hid(libusb_device_handle *handle, uint8_t endpoint_in) size = get_hid_record_size(hid_report_descriptor, descriptor_size, HID_REPORT_TYPE_FEATURE); if (size <= 0) { printf("\nSkipping Feature Report readout (None detected)\n"); + } else if (size > UINT16_MAX) { + printf("\nSkipping Feature Report readout (bigger than UINT16_MAX)\n"); } else { - report_buffer = (uint8_t*) calloc(size, 1); + report_buffer = (uint8_t*) calloc(1, (size_t)size); if (report_buffer == NULL) { return -1; } @@ -644,7 +650,7 @@ static int test_hid(libusb_device_handle *handle, uint8_t endpoint_in) r = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE, HID_GET_REPORT, (HID_REPORT_TYPE_FEATURE<<8)|0, 0, report_buffer, (uint16_t)size, 5000); if (r >= 0) { - display_buffer_hex(report_buffer, size); + display_buffer_hex(report_buffer, (unsigned int)size); } else { switch(r) { case LIBUSB_ERROR_NOT_FOUND: @@ -665,8 +671,10 @@ static int test_hid(libusb_device_handle *handle, uint8_t endpoint_in) size = get_hid_record_size(hid_report_descriptor, descriptor_size, HID_REPORT_TYPE_INPUT); if (size <= 0) { printf("\nSkipping Input Report readout (None detected)\n"); + } else if (size > UINT16_MAX) { + printf("\nSkipping Input Report readout (bigger than UINT16_MAX)\n"); } else { - report_buffer = (uint8_t*) calloc(size, 1); + report_buffer = (uint8_t*) calloc(1, (size_t)size); if (report_buffer == NULL) { return -1; } @@ -675,7 +683,7 @@ static int test_hid(libusb_device_handle *handle, uint8_t endpoint_in) r = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE, HID_GET_REPORT, (HID_REPORT_TYPE_INPUT<<8)|0x00, 0, report_buffer, (uint16_t)size, 5000); if (r >= 0) { - display_buffer_hex(report_buffer, size); + display_buffer_hex(report_buffer, (unsigned int)size); } else { switch(r) { case LIBUSB_ERROR_TIMEOUT: @@ -695,7 +703,7 @@ static int test_hid(libusb_device_handle *handle, uint8_t endpoint_in) printf("\nTesting interrupt read using endpoint %02X...\n", endpoint_in); r = libusb_interrupt_transfer(handle, endpoint_in, report_buffer, size, &size, 5000); if (r >= 0) { - display_buffer_hex(report_buffer, size); + display_buffer_hex(report_buffer, (unsigned int)size); } else { printf(" %s\n", libusb_strerror((enum libusb_error)r)); } @@ -753,11 +761,22 @@ static void read_ms_winsub_feature_descriptors(libusb_device_handle *handle, uin perr(" Failed: %s", libusb_strerror((enum libusb_error)r)); return; } else { - display_buffer_hex(os_desc, r); + display_buffer_hex(os_desc, (unsigned int)r); } } } +static void print_sublink_speed_attribute(struct libusb_ssplus_sublink_attribute* ss_attr) { + static const char exponent[] = " KMG"; + printf(" id=%u speed=%u%cbs %s %s SuperSpeed%s", + ss_attr->ssid, + ss_attr->mantisa, + (exponent[ss_attr->exponent]), + (ss_attr->type == LIBUSB_SSPLUS_ATTR_TYPE_ASYM)? "Asym" : "Sym", + (ss_attr->direction == LIBUSB_SSPLUS_ATTR_DIR_TX)? "TX" : "RX", + (ss_attr->protocol == LIBUSB_SSPLUS_ATTR_PROT_SSPLUS)? "+": "" ); +} + static void print_device_cap(struct libusb_bos_dev_capability_descriptor *dev_cap) { switch(dev_cap->bDevCapabilityType) { @@ -806,6 +825,25 @@ static void print_device_cap(struct libusb_bos_dev_capability_descriptor *dev_ca break; } + case LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY: { + struct libusb_ssplus_usb_device_capability_descriptor *ssplus_usb_device_cap = NULL; + libusb_get_ssplus_usb_device_capability_descriptor(NULL, dev_cap, &ssplus_usb_device_cap); + if (ssplus_usb_device_cap) { + printf(" USB 3.1 capabilities:\n"); + printf(" num speed IDs: %d\n", ssplus_usb_device_cap->numSublinkSpeedIDs); + printf(" minLaneSpeed: %d\n", ssplus_usb_device_cap->ssid); + printf(" minRXLanes: %d\n", ssplus_usb_device_cap->minRxLaneCount); + printf(" minTXLanes: %d\n", ssplus_usb_device_cap->minTxLaneCount); + + printf(" num speed attribute IDs: %d\n", ssplus_usb_device_cap->numSublinkSpeedAttributes); + for(uint8_t i=0 ; i < ssplus_usb_device_cap->numSublinkSpeedAttributes ; i++) { + print_sublink_speed_attribute(&ssplus_usb_device_cap->sublinkSpeedAttributes[i]); + printf("\n"); + } + libusb_free_ssplus_usb_device_capability_descriptor(ssplus_usb_device_cap); + } + break; + } default: printf(" Unknown BOS device capability %02x:\n", dev_cap->bDevCapabilityType); } @@ -822,9 +860,10 @@ static int test_device(uint16_t vid, uint16_t pid) int i, j, k, r; int iface, nb_ifaces, first_iface = -1; struct libusb_device_descriptor dev_desc; - const char* const speed_name[6] = { "Unknown", "1.5 Mbit/s (USB LowSpeed)", "12 Mbit/s (USB FullSpeed)", - "480 Mbit/s (USB HighSpeed)", "5000 Mbit/s (USB SuperSpeed)", "10000 Mbit/s (USB SuperSpeedPlus)" }; - char string[128]; + const char* const speed_name[] = { "Unknown", "1.5 Mbit/s (USB LowSpeed)", "12 Mbit/s (USB FullSpeed)", + "480 Mbit/s (USB HighSpeed)", "5000 Mbit/s (USB SuperSpeed)", "10000 Mbit/s (USB SuperSpeedPlus)", + "20000 Mbit/s (USB SuperSpeedPlus x2)" }; + unsigned char string[128]; uint8_t string_index[3]; // indexes of the string descriptors uint8_t endpoint_in = 0, endpoint_out = 0; // default IN and OUT endpoints @@ -850,7 +889,8 @@ static int test_device(uint16_t vid, uint16_t pid) printf(" (from root hub)\n"); } r = libusb_get_device_speed(dev); - if ((r<0) || (r>5)) r=0; + if ((r < 0) || ((size_t)r >= ARRAYSIZE(speed_name))) + r = 0; printf(" speed: %s\n", speed_name[r]); } @@ -960,13 +1000,13 @@ static int test_device(uint16_t vid, uint16_t pid) if (string_index[i] == 0) { continue; } - if (libusb_get_string_descriptor_ascii(handle, string_index[i], (unsigned char*)string, sizeof(string)) > 0) { + if (libusb_get_string_descriptor_ascii(handle, string_index[i], string, sizeof(string)) > 0) { printf(" String (0x%02X): \"%s\"\n", string_index[i], string); } } printf("\nReading OS string descriptor:"); - r = libusb_get_string_descriptor(handle, MS_OS_DESC_STRING_INDEX, 0, (unsigned char*)string, MS_OS_DESC_STRING_LENGTH); + r = libusb_get_string_descriptor(handle, MS_OS_DESC_STRING_INDEX, 0, string, MS_OS_DESC_STRING_LENGTH); if (r == MS_OS_DESC_STRING_LENGTH && memcmp(ms_os_desc_string, string, sizeof(ms_os_desc_string)) == 0) { // If this is a Microsoft OS String Descriptor, // attempt to read the WinUSB extended Feature Descriptors @@ -991,7 +1031,7 @@ static int test_device(uint16_t vid, uint16_t pid) printf(" bFunctionSubClass: %02X\n", iad->bFunctionSubClass); printf(" bFunctionProtocol: %02X\n", iad->bFunctionProtocol); if (iad->iFunction) { - if (libusb_get_string_descriptor_ascii(handle, iad->iFunction, (unsigned char*)string, sizeof(string)) > 0) + if (libusb_get_string_descriptor_ascii(handle, iad->iFunction, string, sizeof(string)) > 0) printf(" iFunction: %u (%s)\n", iad->iFunction, string); else printf(" iFunction: %u (libusb_get_string_descriptor_ascii failed!)\n", iad->iFunction); @@ -1017,6 +1057,7 @@ static int test_device(uint16_t vid, uint16_t pid) break; case USE_SCSI: CALL_CHECK_CLOSE(test_mass_storage(handle, endpoint_in, endpoint_out), handle); + break; case USE_GENERIC: break; } diff --git a/libusb/core.c b/libusb/core.c index ffe33b7..010201c 100644 --- a/libusb/core.c +++ b/libusb/core.c @@ -964,7 +964,7 @@ int API_EXPORTED libusb_get_port_numbers(libusb_device *dev, dev = dev->parent_dev; } if (i < port_numbers_len) - memmove(port_numbers, &port_numbers[i], port_numbers_len - i); + memmove(port_numbers, &port_numbers[i], (size_t)(port_numbers_len - i)); return port_numbers_len - i; } @@ -1014,7 +1014,7 @@ uint8_t API_EXPORTED libusb_get_device_address(libusb_device *dev) */ int API_EXPORTED libusb_get_device_speed(libusb_device *dev) { - return dev->speed; + return (int)(dev->speed); } static const struct libusb_endpoint_descriptor *find_endpoint( @@ -2456,7 +2456,7 @@ int API_EXPORTED libusb_init_context(libusb_context **ctx, const struct libusb_i _ctx->debug = get_env_debug_level(); _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; + _ctx->debug = (enum libusb_log_level)default_context_options[LIBUSB_OPTION_LOG_LEVEL].arg.ival; } #endif @@ -2809,7 +2809,7 @@ static void log_v(struct libusb_context *ctx, enum libusb_log_level level, TIMESPEC_SUB(×tamp, ×tamp_origin, ×tamp); header_len = snprintf(buf, sizeof(buf), - "[%2ld.%06ld] [%08x] libusb: %s [%s] ", + "[%2ld.%06ld] [%08lx] libusb: %s [%s] ", (long)timestamp.tv_sec, (long)(timestamp.tv_nsec / 1000L), usbi_get_tid(), prefix, function); } else { header_len = snprintf(buf, sizeof(buf), diff --git a/libusb/descriptor.c b/libusb/descriptor.c index 4623ad1..b72f558 100644 --- a/libusb/descriptor.c +++ b/libusb/descriptor.c @@ -59,13 +59,18 @@ static void parse_descriptor(const void *source, const char *descriptor, void *d sp += 2; dp += 2; break; - case 'd': /* 32-bit word, convert from little endian to CPU */ + case 'd': /* 32-bit word, convert from little endian to CPU (4-byte align dst before write). */ dp += 4 - ((uintptr_t)dp & 3); /* Align to 32-bit word boundary */ *((uint32_t *)dp) = READ_LE32(sp); sp += 4; dp += 4; break; + case 'i': /* 32-bit word, convert from little endian to CPU (no dst alignment before write) */ + *((uint32_t *)dp) = READ_LE32(sp); + sp += 4; + dp += 4; + break; case 'u': /* 16 byte UUID */ memcpy(dp, sp, 16); sp += 16; @@ -156,7 +161,7 @@ static int parse_endpoint(struct libusb_context *ctx, if (!extra) return LIBUSB_ERROR_NO_MEM; - memcpy(extra, begin, len); + memcpy(extra, begin, (size_t)len); endpoint->extra = extra; endpoint->extra_length = len; @@ -286,7 +291,7 @@ static int parse_interface(libusb_context *ctx, goto err; } - memcpy(extra, begin, len); + memcpy(extra, begin, (size_t)len); ifp->extra = extra; ifp->extra_length = len; } @@ -431,7 +436,7 @@ static int parse_configuration(struct libusb_context *ctx, goto err; } - memcpy(extra + config->extra_length, begin, len); + memcpy(extra + config->extra_length, begin, (size_t)len); config->extra = extra; config->extra_length += len; } @@ -1001,6 +1006,89 @@ int API_EXPORTED libusb_get_ss_usb_device_capability_descriptor( return LIBUSB_SUCCESS; } +// We use this private struct ony to parse a superspeed+ device capability +// descriptor according to section 9.6.2.5 of the USB 3.1 specification. +// We don't expose it. +struct internal_ssplus_capability_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t bReserved; + uint32_t bmAttributes; + uint16_t wFunctionalitySupport; + uint16_t wReserved; +}; + +int API_EXPORTED libusb_get_ssplus_usb_device_capability_descriptor( + libusb_context *ctx, + struct libusb_bos_dev_capability_descriptor *dev_cap, + struct libusb_ssplus_usb_device_capability_descriptor **ssplus_usb_device_cap) +{ + struct libusb_ssplus_usb_device_capability_descriptor *_ssplus_cap; + + // Use a private struct to re-use our descriptor parsing system. + struct internal_ssplus_capability_descriptor parsedDescriptor; + + // Some size/type checks to make sure everything is in order + if (dev_cap->bDevCapabilityType != LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY) { + usbi_err(ctx, "unexpected bDevCapabilityType 0x%x (expected 0x%x)", + dev_cap->bDevCapabilityType, + LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY); + return LIBUSB_ERROR_INVALID_PARAM; + } else if (dev_cap->bLength < LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE) { + usbi_err(ctx, "short dev-cap descriptor read %u/%d", + dev_cap->bLength, LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE); + return LIBUSB_ERROR_IO; + } + + // We can only parse the non-variable size part of the SuperSpeedPlus descriptor. The attributes + // have to be read "manually". + parse_descriptor(dev_cap, "bbbbiww", &parsedDescriptor); + + uint8_t numSublikSpeedAttributes = (parsedDescriptor.bmAttributes & 0xF) + 1; + _ssplus_cap = malloc(sizeof(struct libusb_ssplus_usb_device_capability_descriptor) + numSublikSpeedAttributes * sizeof(struct libusb_ssplus_sublink_attribute)); + if (!_ssplus_cap) + return LIBUSB_ERROR_NO_MEM; + + // Parse bmAttributes + _ssplus_cap->numSublinkSpeedAttributes = numSublikSpeedAttributes; + _ssplus_cap->numSublinkSpeedIDs = ((parsedDescriptor.bmAttributes & 0xF0) >> 4) + 1; + + // Parse wFunctionalitySupport + _ssplus_cap->ssid = parsedDescriptor.wFunctionalitySupport & 0xF; + _ssplus_cap->minRxLaneCount = (parsedDescriptor.wFunctionalitySupport & 0x0F00) >> 8; + _ssplus_cap->minTxLaneCount = (parsedDescriptor.wFunctionalitySupport & 0xF000) >> 12; + + // Check that we have enough to read all the sublink attributes + if (dev_cap->bLength < LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE + _ssplus_cap->numSublinkSpeedAttributes * sizeof(uint32_t)) { + usbi_err(ctx, "short ssplus capability descriptor, unable to read sublinks: Not enough data"); + return LIBUSB_ERROR_IO; + } + + // Read the attributes + uint8_t* base = ((uint8_t*)dev_cap) + LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE; + for(uint8_t i = 0 ; i < _ssplus_cap->numSublinkSpeedAttributes ; i++) { + uint32_t attr = READ_LE32(base + i * sizeof(uint32_t)); + _ssplus_cap->sublinkSpeedAttributes[i].ssid = attr & 0x0f; + _ssplus_cap->sublinkSpeedAttributes[i].mantisa = attr >> 16; + _ssplus_cap->sublinkSpeedAttributes[i].exponent = (attr >> 4) & 0x3 ; + _ssplus_cap->sublinkSpeedAttributes[i].type = attr & 0x40 ? LIBUSB_SSPLUS_ATTR_TYPE_ASYM : LIBUSB_SSPLUS_ATTR_TYPE_SYM; + _ssplus_cap->sublinkSpeedAttributes[i].direction = attr & 0x80 ? LIBUSB_SSPLUS_ATTR_DIR_TX : LIBUSB_SSPLUS_ATTR_DIR_RX; + _ssplus_cap->sublinkSpeedAttributes[i].protocol = attr & 0x4000 ? LIBUSB_SSPLUS_ATTR_PROT_SSPLUS: LIBUSB_SSPLUS_ATTR_PROT_SS; + } + + *ssplus_usb_device_cap = _ssplus_cap; + return LIBUSB_SUCCESS; +} + +void API_EXPORTED libusb_free_ssplus_usb_device_capability_descriptor( + struct libusb_ssplus_usb_device_capability_descriptor *ssplus_usb_device_cap) +{ + free(ssplus_usb_device_cap); +} + + + /** \ingroup libusb_desc * Free a SuperSpeed USB Device Capability descriptor obtained from * libusb_get_ss_usb_device_capability_descriptor(). @@ -1241,7 +1329,7 @@ static int parse_iad_array(struct libusb_context *ctx, iad_array->iad = NULL; if (iad_array->length > 0) { - iad = calloc(iad_array->length, sizeof(*iad)); + iad = calloc((size_t)iad_array->length, sizeof(*iad)); if (!iad) return LIBUSB_ERROR_NO_MEM; diff --git a/libusb/hotplug.c b/libusb/hotplug.c index 3c64f69..026e11d 100644 --- a/libusb/hotplug.c +++ b/libusb/hotplug.c @@ -161,6 +161,27 @@ void usbi_hotplug_init(struct libusb_context *ctx) usbi_atomic_store(&ctx->hotplug_ready, 1); } +static void usbi_recursively_remove_parents(struct libusb_device *dev, struct libusb_device *next_dev) +{ + if (dev && dev->parent_dev) { + if (usbi_atomic_load(&dev->parent_dev->refcnt) == 1) { + /* The parent was processed before this device in the list and + * therefore has its ref count already decremented for its own ref. + * The only remaining counted ref comes from its remaining single child. + * It will thus be released when its child will be released. So we + * can remove it from the list. This is safe as parent_dev cannot be + * equal to next_dev given that we know at this point that it was + * previously seen in the list. */ + assert (dev->parent_dev != next_dev); + if (dev->parent_dev->list.next && dev->parent_dev->list.prev) { + list_del(&dev->parent_dev->list); + } + } + + usbi_recursively_remove_parents(dev->parent_dev, next_dev); + } +} + void usbi_hotplug_exit(struct libusb_context *ctx) { struct usbi_hotplug_callback *hotplug_cb, *next_cb; @@ -193,7 +214,8 @@ void usbi_hotplug_exit(struct libusb_context *ctx) free(msg); } - /* free all discovered devices. due to parent references loop until no devices are freed. */ + usbi_mutex_lock(&ctx->usb_devs_lock); /* hotplug thread might still be processing an already triggered event, possibly accessing this list as well */ + /* free all discovered devices */ for_each_device_safe(ctx, dev, next_dev) { /* remove the device from the usb_devs list only if there are no * references held, otherwise leave it on the list so that a @@ -201,15 +223,12 @@ void usbi_hotplug_exit(struct libusb_context *ctx) if (usbi_atomic_load(&dev->refcnt) == 1) { list_del(&dev->list); } - if (dev->parent_dev && usbi_atomic_load(&dev->parent_dev->refcnt) == 1) { - /* the parent was before this device in the list and will be released. - remove it from the list. this is safe as parent_dev can not be - equal to next_dev. */ - assert (dev->parent_dev != next_dev); - list_del(&dev->parent_dev->list); - } + + usbi_recursively_remove_parents(dev, next_dev); + libusb_unref_device(dev); } + usbi_mutex_unlock(&ctx->usb_devs_lock); usbi_mutex_destroy(&ctx->hotplug_cbs_lock); } diff --git a/libusb/io.c b/libusb/io.c index ab84ba6..0b2aaf6 100644 --- a/libusb/io.c +++ b/libusb/io.c @@ -1714,6 +1714,7 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, flags = transfer->flags; transfer->status = status; transfer->actual_length = itransfer->transferred; + assert(transfer->actual_length >= 0); usbi_dbg(ctx, "transfer %p has callback %p", (void *) transfer, transfer->callback); if (transfer->callback) { diff --git a/libusb/libusb-1.0.def b/libusb/libusb-1.0.def index 6d7caa7..921f3dd 100644 --- a/libusb/libusb-1.0.def +++ b/libusb/libusb-1.0.def @@ -50,6 +50,8 @@ EXPORTS libusb_free_ss_endpoint_companion_descriptor@4 = libusb_free_ss_endpoint_companion_descriptor libusb_free_ss_usb_device_capability_descriptor libusb_free_ss_usb_device_capability_descriptor@4 = libusb_free_ss_usb_device_capability_descriptor + libusb_free_ssplus_usb_device_capability_descriptor + libusb_free_ssplus_usb_device_capability_descriptor@4 = libusb_free_ssplus_usb_device_capability_descriptor libusb_free_streams libusb_free_streams@12 = libusb_free_streams libusb_free_transfer @@ -108,6 +110,8 @@ EXPORTS libusb_get_ss_endpoint_companion_descriptor@12 = libusb_get_ss_endpoint_companion_descriptor libusb_get_ss_usb_device_capability_descriptor libusb_get_ss_usb_device_capability_descriptor@12 = libusb_get_ss_usb_device_capability_descriptor + libusb_get_ssplus_usb_device_capability_descriptor + libusb_get_ssplus_usb_device_capability_descriptor@12 = libusb_get_ssplus_usb_device_capability_descriptor libusb_get_string_descriptor_ascii libusb_get_string_descriptor_ascii@16 = libusb_get_string_descriptor_ascii libusb_get_usb_2_0_extension_descriptor diff --git a/libusb/libusb.h b/libusb/libusb.h index f4e9203..2353f4c 100644 --- a/libusb/libusb.h +++ b/libusb/libusb.h @@ -339,6 +339,7 @@ enum libusb_descriptor_type { /* BOS descriptor sizes */ #define LIBUSB_BT_USB_2_0_EXTENSION_SIZE 7 #define LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE 10 +#define LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE 12 #define LIBUSB_BT_CONTAINER_ID_SIZE 20 #define LIBUSB_BT_PLATFORM_DESCRIPTOR_MIN_SIZE 20 @@ -562,7 +563,10 @@ enum libusb_bos_type { LIBUSB_BT_CONTAINER_ID = 0x04, /** Platform descriptor */ - LIBUSB_BT_PLATFORM_DESCRIPTOR = 0x05 + LIBUSB_BT_PLATFORM_DESCRIPTOR = 0x05, + + /* SuperSpeed+ device capability */ + LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY = 0x0A, }; /** \ingroup libusb_desc @@ -981,6 +985,100 @@ struct libusb_ss_usb_device_capability_descriptor { }; /** \ingroup libusb_desc + * enum used in \ref libusb_ssplus_sublink_attribute + */ +enum libusb_superspeedplus_sublink_attribute_sublink_type { + LIBUSB_SSPLUS_ATTR_TYPE_SYM = 0, + LIBUSB_SSPLUS_ATTR_TYPE_ASYM = 1, +}; + +/** \ingroup libusb_desc + * enum used in \ref libusb_ssplus_sublink_attribute + */ +enum libusb_superspeedplus_sublink_attribute_sublink_direction { + LIBUSB_SSPLUS_ATTR_DIR_RX = 0, + LIBUSB_SSPLUS_ATTR_DIR_TX = 1, +}; + +/** \ingroup libusb_desc + * enum used in \ref libusb_ssplus_sublink_attribute + * Bit = Bits per second + * Kb = Kbps + * Mb = Mbps + * Gb = Gbps + */ +enum libusb_superspeedplus_sublink_attribute_exponent { + LIBUSB_SSPLUS_ATTR_EXP_BPS = 0, + LIBUSB_SSPLUS_ATTR_EXP_KBS = 1, + LIBUSB_SSPLUS_ATTR_EXP_MBS = 2, + LIBUSB_SSPLUS_ATTR_EXP_GBS = 3, +}; + +/** \ingroup libusb_desc + * enum used in \ref libusb_ssplus_sublink_attribute + */ +enum libusb_superspeedplus_sublink_attribute_link_protocol { + LIBUSB_SSPLUS_ATTR_PROT_SS = 0, + LIBUSB_SSPLUS_ATTR_PROT_SSPLUS = 1, +}; + +/** \ingroup libusb_desc + * Expose \ref libusb_ssplus_usb_device_capability_descriptor.sublinkSpeedAttributes + */ +struct libusb_ssplus_sublink_attribute { + /** Sublink Speed Attribute ID (SSID). + This field is an ID that uniquely identifies the speed of this sublink */ + uint8_t ssid; + + /** This field defines the + base 10 exponent times 3, that shall be applied to the + mantissa. */ + enum libusb_superspeedplus_sublink_attribute_exponent exponent; + + /** This field identifies whether the + Sublink Speed Attribute defines a symmetric or + asymmetric bit rate.*/ + enum libusb_superspeedplus_sublink_attribute_sublink_type type; + + /** This field indicates if this + Sublink Speed Attribute defines the receive or + transmit bit rate. */ + enum libusb_superspeedplus_sublink_attribute_sublink_direction direction; + + /** This field identifies the protocol + supported by the link. */ + enum libusb_superspeedplus_sublink_attribute_link_protocol protocol; + + /** This field defines the mantissa that shall be applied to the exponent when + calculating the maximum bit rate. */ + uint16_t mantisa; +}; + +/** \ingroup libusb_desc + * A structure representing the SuperSpeedPlus descriptor + * This descriptor is documented in section 9.6.2.5 of the USB 3.1 specification. + */ +struct libusb_ssplus_usb_device_capability_descriptor { + /** Sublink Speed Attribute Count */ + uint8_t numSublinkSpeedAttributes; + + /** Sublink Speed ID Count */ + uint8_t numSublinkSpeedIDs; + + /** Unique ID to indicates the minimum lane speed */ + uint8_t ssid; + + /** This field indicates the minimum receive lane count.*/ + uint8_t minRxLaneCount; + + /** This field indicates the minimum transmit lane count*/ + uint8_t minTxLaneCount; + + /** num attrtibutes= \ref libusb_ssplus_usb_device_capability_descriptor.numSublinkSpeedAttributes= */ + struct libusb_ssplus_sublink_attribute sublinkSpeedAttributes[]; +}; + +/** \ingroup libusb_desc * A structure representing the Container ID descriptor. * This descriptor is documented in section 9.6.2.3 of the USB 3.0 specification. * All multiple-byte fields, except UUIDs, are represented in host-endian format. @@ -1167,7 +1265,10 @@ enum libusb_speed { LIBUSB_SPEED_SUPER = 4, /** The device is operating at super speed plus (10000MBit/s). */ - LIBUSB_SPEED_SUPER_PLUS = 5 + LIBUSB_SPEED_SUPER_PLUS = 5, + + /** The device is operating at super speed plus x2 (20000MBit/s). */ + LIBUSB_SPEED_SUPER_PLUS_X2 = 6, }; /** \ingroup libusb_misc @@ -1625,6 +1726,12 @@ int LIBUSB_CALL libusb_get_ss_usb_device_capability_descriptor( struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_cap); void LIBUSB_CALL libusb_free_ss_usb_device_capability_descriptor( struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_cap); +int LIBUSB_CALL libusb_get_ssplus_usb_device_capability_descriptor( + libusb_context *ctx, + struct libusb_bos_dev_capability_descriptor *dev_cap, + struct libusb_ssplus_usb_device_capability_descriptor **ssplus_usb_device_cap); +void LIBUSB_CALL libusb_free_ssplus_usb_device_capability_descriptor( + struct libusb_ssplus_usb_device_capability_descriptor *ssplus_usb_device_cap); int LIBUSB_CALL libusb_get_container_id_descriptor(libusb_context *ctx, struct libusb_bos_dev_capability_descriptor *dev_cap, struct libusb_container_id_descriptor **container_id); diff --git a/libusb/libusbi.h b/libusb/libusbi.h index 3b0c610..6d19a93 100644 --- a/libusb/libusbi.h +++ b/libusb/libusbi.h @@ -103,6 +103,17 @@ typedef volatile LONG usbi_atomic_t; #define usbi_atomic_inc(a) InterlockedIncrement((a)) #define usbi_atomic_dec(a) InterlockedDecrement((a)) #else +#if defined(__HAIKU__) && defined(__GNUC__) && !defined(__clang__) +/* The Haiku port of libusb has some C++ files and GCC does not define + * anything in stdatomic.h when compiled in C++11 (only in C++23). + * This appears to be a bug in gcc's stdatomic.h, and should be fixed either + * in gcc or in Haiku. Until then, use the gcc builtins. */ +typedef long usbi_atomic_t; +#define usbi_atomic_load(a) __atomic_load_n((a), __ATOMIC_SEQ_CST) +#define usbi_atomic_store(a, v) __atomic_store_n((a), (v), __ATOMIC_SEQ_CST) +#define usbi_atomic_inc(a) __atomic_add_fetch((a), 1, __ATOMIC_SEQ_CST) +#define usbi_atomic_dec(a) __atomic_sub_fetch((a), 1, __ATOMIC_SEQ_CST) +#else #include <stdatomic.h> typedef atomic_long usbi_atomic_t; #define usbi_atomic_load(a) atomic_load((a)) @@ -110,6 +121,7 @@ typedef atomic_long usbi_atomic_t; #define usbi_atomic_inc(a) (atomic_fetch_add((a), 1) + 1) #define usbi_atomic_dec(a) (atomic_fetch_add((a), -1) - 1) #endif +#endif /* Internal abstractions for event handling and thread synchronization */ #if defined(PLATFORM_POSIX) diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c index c0963e0..ae09db7 100644 --- a/libusb/os/darwin_usb.c +++ b/libusb/os/darwin_usb.c @@ -40,7 +40,7 @@ /* Default timeout to 10s for reenumerate. This is needed because USBDeviceReEnumerate * does not return error status on macOS. */ -#define DARWIN_REENUMERATE_TIMEOUT_US (10 * USEC_PER_SEC) +#define DARWIN_REENUMERATE_TIMEOUT_US (10ULL * USEC_PER_SEC) #include <AvailabilityMacros.h> #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 && MAC_OS_X_VERSION_MIN_REQUIRED < 101200 @@ -70,8 +70,8 @@ static struct list_head darwin_cached_devices; static const char *darwin_device_class = "IOUSBDevice"; uint32_t libusb_testonly_fake_running_version __attribute__ ((visibility ("hidden"))); -int libusb_testonly_using_running_interface_version __attribute__ ((visibility ("hidden"))); -int libusb_testonly_using_running_device_version __attribute__ ((visibility ("hidden"))); +uint32_t libusb_testonly_using_running_interface_version __attribute__ ((visibility ("hidden"))); +uint32_t libusb_testonly_using_running_device_version __attribute__ ((visibility ("hidden"))); bool libusb_testonly_clear_running_version_cache __attribute__ ((visibility ("hidden"))); #define DARWIN_CACHED_DEVICE(a) (((struct darwin_device_priv *)usbi_get_device_priv((a)))->dev) @@ -173,7 +173,7 @@ static CFUUIDRef get_interface_interface_id(void) { return get_interface_interface()->interface_id; } -static int get_interface_interface_version(void) { +static uint32_t get_interface_interface_version(void) { return get_interface_interface()->version; } @@ -244,7 +244,7 @@ static CFUUIDRef get_device_interface_id(void) { return get_device_interface()->interface_id; } -static int get_device_interface_version(void) { +static uint32_t get_device_interface_version(void) { return get_device_interface()->version; } @@ -370,11 +370,11 @@ uint32_t get_running_version(void) { * it provides the exact macOS version instead of the approximate version (as below). */ ret = sysctlbyname("kern.osproductversion", os_version_string, &os_version_string_len, NULL, 0); if (ret == 0) { - int major = 10, minor = 0, patch = 0; - ret = sscanf(os_version_string, "%i.%i.%i", &major, &minor, &patch); + unsigned int major = 10, minor = 0, patch = 0; + ret = sscanf(os_version_string, "%u.%u.%u", &major, &minor, &patch); if (ret < 2) { usbi_err (NULL, "could not determine the running OS version, assuming 10.0, kern.osproductversion=%s", os_version_string); - return 100000; + return 10 * 10000; } return (major * 10000) + (minor * 100) + patch; } @@ -386,17 +386,17 @@ uint32_t get_running_version(void) { ret = sysctlbyname("kern.osrelease", os_release_string, &os_release_string_len, NULL, 0); if (ret != 0) { usbi_err (NULL, "could not read kern.osrelease, errno=", errno); - return 100000; + return 10 * 10000; } - int darwin_major = 1, darwin_minor = 0; - ret = sscanf(os_release_string, "%i.%i", &darwin_major, &darwin_minor); + unsigned int darwin_major = 1, darwin_minor = 0; + ret = sscanf(os_release_string, "%u.%u", &darwin_major, &darwin_minor); if (ret < 1) { usbi_err (NULL, "could not determine the running Darwin version, assuming 1.3 (OS X 10.0), kern.osrelease=%s", os_release_string); - return 100000; + return 10 * 10000; } - int major = 10, minor = 0, patch = 0; + unsigned int major = 10, minor = 0, patch = 0; if (1 == darwin_major && darwin_minor < 4) { /* 10.0.x */ @@ -1242,17 +1242,18 @@ static bool get_device_port (io_service_t service, UInt8 *port) { /* Returns 1 on success, 0 on failure. */ static bool get_device_parent_sessionID(io_service_t service, UInt64 *parent_sessionID) { - IOReturn kresult; - io_service_t parent; - /* Walk up the tree in the IOService plane until we find a parent that has a sessionID */ - parent = service; - while((kresult = IORegistryEntryGetParentEntry (parent, kIOUSBPlane, &parent)) == kIOReturnSuccess) { + io_service_t parent = service; + do { + IOReturn kresult = IORegistryEntryGetParentEntry (parent, kIOUSBPlane, &parent); + if (kresult != kIOReturnSuccess) { + break; + } if (get_ioregistry_value_number (parent, CFSTR("sessionID"), kCFNumberSInt64Type, parent_sessionID)) { /* Success */ return true; } - } + } while (true); /* We ran out of parents */ return false; @@ -1361,6 +1362,8 @@ static enum libusb_error darwin_get_cached_device(struct libusb_context *ctx, io usbi_mutex_unlock(&darwin_cached_devices_mutex); + assert((ret == LIBUSB_SUCCESS) ? (*cached_out != NULL) : true); + return ret; } @@ -1435,6 +1438,9 @@ static enum libusb_error process_new_device (struct libusb_context *ctx, struct #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 case kUSBDeviceSpeedSuperPlus: dev->speed = LIBUSB_SPEED_SUPER_PLUS; break; #endif +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101500 + case kUSBDeviceSpeedSuperPlusBy2: dev->speed = LIBUSB_SPEED_SUPER_PLUS_X2; break; +#endif default: usbi_warn (ctx, "Got unknown device speed %d", devSpeed); } @@ -1471,6 +1477,7 @@ static enum libusb_error darwin_scan_devices(struct libusb_context *ctx) { while ((service = IOIteratorNext (deviceIterator))) { ret = darwin_get_cached_device (ctx, service, &cached_device, &old_session_id); + assert((ret >= 0) ? (cached_device != NULL) : true); if (ret < 0 || !cached_device->can_enumerate) { continue; } @@ -1868,9 +1875,10 @@ static int darwin_release_interface(struct libusb_device_handle *dev_handle, uin if (kresult != kIOReturnSuccess) usbi_warn (HANDLE_CTX (dev_handle), "USBInterfaceClose: %s", darwin_error_str(kresult)); - kresult = (*IOINTERFACE(cInterface))->Release(IOINTERFACE(cInterface)); - if (kresult != kIOReturnSuccess) - usbi_warn (HANDLE_CTX (dev_handle), "Release: %s", darwin_error_str(kresult)); + ULONG refCount = (*IOINTERFACE(cInterface))->Release(IOINTERFACE(cInterface)); + if (refCount != 0) { + usbi_warn (HANDLE_CTX (dev_handle), "Release final refCount: %u", refCount); + } IOINTERFACE(cInterface) = NULL; @@ -1972,7 +1980,7 @@ static int darwin_clear_halt(struct libusb_device_handle *dev_handle, unsigned c return darwin_to_libusb (kresult); } -static int darwin_restore_state (struct libusb_device_handle *dev_handle, int8_t active_config, +static int darwin_restore_state (struct libusb_device_handle *dev_handle, uint8_t active_config, unsigned long claimed_interfaces) { struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle); @@ -2037,7 +2045,7 @@ static int darwin_restore_state (struct libusb_device_handle *dev_handle, int8_t static int darwin_reenumerate_device (struct libusb_device_handle *dev_handle, bool capture) { struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); unsigned long claimed_interfaces = dev_handle->claimed_interfaces; - int8_t active_config = dpriv->active_config; + uint8_t active_config = dpriv->active_config; UInt32 options = 0; IOUSBDeviceDescriptor descriptor; IOUSBConfigurationDescriptorPtr cached_configuration; @@ -2100,8 +2108,10 @@ static int darwin_reenumerate_device (struct libusb_device_handle *dev_handle, b struct timespec now; usbi_get_monotonic_time(&now); - unsigned long elapsed_us = (now.tv_sec - start.tv_sec) * USEC_PER_SEC + - (now.tv_nsec - start.tv_nsec) / 1000; + long delta_sec = now.tv_sec - start.tv_sec; + long delta_nsec = now.tv_nsec - start.tv_nsec; + unsigned long long elapsed_us = (unsigned long long)delta_sec * USEC_PER_SEC + + (unsigned long long)delta_nsec / 1000ULL; if (elapsed_us >= DARWIN_REENUMERATE_TIMEOUT_US) { usbi_err (ctx, "darwin/reenumerate_device: timeout waiting for reenumerate"); @@ -2150,7 +2160,7 @@ static int darwin_reset_device (struct libusb_device_handle *dev_handle) { ret = darwin_reenumerate_device (dev_handle, false); if ((ret == LIBUSB_SUCCESS || ret == LIBUSB_ERROR_NOT_FOUND) && dpriv->capture_count > 0) { int capture_count; - int8_t active_config = dpriv->active_config; + uint8_t active_config = dpriv->active_config; unsigned long claimed_interfaces = dev_handle->claimed_interfaces; /* save old capture_count */ @@ -2888,15 +2898,26 @@ const struct usbi_os_backend usbi_backend = { .caps = USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER, .init = darwin_init, .exit = darwin_exit, - .get_active_config_descriptor = darwin_get_active_config_descriptor, - .get_config_descriptor = darwin_get_config_descriptor, + .set_option = NULL, + .get_device_list = NULL, .hotplug_poll = darwin_hotplug_poll, - + .wrap_sys_device = NULL, .open = darwin_open, .close = darwin_close, + .get_active_config_descriptor = darwin_get_active_config_descriptor, + .get_config_descriptor = darwin_get_config_descriptor, + .get_config_descriptor_by_value = NULL, .get_configuration = darwin_get_configuration, .set_configuration = darwin_set_configuration, +#if MAX_INTERFACE_VERSION >= 700 + .claim_interface = darwin_capture_claim_interface, + .release_interface = darwin_capture_release_interface, +#else + .claim_interface = darwin_claim_interface, + .release_interface = darwin_release_interface, +#endif + .set_interface_altsetting = darwin_set_interface_altsetting, .clear_halt = darwin_clear_halt, .reset_device = darwin_reset_device, @@ -2906,25 +2927,24 @@ const struct usbi_os_backend usbi_backend = { .free_streams = darwin_free_streams, #endif + .dev_mem_alloc = NULL, + .dev_mem_free = NULL, .kernel_driver_active = darwin_kernel_driver_active, #if MAX_INTERFACE_VERSION >= 700 .detach_kernel_driver = darwin_detach_kernel_driver, .attach_kernel_driver = darwin_attach_kernel_driver, - .claim_interface = darwin_capture_claim_interface, - .release_interface = darwin_capture_release_interface, -#else - .claim_interface = darwin_claim_interface, - .release_interface = darwin_release_interface, #endif .destroy_device = darwin_destroy_device, .submit_transfer = darwin_submit_transfer, .cancel_transfer = darwin_cancel_transfer, - + .clear_transfer_priv = NULL, + .handle_events = NULL, .handle_transfer_completion = darwin_handle_transfer_completion, + .context_priv_size = 0, .device_priv_size = sizeof(struct darwin_device_priv), .device_handle_priv_size = sizeof(struct darwin_device_handle_priv), .transfer_priv_size = sizeof(struct darwin_transfer_priv), diff --git a/libusb/os/emscripten_webusb.cpp b/libusb/os/emscripten_webusb.cpp index f19c1bd..ced9ad8 100644 --- a/libusb/os/emscripten_webusb.cpp +++ b/libusb/os/emscripten_webusb.cpp @@ -844,7 +844,7 @@ int em_handle_transfer_completion(usbi_transfer* itransfer) { #pragma clang diagnostic ignored "-Wmissing-field-initializers" extern "C" const usbi_os_backend usbi_backend = { .name = "Emscripten + WebUSB backend", - .caps = LIBUSB_CAP_HAS_CAPABILITY, + .caps = 0, .get_device_list = em_get_device_list, .open = em_open, .close = em_close, diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c index ed8597b..25ee02e 100644 --- a/libusb/os/linux_usbfs.c +++ b/libusb/os/linux_usbfs.c @@ -933,6 +933,7 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, case 480: dev->speed = LIBUSB_SPEED_HIGH; break; case 5000: dev->speed = LIBUSB_SPEED_SUPER; break; case 10000: dev->speed = LIBUSB_SPEED_SUPER_PLUS; break; + case 20000: dev->speed = LIBUSB_SPEED_SUPER_PLUS_X2; break; default: usbi_warn(ctx, "unknown device speed: %d Mbps", speed); } diff --git a/libusb/os/sunos_usb.c b/libusb/os/sunos_usb.c index 6c8250c..d7be7de 100644 --- a/libusb/os/sunos_usb.c +++ b/libusb/os/sunos_usb.c @@ -86,7 +86,7 @@ static int sunos_get_link(di_devlink_t devlink, void *arg) const char *p; const char *q; - if (larg->path) { + if (link_arg->path) { char *content = (char *)di_devlink_content(devlink); char *start = strstr(content, "/devices/"); start += strlen("/devices"); @@ -94,8 +94,8 @@ static int sunos_get_link(di_devlink_t devlink, void *arg) /* line content must have minor node */ if (start == NULL || - strncmp(start, larg->path, larg->len) != 0 || - start[larg->len] != ':') + strncmp(start, link_arg->path, link_arg->len) != 0 || + start[link_arg->len] != ':') return (DI_WALK_CONTINUE); } @@ -103,7 +103,7 @@ static int sunos_get_link(di_devlink_t devlink, void *arg) q = strrchr(p, '/'); usbi_dbg(NULL, "%s", q); - *(larg->linkpp) = strndup(p, strlen(p) - strlen(q)); + *(link_arg->linkpp) = strndup(p, strlen(p) - strlen(q)); return (DI_WALK_TERMINATE); } diff --git a/libusb/os/threads_posix.c b/libusb/os/threads_posix.c index 0079fd5..2e6d942 100644 --- a/libusb/os/threads_posix.c +++ b/libusb/os/threads_posix.c @@ -22,6 +22,7 @@ #include "libusbi.h" #include <errno.h> +#include <limits.h> #if defined(__ANDROID__) # include <unistd.h> #elif defined(__HAIKU__) @@ -79,47 +80,47 @@ int usbi_cond_timedwait(pthread_cond_t *cond, return LIBUSB_ERROR_OTHER; } -unsigned int usbi_get_tid(void) +unsigned long usbi_get_tid(void) { - static _Thread_local unsigned int tl_tid; - int tid; + static _Thread_local unsigned long tl_tid; + unsigned long tid; if (tl_tid) return tl_tid; #if defined(__ANDROID__) - tid = gettid(); + tid = (unsigned long)gettid(); #elif defined(__APPLE__) #ifdef HAVE_PTHREAD_THREADID_NP uint64_t thread_id; if (pthread_threadid_np(NULL, &thread_id) == 0) - tid = (int)thread_id; + tid = (unsigned long)thread_id; else - tid = -1; + tid = ULONG_MAX; #else - tid = (int)pthread_mach_thread_np(pthread_self()); + tid = (unsigned long)pthread_mach_thread_np(pthread_self()); #endif #elif defined(__HAIKU__) - tid = get_pthread_thread_id(pthread_self()); + tid = (unsigned long)get_pthread_thread_id(pthread_self()); #elif defined(__linux__) - tid = (int)syscall(SYS_gettid); + tid = (unsigned long)syscall(SYS_gettid); #elif defined(__NetBSD__) - tid = _lwp_self(); + tid = (unsigned long)_lwp_self(); #elif defined(__OpenBSD__) - tid = getthrid(); + tid = (unsigned long)getthrid(); #elif defined(__sun__) - tid = _lwp_self(); + tid = (unsigned long)_lwp_self(); #else - tid = -1; + tid = ULONG_MAX; #endif - if (tid == -1) { + if (tid == ULONG_MAX) { /* If we don't have a thread ID, at least return a unique * value that can be used to distinguish individual * threads. */ - tid = (int)(intptr_t)pthread_self(); + tid = (unsigned long)(uintptr_t)pthread_self(); } - return tl_tid = (unsigned int)tid; + return tl_tid = tid; } diff --git a/libusb/os/threads_posix.h b/libusb/os/threads_posix.h index 9322834..e6096ed 100644 --- a/libusb/os/threads_posix.h +++ b/libusb/os/threads_posix.h @@ -93,6 +93,6 @@ static inline void usbi_tls_key_delete(usbi_tls_key_t key) PTHREAD_CHECK(pthread_key_delete(key)); } -unsigned int usbi_get_tid(void); +unsigned long usbi_get_tid(void); #endif /* LIBUSB_THREADS_POSIX_H */ diff --git a/libusb/os/threads_windows.h b/libusb/os/threads_windows.h index dfef158..8c9cfb4 100644 --- a/libusb/os/threads_windows.h +++ b/libusb/os/threads_windows.h @@ -105,9 +105,9 @@ static inline void usbi_tls_key_delete(usbi_tls_key_t key) WINAPI_CHECK(TlsFree(key)); } -static inline unsigned int usbi_get_tid(void) +static inline unsigned long usbi_get_tid(void) { - return (unsigned int)GetCurrentThreadId(); + return (unsigned long)GetCurrentThreadId(); } #endif /* LIBUSB_THREADS_WINDOWS_H */ diff --git a/libusb/os/windows_winusb.c b/libusb/os/windows_winusb.c index 926b9e8..65d288f 100644 --- a/libusb/os/windows_winusb.c +++ b/libusb/os/windows_winusb.c @@ -1572,7 +1572,6 @@ static int get_guid(struct libusb_context *ctx, char *dev_id, HDEVINFO *dev_info usbi_warn(ctx, "device '%s' has malformed DeviceInterfaceGUID string '%s', skipping", dev_id, guid); free(*if_guid); *if_guid = NULL; - err = LIBUSB_ERROR_NO_MEM; goto exit; } @@ -1767,7 +1766,7 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_ } // ...and to add the additional device interface GUIDs r = get_guid(ctx, dev_id, dev_info, &dev_info_data, 0, &if_guid); - if (r == LIBUSB_SUCCESS) { + if (r == LIBUSB_SUCCESS && if_guid != NULL) { // Check if we've already seen this GUID for (j = EXT_PASS; j < nb_guids; j++) { if (memcmp(guid_list[j], if_guid, sizeof(*if_guid)) == 0) @@ -1796,7 +1795,9 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_ } else if (r == LIBUSB_ERROR_NO_MEM) { LOOP_BREAK(LIBUSB_ERROR_NO_MEM); } else { - usbi_warn(ctx, "unexpected error during getting DeviceInterfaceGUID for '%s'", dev_id); + if (r != LIBUSB_SUCCESS) { + usbi_warn(ctx, "unexpected error during getting DeviceInterfaceGUID for '%s'", dev_id); + } } break; case HID_PASS: diff --git a/libusb/sync.c b/libusb/sync.c index 146cce2..733927d 100644 --- a/libusb/sync.c +++ b/libusb/sync.c @@ -22,6 +22,7 @@ #include "libusbi.h" +#include <assert.h> #include <string.h> /** @@ -139,7 +140,7 @@ int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle, if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) memcpy(data, libusb_control_transfer_get_data(transfer), - transfer->actual_length); + (size_t)transfer->actual_length); switch (transfer->status) { case LIBUSB_TRANSFER_COMPLETED: @@ -198,8 +199,10 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle, sync_transfer_wait_for_completion(transfer); - if (transferred) + if (transferred) { + assert(transfer->actual_length >= 0); *transferred = transfer->actual_length; + } switch (transfer->status) { case LIBUSB_TRANSFER_COMPLETED: @@ -312,9 +315,9 @@ int API_EXPORTED libusb_bulk_transfer(libusb_device_handle *dev_handle, * \param length for bulk writes, the number of bytes from data to be sent. for * bulk reads, the maximum number of bytes to receive into the data buffer. * \param transferred output location for the number of bytes actually - * transferred. Since version 1.0.21 (\ref LIBUSB_API_VERSION >= 0x01000105), - * it is legal to pass a NULL pointer if you do not wish to receive this - * information. + * transferred. Will never be negative. Since version 1.0.21 + * (\ref LIBUSB_API_VERSION >= 0x01000105), it is legal to pass a NULL + * pointer if you do not wish to receive this information. * \param timeout timeout (in milliseconds) that this function should wait * before giving up due to no response being received. For an unlimited * timeout, use value 0. diff --git a/libusb/version_nano.h b/libusb/version_nano.h index a6165f3..d4f0bc9 100644 --- a/libusb/version_nano.h +++ b/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 11882 +#define LIBUSB_NANO 11899 diff --git a/tests/macos.c b/tests/macos.c index a7b1231..5dc3ba3 100644 --- a/tests/macos.c +++ b/tests/macos.c @@ -71,8 +71,8 @@ extern uint32_t libusb_testonly_fake_running_version; -extern int libusb_testonly_using_running_interface_version; -extern int libusb_testonly_using_running_device_version; +extern uint32_t libusb_testonly_using_running_interface_version; +extern uint32_t libusb_testonly_using_running_device_version; extern bool libusb_testonly_clear_running_version_cache; static libusb_testlib_result test_macos_version_fallback(void) { |