Upgrade libusb to fef78a96e37936f16c10c43c9a220683f7c2ff74

This project was upgraded with external_updater.
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

Test: TreeHugger
Change-Id: I52801e891e1a773c5963d80eeda6673f144557e6
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: "*"
+...
diff --git a/Android.bp b/Android.bp
index 93e5c1b..c9e49a4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -62,6 +62,7 @@
         "-Wno-error=switch",
         "-Wno-error=unused-function",
         "-Wno-unused-parameter",
+"-DENABLE_LOGGING=1",
     ],
 
     target: {
diff --git a/METADATA b/METADATA
index a58a804..bcf5c95 100644
--- a/METADATA
+++ b/METADATA
@@ -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 @@
   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_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 @@
         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 @@
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 		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 @@
 	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 @@
 		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 @@
 	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 @@
 		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 @@
 		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 @@
 			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 @@
 		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 @@
 	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 @@
 			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 @@
 		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 @@
 			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 @@
 		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 @@
 		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 @@
  */
 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 @@
 		_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 @@
 		TIMESPEC_SUB(&timestamp, &timestamp_origin, &timestamp);
 
 		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 @@
 			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 @@
 	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 @@
 				goto err;
 			}
 
-			memcpy(extra, begin, len);
+			memcpy(extra, begin, (size_t)len);
 			ifp->extra = extra;
 			ifp->extra_length = len;
 		}
@@ -431,7 +436,7 @@
 				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 @@
 	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 @@
 
 	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 @@
 	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 @@
 		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 @@
 		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 @@
 	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 @@
   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 @@
   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 @@
 /* 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 @@
 	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 @@
 };
 
 /** \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 @@
 	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 @@
 	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 @@
 #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 @@
 #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 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 @@
   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 @@
   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 @@
    * 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 @@
   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 @@
 
 /* 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 @@
 
   usbi_mutex_unlock(&darwin_cached_devices_mutex);
 
+  assert((ret == LIBUSB_SUCCESS) ? (*cached_out != NULL) : true);
+
   return ret;
 }
 
@@ -1435,6 +1438,9 @@
 #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 @@
 
   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 @@
   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 @@
   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_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 @@
 
     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 @@
   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 @@
         .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 @@
         .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 @@
 #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 @@
 			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 @@
 	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 @@
 
 		/* 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 @@
 	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 @@
 		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 @@
 	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 @@
 	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 @@
 		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 @@
 				}
 				// ...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 @@
 				} 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 @@
 
 	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 @@
 
 	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 @@
  * \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) {