usb 2.17.0 → 2.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +14 -0
  3. package/binding.gyp +2 -9
  4. package/dist/usb/bindings.d.ts +27 -2
  5. package/dist/usb/bindings.js.map +1 -1
  6. package/dist/usb/index.d.ts +0 -29
  7. package/dist/usb/index.js +4 -18
  8. package/dist/usb/index.js.map +1 -1
  9. package/libusb/.clang-tidy +5 -3
  10. package/libusb/.private/ci-build.sh +5 -1
  11. package/libusb/AUTHORS +14 -0
  12. package/libusb/ChangeLog +15 -2
  13. package/libusb/README +8 -5
  14. package/libusb/Xcode/libusb.xcodeproj/project.pbxproj +4 -0
  15. package/libusb/configure.ac +12 -2
  16. package/libusb/examples/hotplugtest.c +19 -11
  17. package/libusb/examples/listdevs.c +41 -3
  18. package/libusb/examples/xusb.c +6 -1
  19. package/libusb/libusb/Makefile.am +4 -0
  20. package/libusb/libusb/core.c +175 -14
  21. package/libusb/libusb/descriptor.c +163 -14
  22. package/libusb/libusb/io.c +7 -3
  23. package/libusb/libusb/libusb-1.0.def +10 -0
  24. package/libusb/libusb/libusb.h +59 -9
  25. package/libusb/libusb/libusbi.h +89 -25
  26. package/libusb/libusb/os/darwin_usb.c +126 -46
  27. package/libusb/libusb/os/darwin_usb.h +10 -8
  28. package/libusb/libusb/os/emscripten_webusb.cpp +31 -10
  29. package/libusb/libusb/os/haiku_usb_raw.cpp +4 -0
  30. package/libusb/libusb/os/linux_usbfs.c +73 -25
  31. package/libusb/libusb/os/netbsd_usb.c +2 -0
  32. package/libusb/libusb/os/openbsd_usb.c +2 -0
  33. package/libusb/libusb/os/sunos_usb.c +2 -0
  34. package/libusb/libusb/os/threads_posix.c +3 -3
  35. package/libusb/libusb/os/threads_posix.h +8 -2
  36. package/libusb/libusb/os/threads_windows.h +2 -1
  37. package/libusb/libusb/os/windows_common.c +86 -1
  38. package/libusb/libusb/os/windows_common.h +20 -1
  39. package/libusb/libusb/os/windows_hotplug.c +321 -0
  40. package/libusb/libusb/os/windows_hotplug.h +28 -0
  41. package/libusb/libusb/os/windows_usbdk.c +16 -8
  42. package/libusb/libusb/os/windows_winusb.c +753 -41
  43. package/libusb/libusb/os/windows_winusb.h +11 -6
  44. package/libusb/libusb/version.h +1 -1
  45. package/libusb/libusb/version_nano.h +1 -1
  46. package/libusb/msvc/Base.props +1 -1
  47. package/libusb/msvc/Configuration.Base.props +2 -1
  48. package/libusb/msvc/Configuration.DynamicLibrary.props +12 -0
  49. package/libusb/msvc/ProjectConfigurations.Base.props +69 -16
  50. package/libusb/msvc/build_all.ps1 +2 -2
  51. package/libusb/msvc/config.h +4 -0
  52. package/libusb/msvc/getopt/bits/getopt_core.h +96 -0
  53. package/libusb/msvc/getopt/bits/getopt_ext.h +77 -0
  54. package/libusb/msvc/getopt/features.h +21 -0
  55. package/libusb/msvc/getopt/getopt.c +456 -705
  56. package/libusb/msvc/getopt/getopt.h +16 -158
  57. package/libusb/msvc/getopt/getopt1.c +40 -69
  58. package/libusb/msvc/getopt/getopt_int.h +118 -0
  59. package/libusb/msvc/getopt/gettext.h +7 -0
  60. package/libusb/msvc/getopt/unistd.h +5 -0
  61. package/libusb/msvc/getopt.vcxproj +11 -4
  62. package/libusb/msvc/libusb.sln +515 -268
  63. package/libusb/msvc/libusb_dll.vcxproj +2 -0
  64. package/libusb/msvc/libusb_static.vcxproj +2 -0
  65. package/libusb/msvc/xusb.vcxproj +1 -1
  66. package/libusb/tests/Makefile.am +10 -1
  67. package/libusb/tests/fuzz/corpus/bos/min.bos +0 -0
  68. package/libusb/tests/fuzz/corpus/descriptor_parsers/min_valid_config.bin +0 -0
  69. package/libusb/tests/fuzz/corpus/descriptor_parsers/regression_bug_a_endpoint_null.bin +0 -0
  70. package/libusb/tests/fuzz/corpus/descriptor_parsers/regression_bug_b_iad_oob.bin +0 -0
  71. package/libusb/tests/fuzz/fuzz_bos_descriptor.c +49 -0
  72. package/libusb/tests/fuzz/fuzz_descriptor_parsers.c +83 -0
  73. package/libusb/tests/stress_mt.c +2 -1
  74. package/libusb/tests/webusb-test-shim/index.js +6 -5
  75. package/libusb.gypi +5 -0
  76. package/package.json +1 -1
  77. package/prebuilds/android-arm/node.napi.armv7.node +0 -0
  78. package/prebuilds/android-arm64/node.napi.armv8.node +0 -0
  79. package/prebuilds/darwin-x64+arm64/node.napi.node +0 -0
  80. package/prebuilds/linux-arm/node.napi.armv6.node +0 -0
  81. package/prebuilds/linux-arm/node.napi.armv7.node +0 -0
  82. package/prebuilds/linux-arm64/node.napi.armv8.node +0 -0
  83. package/prebuilds/linux-ia32/node.napi.node +0 -0
  84. package/prebuilds/linux-x64/node.napi.glibc.node +0 -0
  85. package/prebuilds/linux-x64/node.napi.musl.node +0 -0
  86. package/prebuilds/win32-arm64/node.napi.node +0 -0
  87. package/prebuilds/win32-ia32/node.napi.node +0 -0
  88. package/prebuilds/win32-x64/node.napi.node +0 -0
  89. package/src/{hotplug/libusb.cc → hotplug.cc} +2 -3
  90. package/src/{hotplug/hotplug.h → hotplug.h} +2 -6
  91. package/src/node_usb.cc +3 -3
  92. package/test/usb.coffee +4 -4
  93. package/test/webusb.coffee +22 -12
  94. package/src/hotplug/windows.cc +0 -168
@@ -49,24 +49,24 @@
49
49
 
50
50
  #include "darwin_usb.h"
51
51
 
52
- static int init_count = 0;
53
-
54
52
  /* Both kIOMasterPortDefault or kIOMainPortDefault are synonyms for 0. */
55
53
  static const mach_port_t darwin_default_master_port = 0;
56
54
 
57
55
  /* async event thread */
58
56
  /* if both this mutex and darwin_cached_devices_mutex are to be acquired then
59
57
  darwin_cached_devices_mutex must be acquired first. */
60
- static pthread_mutex_t libusb_darwin_at_mutex = PTHREAD_MUTEX_INITIALIZER;
61
- static pthread_cond_t libusb_darwin_at_cond = PTHREAD_COND_INITIALIZER;
58
+ static usbi_mutex_static_t libusb_darwin_at_mutex = USBI_MUTEX_INITIALIZER;
59
+ static usbi_cond_t libusb_darwin_at_cond = USBI_COND_INITIALIZER;
62
60
 
63
61
  #define LIBUSB_DARWIN_STARTUP_FAILURE ((CFRunLoopRef) -1)
64
62
 
65
63
  static CFRunLoopRef libusb_darwin_acfl = NULL; /* event cf loop */
66
64
  static CFRunLoopSourceRef libusb_darwin_acfls = NULL; /* shutdown signal for event cf loop */
67
65
 
68
- static usbi_mutex_t darwin_cached_devices_mutex = PTHREAD_MUTEX_INITIALIZER;
66
+ static usbi_mutex_t darwin_cached_devices_mutex = USBI_MUTEX_INITIALIZER;
69
67
  static struct list_head darwin_cached_devices;
68
+ static int init_count;
69
+
70
70
  static const char *darwin_device_class = "IOUSBDevice";
71
71
 
72
72
  uint32_t libusb_testonly_fake_running_version __attribute__ ((visibility ("hidden")));
@@ -477,6 +477,7 @@ static int ep_to_pipeRef(struct libusb_device_handle *dev_handle, uint8_t ep, ui
477
477
 
478
478
  usbi_dbg (ctx, "converting ep address 0x%02x to pipeRef and interface", ep);
479
479
 
480
+ usbi_mutex_lock(&dev_handle->lock);
480
481
  for (iface = 0 ; iface < USB_MAXINTERFACES ; iface++) {
481
482
  cInterface = &priv->interfaces[iface];
482
483
 
@@ -492,6 +493,7 @@ static int ep_to_pipeRef(struct libusb_device_handle *dev_handle, uint8_t ep, ui
492
493
  *interface_out = cInterface;
493
494
 
494
495
  usbi_dbg (ctx, "pipe %d on interface %d matches", *pipep, iface);
496
+ usbi_mutex_unlock(&dev_handle->lock);
495
497
  return LIBUSB_SUCCESS;
496
498
  }
497
499
  }
@@ -501,6 +503,8 @@ static int ep_to_pipeRef(struct libusb_device_handle *dev_handle, uint8_t ep, ui
501
503
  /* No pipe found with the correct endpoint address */
502
504
  usbi_warn (HANDLE_CTX(dev_handle), "no pipeRef found with endpoint address 0x%02x.", ep);
503
505
 
506
+ usbi_mutex_unlock(&dev_handle->lock);
507
+
504
508
  return LIBUSB_ERROR_NOT_FOUND;
505
509
  }
506
510
 
@@ -595,7 +599,8 @@ static int darwin_device_from_service (struct libusb_context *ctx, io_service_t
595
599
  usbi_dbg (ctx, "set up plugin for service retry: %s", darwin_error_str (kresult));
596
600
 
597
601
  /* sleep for a little while before trying again */
598
- nanosleep(&(struct timespec){.tv_sec = 0, .tv_nsec = 1000}, NULL);
602
+ const struct timespec delay = {.tv_sec = 0, .tv_nsec = 1000};
603
+ nanosleep(&delay, NULL);
599
604
  }
600
605
 
601
606
  if (kIOReturnSuccess != kresult) {
@@ -608,7 +613,7 @@ static int darwin_device_from_service (struct libusb_context *ctx, io_service_t
608
613
  }
609
614
 
610
615
  (void)(*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(get_device_interface_id()),
611
- (LPVOID)device);
616
+ (LPVOID *)device);
612
617
  /* Use release instead of IODestroyPlugInInterface to avoid stopping IOServices associated with this device */
613
618
  (*plugInInterface)->Release (plugInInterface);
614
619
 
@@ -636,9 +641,8 @@ static void darwin_devices_attached (void *ptr, io_iterator_t add_devices) {
636
641
  process_new_device (ctx, cached_device, old_session_id);
637
642
  }
638
643
 
639
- if (cached_device->in_reenumerate) {
644
+ if (atomic_exchange(&cached_device->in_reenumerate, false)) {
640
645
  usbi_dbg (NULL, "cached device in reset state. reset complete...");
641
- cached_device->in_reenumerate = false;
642
646
  }
643
647
 
644
648
  IOObjectRelease(service);
@@ -674,7 +678,7 @@ static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) {
674
678
  usbi_mutex_lock(&darwin_cached_devices_mutex);
675
679
  list_for_each_entry(old_device, &darwin_cached_devices, list, struct darwin_cached_device) {
676
680
  if (old_device->session == session) {
677
- if (old_device->in_reenumerate) {
681
+ if (atomic_load(&old_device->in_reenumerate)) {
678
682
  /* device is re-enumerating. do not dereference the device at this time. libusb_reset_device()
679
683
  * will deref if needed. */
680
684
  usbi_dbg (NULL, "detected device detached due to re-enumeration. sessionID: 0x%" PRIx64
@@ -735,10 +739,10 @@ static void darwin_clear_iterator (io_iterator_t iter) {
735
739
  }
736
740
 
737
741
  static void darwin_fail_startup(void) {
738
- pthread_mutex_lock (&libusb_darwin_at_mutex);
742
+ usbi_mutex_lock (&libusb_darwin_at_mutex);
739
743
  libusb_darwin_acfl = LIBUSB_DARWIN_STARTUP_FAILURE;
740
- pthread_cond_signal (&libusb_darwin_at_cond);
741
- pthread_mutex_unlock (&libusb_darwin_at_mutex);
744
+ usbi_cond_signal (&libusb_darwin_at_cond);
745
+ usbi_mutex_unlock (&libusb_darwin_at_mutex);
742
746
  pthread_exit (NULL);
743
747
  }
744
748
 
@@ -822,11 +826,11 @@ static void *darwin_event_thread_main (void *arg0) {
822
826
  usbi_dbg (NULL, "darwin event thread ready to receive events");
823
827
 
824
828
  /* signal the main thread that the hotplug runloop has been created. */
825
- pthread_mutex_lock (&libusb_darwin_at_mutex);
829
+ usbi_mutex_lock (&libusb_darwin_at_mutex);
826
830
  libusb_darwin_acfl = runloop;
827
831
  libusb_darwin_acfls = libusb_shutdown_cfsource;
828
- pthread_cond_signal (&libusb_darwin_at_cond);
829
- pthread_mutex_unlock (&libusb_darwin_at_mutex);
832
+ usbi_cond_signal (&libusb_darwin_at_cond);
833
+ usbi_mutex_unlock (&libusb_darwin_at_mutex);
830
834
 
831
835
  /* run the runloop */
832
836
  CFRunLoopRun();
@@ -834,11 +838,11 @@ static void *darwin_event_thread_main (void *arg0) {
834
838
  usbi_dbg (NULL, "darwin event thread exiting");
835
839
 
836
840
  /* signal the main thread that the hotplug runloop has finished. */
837
- pthread_mutex_lock (&libusb_darwin_at_mutex);
841
+ usbi_mutex_lock (&libusb_darwin_at_mutex);
838
842
  libusb_darwin_acfls = NULL;
839
843
  libusb_darwin_acfl = NULL;
840
- pthread_cond_signal (&libusb_darwin_at_cond);
841
- pthread_mutex_unlock (&libusb_darwin_at_mutex);
844
+ usbi_cond_signal (&libusb_darwin_at_cond);
845
+ usbi_mutex_unlock (&libusb_darwin_at_mutex);
842
846
 
843
847
  /* remove the notification cfsource */
844
848
  CFRunLoopRemoveSource(runloop, libusb_notification_cfsource, kCFRunLoopDefaultMode);
@@ -898,17 +902,17 @@ static int darwin_first_time_init(void) {
898
902
  return LIBUSB_ERROR_OTHER;
899
903
  }
900
904
 
901
- pthread_mutex_lock (&libusb_darwin_at_mutex);
905
+ usbi_mutex_lock (&libusb_darwin_at_mutex);
902
906
  libusb_darwin_at_started = true;
903
907
  while (NULL == libusb_darwin_acfl) {
904
- pthread_cond_wait (&libusb_darwin_at_cond, &libusb_darwin_at_mutex);
908
+ usbi_cond_wait (&libusb_darwin_at_cond, &libusb_darwin_at_mutex);
905
909
  }
906
910
 
907
911
  if (libusb_darwin_acfl == LIBUSB_DARWIN_STARTUP_FAILURE) {
908
912
  libusb_darwin_acfl = NULL;
909
913
  rc = LIBUSB_ERROR_OTHER;
910
914
  }
911
- pthread_mutex_unlock (&libusb_darwin_at_mutex);
915
+ usbi_mutex_unlock (&libusb_darwin_at_mutex);
912
916
 
913
917
  return rc;
914
918
  }
@@ -946,25 +950,78 @@ static void darwin_exit (struct libusb_context *ctx) {
946
950
  usbi_mutex_lock(&darwin_cached_devices_mutex);
947
951
  if (0 == --init_count) {
948
952
  /* stop the event runloop and wait for the thread to terminate. */
949
- pthread_mutex_lock (&libusb_darwin_at_mutex);
953
+ usbi_mutex_lock (&libusb_darwin_at_mutex);
950
954
  if (NULL != libusb_darwin_acfls) {
951
955
  CFRunLoopSourceSignal (libusb_darwin_acfls);
952
956
  CFRunLoopWakeUp (libusb_darwin_acfl);
953
957
  while (libusb_darwin_acfl)
954
- pthread_cond_wait (&libusb_darwin_at_cond, &libusb_darwin_at_mutex);
958
+ usbi_cond_wait (&libusb_darwin_at_cond, &libusb_darwin_at_mutex);
955
959
  }
956
960
 
957
961
  if (libusb_darwin_at_started) {
958
962
  pthread_join (libusb_darwin_at, NULL);
959
963
  libusb_darwin_at_started = false;
960
964
  }
961
- pthread_mutex_unlock (&libusb_darwin_at_mutex);
965
+ usbi_mutex_unlock (&libusb_darwin_at_mutex);
962
966
 
963
967
  darwin_cleanup_devices ();
964
968
  }
965
969
  usbi_mutex_unlock(&darwin_cached_devices_mutex);
966
970
  }
967
971
 
972
+ static int darwin_get_device_string(struct libusb_device *dev,
973
+ enum libusb_device_string_type string_type, char *buffer, int length) {
974
+
975
+ if (length <= 0)
976
+ return LIBUSB_ERROR_INVALID_PARAM;
977
+
978
+ struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev);
979
+ io_iterator_t deviceIterator;
980
+ io_service_t service;
981
+ kern_return_t kresult;
982
+ CFStringRef cf;
983
+
984
+ kresult = usb_setup_device_iterator (&deviceIterator, priv->location);
985
+ if (kresult != kIOReturnSuccess)
986
+ return darwin_to_libusb (kresult);
987
+
988
+ service = IOIteratorNext (deviceIterator);
989
+ IOObjectRelease(deviceIterator);
990
+ if (service == IO_OBJECT_NULL)
991
+ return LIBUSB_ERROR_NOT_FOUND;
992
+
993
+ switch (string_type) {
994
+ case LIBUSB_DEVICE_STRING_MANUFACTURER:
995
+ cf = IORegistryEntryCreateCFProperty(service, CFSTR(kUSBVendorString), kCFAllocatorDefault, 0);
996
+ break;
997
+ case LIBUSB_DEVICE_STRING_PRODUCT:
998
+ cf = IORegistryEntryCreateCFProperty(service, CFSTR(kUSBProductString), kCFAllocatorDefault, 0);
999
+ break;
1000
+ case LIBUSB_DEVICE_STRING_SERIAL_NUMBER:
1001
+ cf = IORegistryEntryCreateCFProperty(service, CFSTR(kUSBSerialNumberString), kCFAllocatorDefault, 0);
1002
+ break;
1003
+ case LIBUSB_DEVICE_STRING_COUNT: /* intentional fall-through, avoid -Wswitch-enum */
1004
+ default:
1005
+ IOObjectRelease(service);
1006
+ return LIBUSB_ERROR_INVALID_PARAM;
1007
+ }
1008
+
1009
+ IOObjectRelease(service);
1010
+ if (cf == NULL)
1011
+ return LIBUSB_ERROR_NOT_FOUND;
1012
+
1013
+ long cfUsedIndex = 0;
1014
+ CFStringGetBytes(cf, CFRangeMake(0, CFStringGetLength(cf)), kCFStringEncodingUTF8, '?', false,
1015
+ (uint8_t *) buffer, length - 1, &cfUsedIndex);
1016
+ CFRelease(cf);
1017
+
1018
+ if (cfUsedIndex <= 0)
1019
+ return LIBUSB_ERROR_NOT_FOUND;
1020
+
1021
+ buffer[cfUsedIndex] = '\0';
1022
+ return (int) cfUsedIndex + 1;
1023
+ }
1024
+
968
1025
  static int get_configuration_index (struct libusb_device *dev, UInt8 config_value) {
969
1026
  struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev);
970
1027
  UInt8 i, numConfig;
@@ -977,9 +1034,9 @@ static int get_configuration_index (struct libusb_device *dev, UInt8 config_valu
977
1034
  return darwin_to_libusb (kresult);
978
1035
 
979
1036
  for (i = 0 ; i < numConfig ; i++) {
980
- (*priv->device)->GetConfigurationDescriptorPtr (priv->device, i, &desc);
1037
+ kresult = (*priv->device)->GetConfigurationDescriptorPtr (priv->device, i, &desc);
981
1038
 
982
- if (desc->bConfigurationValue == config_value)
1039
+ if (kresult == kIOReturnSuccess && desc->bConfigurationValue == config_value)
983
1040
  return i;
984
1041
  }
985
1042
 
@@ -1196,7 +1253,8 @@ static enum libusb_error darwin_cache_device_descriptor (struct libusb_context *
1196
1253
  if (kIOReturnSuccess != ret) {
1197
1254
  usbi_dbg(ctx, "kernel responded with code: 0x%08x. sleeping for %ld ms before trying again", ret, delay/1000);
1198
1255
  /* sleep for a little while before trying again */
1199
- nanosleep(&(struct timespec){delay / 1000000, (delay * 1000) % 1000000000}, NULL);
1256
+ struct timespec full_delay = {delay / 1000000, (delay * 1000) % 1000000000};
1257
+ nanosleep(&full_delay, NULL);
1200
1258
  }
1201
1259
  } while (kIOReturnSuccess != ret && retries--);
1202
1260
 
@@ -1258,7 +1316,15 @@ static bool get_device_port (io_service_t service, UInt8 *port) {
1258
1316
 
1259
1317
  kresult = IORegistryEntryGetParentEntry (service, kIOServicePlane, &parent);
1260
1318
  if (kIOReturnSuccess == kresult) {
1261
- ret = get_ioregistry_value_data (parent, CFSTR("port"), 1, port);
1319
+ /*
1320
+ macOS 10 to 15 always had port number property as "port".
1321
+ macOS 26 has changed it to "usb-port-number".
1322
+ For the same binaries to run correctly on both macOS 15 and macOS 26+,
1323
+ we have to detect os version at runtime and use correct port name property.
1324
+ */
1325
+ uint32_t os_version = get_running_version();
1326
+ CFStringRef cfstrPort = os_version < 260000 ? CFSTR("port") : CFSTR("usb-port-number");
1327
+ ret = get_ioregistry_value_data (parent, cfstrPort, 1, port);
1262
1328
  IOObjectRelease (parent);
1263
1329
  }
1264
1330
 
@@ -1315,7 +1381,7 @@ static enum libusb_error darwin_get_cached_device(struct libusb_context *ctx, io
1315
1381
  list_for_each_entry(new_device, &darwin_cached_devices, list, struct darwin_cached_device) {
1316
1382
  usbi_dbg(ctx, "matching sessionID/locationID 0x%" PRIx64 "/0x%" PRIx32 " against cached device with sessionID/locationID 0x%" PRIx64 "/0x%" PRIx32,
1317
1383
  sessionID, locationID, new_device->session, new_device->location);
1318
- if (new_device->location == locationID && new_device->in_reenumerate) {
1384
+ if (new_device->location == locationID && atomic_load(&new_device->in_reenumerate)) {
1319
1385
  usbi_dbg (ctx, "found cached device with matching location that is being re-enumerated");
1320
1386
  *old_session_id = new_device->session;
1321
1387
  break;
@@ -1479,7 +1545,7 @@ static enum libusb_error process_new_device (struct libusb_context *ctx, struct
1479
1545
 
1480
1546
  } while (0);
1481
1547
 
1482
- if (!cached_device->in_reenumerate && 0 == ret) {
1548
+ if (!atomic_load(&cached_device->in_reenumerate) && 0 == ret) {
1483
1549
  usbi_connect_device (dev);
1484
1550
  } else {
1485
1551
  libusb_unref_device (dev);
@@ -1523,6 +1589,10 @@ static int darwin_open (struct libusb_device_handle *dev_handle) {
1523
1589
  IOReturn kresult;
1524
1590
 
1525
1591
  if (0 == dpriv->open_count) {
1592
+ if (!dpriv->device) {
1593
+ usbi_err(HANDLE_CTX(dev_handle), "device interface is NULL, cannot open");
1594
+ return LIBUSB_ERROR_NO_DEVICE;
1595
+ }
1526
1596
  /* try to open the device */
1527
1597
  kresult = (*dpriv->device)->USBDeviceOpenSeize (dpriv->device);
1528
1598
  if (kresult != kIOReturnSuccess) {
@@ -1824,7 +1894,7 @@ static int darwin_claim_interface(struct libusb_device_handle *dev_handle, uint8
1824
1894
  /* Do the actual claim */
1825
1895
  kresult = (*plugInInterface)->QueryInterface(plugInInterface,
1826
1896
  CFUUIDGetUUIDBytes(get_interface_interface_id()),
1827
- (LPVOID)&IOINTERFACE(cInterface));
1897
+ (LPVOID *)&IOINTERFACE(cInterface));
1828
1898
  /* We no longer need the intermediate plug-in */
1829
1899
  /* Use release instead of IODestroyPlugInInterface to avoid stopping IOServices associated with this device */
1830
1900
  (*plugInInterface)->Release (plugInInterface);
@@ -2022,7 +2092,7 @@ static int darwin_restore_state (struct libusb_device_handle *dev_handle, uint8_
2022
2092
  dpriv->open_count = 1;
2023
2093
 
2024
2094
  /* clean up open interfaces */
2025
- (void) darwin_close (dev_handle);
2095
+ darwin_close (dev_handle);
2026
2096
 
2027
2097
  /* re-open the device */
2028
2098
  ret = darwin_open (dev_handle);
@@ -2080,19 +2150,26 @@ static int darwin_reenumerate_device (struct libusb_device_handle *dev_handle, b
2080
2150
 
2081
2151
  struct libusb_context *ctx = HANDLE_CTX (dev_handle);
2082
2152
 
2083
- if (dpriv->in_reenumerate) {
2153
+ if (!dpriv->device) {
2154
+ usbi_warn(ctx, "darwin_reenumerate_device: device interface is NULL");
2155
+ return LIBUSB_ERROR_NO_DEVICE;
2156
+ }
2157
+
2158
+ if (atomic_exchange(&dpriv->in_reenumerate, true)) {
2084
2159
  /* ack, two (or more) threads are trying to reset the device! abort! */
2085
2160
  return LIBUSB_ERROR_NOT_FOUND;
2086
2161
  }
2087
2162
 
2088
- dpriv->in_reenumerate = true;
2089
-
2090
2163
  /* store copies of descriptors so they can be compared after the reset */
2091
2164
  memcpy (&descriptor, &dpriv->dev_descriptor, sizeof (descriptor));
2092
2165
  cached_configurations = alloca (sizeof (*cached_configurations) * descriptor.bNumConfigurations);
2093
2166
 
2094
2167
  for (i = 0 ; i < descriptor.bNumConfigurations ; ++i) {
2095
- (*dpriv->device)->GetConfigurationDescriptorPtr (dpriv->device, i, &cached_configuration);
2168
+ kresult = (*dpriv->device)->GetConfigurationDescriptorPtr (dpriv->device, i, &cached_configuration);
2169
+ if (kresult != kIOReturnSuccess) {
2170
+ atomic_store(&dpriv->in_reenumerate, false);
2171
+ return LIBUSB_ERROR_NOT_FOUND;
2172
+ }
2096
2173
  memcpy (cached_configurations + i, cached_configuration, sizeof (cached_configurations[i]));
2097
2174
  }
2098
2175
 
@@ -2111,14 +2188,14 @@ static int darwin_reenumerate_device (struct libusb_device_handle *dev_handle, b
2111
2188
  kresult = (*dpriv->device)->USBDeviceReEnumerate (dpriv->device, options);
2112
2189
  if (kresult != kIOReturnSuccess) {
2113
2190
  usbi_err (ctx, "USBDeviceReEnumerate: %s", darwin_error_str (kresult));
2114
- dpriv->in_reenumerate = false;
2191
+ atomic_store(&dpriv->in_reenumerate, false);
2115
2192
  return darwin_to_libusb (kresult);
2116
2193
  }
2117
2194
 
2118
2195
  /* capture mode does not re-enumerate but it does require re-open */
2119
2196
  if (capture) {
2120
2197
  usbi_dbg (ctx, "darwin/reenumerate_device: restoring state...");
2121
- dpriv->in_reenumerate = false;
2198
+ atomic_store(&dpriv->in_reenumerate, false);
2122
2199
  return darwin_restore_state (dev_handle, active_config, claimed_interfaces);
2123
2200
  }
2124
2201
 
@@ -2127,19 +2204,19 @@ static int darwin_reenumerate_device (struct libusb_device_handle *dev_handle, b
2127
2204
  struct timespec start;
2128
2205
  usbi_get_monotonic_time(&start);
2129
2206
 
2130
- while (dpriv->in_reenumerate) {
2131
- struct timespec delay = {.tv_sec = 0, .tv_nsec = 1000};
2207
+ while (atomic_load(&dpriv->in_reenumerate)) {
2208
+ const struct timespec delay = {.tv_sec = 0, .tv_nsec = 1000};
2132
2209
  nanosleep (&delay, NULL);
2133
2210
 
2134
2211
  struct timespec now, delta;
2135
2212
  usbi_get_monotonic_time(&now);
2136
2213
  TIMESPEC_SUB(&now, &start, &delta);
2137
- unsigned long long elapsed_us = (unsigned long long)delta.tv_sec * USEC_PER_SEC +
2138
- (unsigned long long)delta.tv_nsec / 1000ULL;
2214
+ unsigned long long elapsed_us = ((unsigned long long)delta.tv_sec * USEC_PER_SEC) +
2215
+ ((unsigned long long)delta.tv_nsec / 1000ULL);
2139
2216
 
2140
2217
  if (elapsed_us >= DARWIN_REENUMERATE_TIMEOUT_US) {
2141
2218
  usbi_err (ctx, "darwin/reenumerate_device: timeout waiting for reenumerate");
2142
- dpriv->in_reenumerate = false;
2219
+ atomic_store(&dpriv->in_reenumerate, false);
2143
2220
  return LIBUSB_ERROR_TIMEOUT;
2144
2221
  }
2145
2222
  }
@@ -2154,8 +2231,8 @@ static int darwin_reenumerate_device (struct libusb_device_handle *dev_handle, b
2154
2231
  }
2155
2232
 
2156
2233
  for (i = 0 ; i < descriptor.bNumConfigurations ; ++i) {
2157
- (void) (*dpriv->device)->GetConfigurationDescriptorPtr (dpriv->device, i, &cached_configuration);
2158
- if (memcmp (cached_configuration, cached_configurations + i, sizeof (cached_configurations[i])) != 0) {
2234
+ kresult = (*dpriv->device)->GetConfigurationDescriptorPtr (dpriv->device, i, &cached_configuration);
2235
+ if (kresult != kIOReturnSuccess || memcmp (cached_configuration, cached_configurations + i, sizeof (cached_configurations[i])) != 0) {
2159
2236
  usbi_dbg (ctx, "darwin/reenumerate_device: configuration descriptor %d changed", i);
2160
2237
  return LIBUSB_ERROR_NOT_FOUND;
2161
2238
  }
@@ -2650,7 +2727,9 @@ static int darwin_handle_transfer_completion (struct usbi_transfer *itransfer) {
2650
2727
  struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
2651
2728
  struct darwin_transfer_priv *tpriv = usbi_get_transfer_priv(itransfer);
2652
2729
  const unsigned char max_transfer_type = LIBUSB_TRANSFER_TYPE_BULK_STREAM;
2730
+ #ifdef ENABLE_LOGGING
2653
2731
  const char *transfer_types[] = {"control", "isoc", "bulk", "interrupt", "bulk-stream", NULL};
2732
+ #endif
2654
2733
  bool is_isoc = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type;
2655
2734
  struct libusb_context *ctx = ITRANSFER_CTX (itransfer);
2656
2735
 
@@ -2926,6 +3005,7 @@ const struct usbi_os_backend usbi_backend = {
2926
3005
  .exit = darwin_exit,
2927
3006
  .set_option = NULL,
2928
3007
  .get_device_list = NULL,
3008
+ .get_device_string = darwin_get_device_string,
2929
3009
  .hotplug_poll = darwin_hotplug_poll,
2930
3010
  .wrap_sys_device = NULL,
2931
3011
  .open = darwin_open,
@@ -117,7 +117,7 @@ struct darwin_cached_device {
117
117
  UInt8 first_config, active_config, port;
118
118
  int can_enumerate;
119
119
  int refcount;
120
- bool in_reenumerate;
120
+ atomic_bool in_reenumerate;
121
121
  int capture_count;
122
122
  };
123
123
 
@@ -125,17 +125,19 @@ struct darwin_device_priv {
125
125
  struct darwin_cached_device *dev;
126
126
  };
127
127
 
128
+ struct darwin_interface {
129
+ usb_interface_t interface;
130
+ uint8_t num_endpoints;
131
+ CFRunLoopSourceRef cfSource;
132
+ uint64_t frames[256];
133
+ uint8_t endpoint_addrs[USB_MAXENDPOINTS];
134
+ };
135
+
128
136
  struct darwin_device_handle_priv {
129
137
  bool is_open;
130
138
  CFRunLoopSourceRef cfSource;
131
139
 
132
- struct darwin_interface {
133
- usb_interface_t interface;
134
- uint8_t num_endpoints;
135
- CFRunLoopSourceRef cfSource;
136
- uint64_t frames[256];
137
- uint8_t endpoint_addrs[USB_MAXENDPOINTS];
138
- } interfaces[USB_MAXINTERFACES];
140
+ struct darwin_interface interfaces[USB_MAXINTERFACES];
139
141
  };
140
142
 
141
143
  struct darwin_transfer_priv {
@@ -538,17 +538,36 @@ private:
538
538
  auto configurations_len = dev->device_descriptor.bNumConfigurations;
539
539
  configurations.reserve(configurations_len);
540
540
  for (uint8_t j = 0; j < configurations_len; j++) {
541
- // Note: requesting more than (platform-specific limit) bytes
542
- // here will cause the transfer to fail, see
543
- // https://crbug.com/1489414. Use the most common limit of 4096
544
- // bytes for now.
545
- constexpr uint16_t MAX_CTRL_BUFFER_LENGTH = 4096;
546
- auto result = co_await_try(
547
- requestDescriptor(LIBUSB_DT_CONFIG, j, MAX_CTRL_BUFFER_LENGTH));
548
- if (auto error = getTransferStatus(result)) {
541
+ // Read descriptor header first to discover target length.
542
+ auto config_header_result = co_await_try(
543
+ requestDescriptor(LIBUSB_DT_CONFIG, j, LIBUSB_DT_CONFIG_SIZE));
544
+ if (auto error = getTransferStatus(config_header_result)) {
545
+ co_return error;
546
+ }
547
+ union usbi_config_desc_buf config_header = {};
548
+ copyFromDataView(config_header.buf, config_header_result["data"]);
549
+ if (config_header.desc.bDescriptorType != LIBUSB_DT_CONFIG ||
550
+ config_header.desc.bLength < LIBUSB_DT_CONFIG_SIZE) {
551
+ co_return LIBUSB_ERROR_IO;
552
+ }
553
+
554
+ auto config_total_length =
555
+ libusb_le16_to_cpu(config_header.desc.wTotalLength);
556
+ if (config_total_length < LIBUSB_DT_CONFIG_SIZE) {
557
+ co_return LIBUSB_ERROR_IO;
558
+ }
559
+
560
+ auto config_result = co_await_try(
561
+ requestDescriptor(LIBUSB_DT_CONFIG, j, config_total_length));
562
+ if (auto error = getTransferStatus(config_result)) {
549
563
  co_return error;
550
564
  }
551
- auto configVal = result["data"];
565
+
566
+ auto configVal = config_result["data"];
567
+ if (configVal["byteLength"].as<size_t>() < config_total_length) {
568
+ co_return LIBUSB_ERROR_IO;
569
+ }
570
+
552
571
  auto configLen = configVal["byteLength"].as<size_t>();
553
572
  auto& config = configurations.emplace_back(
554
573
  (usbi_configuration_descriptor*)::operator new(configLen));
@@ -623,6 +642,8 @@ val getDeviceList(libusb_context* ctx, discovered_devs** devs) {
623
642
  // This can wrap around but it's the best approximation of a stable
624
643
  // device address and port number we can provide.
625
644
  dev->device_address = dev->port_number = (uint8_t)session_id;
645
+
646
+ usbi_connect_device(dev);
626
647
  }
627
648
  *devs = discovered_devs_append(*devs, dev);
628
649
  libusb_unref_device(dev);
@@ -706,7 +727,7 @@ int em_get_config_descriptor_by_value(libusb_device* dev,
706
727
  }
707
728
 
708
729
  int em_set_configuration(libusb_device_handle* dev_handle, int config) {
709
- return WebUsbDevicePtr(dev_handle)->awaitOnMain("setConfiguration", config);
730
+ return WebUsbDevicePtr(dev_handle)->awaitOnMain("selectConfiguration", config);
710
731
  }
711
732
 
712
733
  int em_claim_interface(libusb_device_handle* handle, uint8_t iface) {
@@ -186,6 +186,7 @@ const struct usbi_os_backend usbi_backend = {
186
186
  /*.exit =*/ haiku_exit,
187
187
  /*.set_option =*/ NULL,
188
188
  /*.get_device_list =*/ NULL,
189
+ /*.get_device_string =*/ NULL,
189
190
  /*.hotplug_poll =*/ NULL,
190
191
  /*.wrap_sys_device =*/ NULL,
191
192
  /*.open =*/ haiku_open,
@@ -214,6 +215,9 @@ const struct usbi_os_backend usbi_backend = {
214
215
  /*.kernel_driver_active =*/ NULL,
215
216
  /*.detach_kernel_driver =*/ NULL,
216
217
  /*.attach_kernel_driver =*/ NULL,
218
+ /*.endpoint_supports_raw_io =*/ NULL,
219
+ /*.endpoint_set_raw_io =*/ NULL,
220
+ /*.get_max_raw_io_transfer_size =*/ NULL,
217
221
 
218
222
  /*.destroy_device =*/ NULL,
219
223