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
@@ -98,6 +98,8 @@ static int init_count = 0;
98
98
  /* Serialize scan-devices, event-thread, and poll */
99
99
  usbi_mutex_static_t linux_hotplug_lock = USBI_MUTEX_INITIALIZER;
100
100
 
101
+ static int open_sysfs_attr(struct libusb_context *ctx,
102
+ const char *sysfs_dir, const char *attr);
101
103
  static int linux_scan_devices(struct libusb_context *ctx);
102
104
  static int detach_kernel_driver_and_claim(struct libusb_device_handle *, uint8_t);
103
105
 
@@ -199,19 +201,25 @@ static int get_usbfs_fd(struct libusb_device *dev, int access_mode, int silent)
199
201
  if (fd != -1)
200
202
  return fd; /* Success */
201
203
 
204
+ /* TODO: fix race between netlink and usbfs https://github.com/libusb/libusb/issues/1691 */
202
205
  if (errno == ENOENT) {
203
206
  const long delay_ms = 10L;
204
207
  const struct timespec delay_ts = { 0L, delay_ms * 1000L * 1000L };
208
+ uint8_t retry = 3;
205
209
 
206
- if (!silent)
207
- usbi_err(ctx, "File doesn't exist, wait %ld ms and try again", delay_ms);
210
+ while (retry-- > 0) {
211
+ if (!silent)
212
+ usbi_err(ctx, "File doesn't exist, wait %ld ms and try again", delay_ms);
208
213
 
209
- /* Wait 10ms for USB device path creation.*/
210
- nanosleep(&delay_ts, NULL);
214
+ /* Wait 10ms for USB device path creation.*/
215
+ nanosleep(&delay_ts, NULL);
211
216
 
212
- fd = open(path, access_mode | O_CLOEXEC);
213
- if (fd != -1)
214
- return fd; /* Success */
217
+ fd = open(path, access_mode | O_CLOEXEC);
218
+ if (fd != -1)
219
+ return fd; /* Success */
220
+ if (errno != ENOENT)
221
+ break;
222
+ }
215
223
  }
216
224
 
217
225
  if (!silent) {
@@ -293,16 +301,7 @@ static const char *find_usbfs_path(void)
293
301
  }
294
302
  }
295
303
 
296
- /* On udev based systems without any usb-devices /dev/bus/usb will not
297
- * exist. So if we've not found anything and we're using udev for hotplug
298
- * simply assume /dev/bus/usb rather then making libusb_init fail.
299
- * Make the same assumption for Android where SELinux policies might block us
300
- * from reading /dev on newer devices. */
301
- #if defined(HAVE_LIBUDEV) || defined(__ANDROID__)
302
- return USB_DEVTMPFS_PATH;
303
- #else
304
304
  return NULL;
305
- #endif
306
305
  }
307
306
 
308
307
  static int get_kernel_version(struct libusb_context *ctx,
@@ -370,12 +369,16 @@ static int op_init(struct libusb_context *ctx)
370
369
 
371
370
  usbfs_path = find_usbfs_path();
372
371
  if (!usbfs_path) {
373
- usbi_err(ctx, "could not find usbfs");
374
- return LIBUSB_ERROR_OTHER;
372
+ /* On udev based systems without any usb devices /dev/bus/usb will not
373
+ * exist. On android and other systems SELinux policies might block us
374
+ * from reading /dev. Nonetheless it's the default for most modern linux
375
+ systems including those using udev alternatives such as busybox's mdev. */
376
+ usbfs_path = USB_DEVTMPFS_PATH;
377
+ usbi_dbg(ctx, "could not find usbfs, defaulting to %s", usbfs_path);
378
+ } else {
379
+ usbi_dbg(ctx, "found usbfs at %s", usbfs_path);
375
380
  }
376
381
 
377
- usbi_dbg(ctx, "found usbfs at %s", usbfs_path);
378
-
379
382
  if (!max_iso_packet_len) {
380
383
  if (kernel_version_ge(&kversion, 5, 2, 0))
381
384
  max_iso_packet_len = 98304;
@@ -452,6 +455,46 @@ static int op_set_option(struct libusb_context *ctx, enum libusb_option option,
452
455
  return LIBUSB_ERROR_NOT_SUPPORTED;
453
456
  }
454
457
 
458
+ static int op_get_device_string(struct libusb_device *dev,
459
+ enum libusb_device_string_type string_type, char *buffer, int length)
460
+ {
461
+ ssize_t r;
462
+ int fd;
463
+ struct linux_device_priv *priv = usbi_get_device_priv(dev);
464
+ struct libusb_context* ctx = DEVICE_CTX(dev);
465
+ const char * attr;
466
+
467
+ switch (string_type) {
468
+ case LIBUSB_DEVICE_STRING_MANUFACTURER: attr = "manufacturer"; break;
469
+ case LIBUSB_DEVICE_STRING_PRODUCT: attr = "product"; break;
470
+ case LIBUSB_DEVICE_STRING_SERIAL_NUMBER: attr = "serial"; break;
471
+ case LIBUSB_DEVICE_STRING_COUNT:
472
+ /* intentional fall-through, avoid -Wswitch-enum */
473
+ default:
474
+ return LIBUSB_ERROR_INVALID_PARAM;
475
+ }
476
+ fd = open_sysfs_attr(ctx, priv->sysfs_dir, attr);
477
+ if (fd < 0)
478
+ return LIBUSB_ERROR_IO;
479
+
480
+ r = read(fd, buffer, length - 1); // leave space for null terminator
481
+ if (r < 0) {
482
+ r = errno;
483
+ close(fd);
484
+ if (r == ENODEV)
485
+ return LIBUSB_ERROR_NO_DEVICE;
486
+ usbi_err(ctx, "attribute %s read failed, errno=%zd", attr, r);
487
+ return LIBUSB_ERROR_IO;
488
+ }
489
+ close(fd);
490
+ buffer[r] = 0; // add null terminator
491
+ while (r && ((buffer[r] == 0) || (buffer[r] == '\n'))) {
492
+ buffer[r--] = 0;
493
+ }
494
+ ++r;
495
+ return r;
496
+ }
497
+
455
498
  static int linux_scan_devices(struct libusb_context *ctx)
456
499
  {
457
500
  int ret;
@@ -1254,6 +1297,10 @@ static int usbfs_get_device_list(struct libusb_context *ctx)
1254
1297
  buses = opendir(USB_DEVTMPFS_PATH);
1255
1298
 
1256
1299
  if (!buses) {
1300
+ if (!usbdev_names && errno == ENOENT) {
1301
+ /* The path does not exist if there are no devices plugged in */
1302
+ return LIBUSB_SUCCESS;
1303
+ }
1257
1304
  usbi_err(ctx, "opendir buses failed, errno=%d", errno);
1258
1305
  return LIBUSB_ERROR_IO;
1259
1306
  }
@@ -1331,10 +1378,10 @@ static int linux_default_scan_devices(struct libusb_context *ctx)
1331
1378
  * any autosuspended USB devices. however, sysfs is not available
1332
1379
  * everywhere, so we need a usbfs fallback too.
1333
1380
  */
1334
- if (sysfs_available)
1335
- return sysfs_get_device_list(ctx);
1336
- else
1337
- return usbfs_get_device_list(ctx);
1381
+ if (sysfs_available && sysfs_get_device_list(ctx) == LIBUSB_SUCCESS)
1382
+ return LIBUSB_SUCCESS;
1383
+
1384
+ return usbfs_get_device_list(ctx);
1338
1385
  }
1339
1386
  #endif
1340
1387
 
@@ -2760,7 +2807,7 @@ static int op_handle_events(struct libusb_context *ctx,
2760
2807
  } while (r == 0);
2761
2808
  }
2762
2809
 
2763
- usbi_handle_disconnect(handle);
2810
+ usbi_handle_disconnect(ctx, handle);
2764
2811
  continue;
2765
2812
  }
2766
2813
 
@@ -2787,6 +2834,7 @@ const struct usbi_os_backend usbi_backend = {
2787
2834
  .init = op_init,
2788
2835
  .exit = op_exit,
2789
2836
  .set_option = op_set_option,
2837
+ .get_device_string = op_get_device_string,
2790
2838
  .hotplug_poll = op_hotplug_poll,
2791
2839
  .get_active_config_descriptor = op_get_active_config_descriptor,
2792
2840
  .get_config_descriptor = op_get_config_descriptor,
@@ -171,6 +171,8 @@ netbsd_get_device_list(struct libusb_context * ctx,
171
171
 
172
172
  if ((err = usbi_sanitize_device(dev)))
173
173
  goto error;
174
+
175
+ usbi_connect_device(dev);
174
176
  }
175
177
  close(fd);
176
178
 
@@ -200,6 +200,8 @@ obsd_get_device_list(struct libusb_context * ctx,
200
200
  libusb_unref_device(dev);
201
201
  continue;
202
202
  }
203
+
204
+ usbi_connect_device(dev);
203
205
  }
204
206
 
205
207
  ddd = discovered_devs_append(*discdevs, dev);
@@ -627,6 +627,8 @@ sunos_add_devices(di_devlink_t link, void *arg)
627
627
  usbi_dbg(NULL, "sanitize failed: ");
628
628
  return (DI_WALK_TERMINATE);
629
629
  }
630
+
631
+ usbi_connect_device(dev);
630
632
  } else {
631
633
  devpriv = usbi_get_device_priv(dev);
632
634
  usbi_dbg(NULL, "Dev %s exists", devpriv->ugenpath);
@@ -38,7 +38,7 @@
38
38
  # include <sys/lwp.h>
39
39
  #endif
40
40
 
41
- void usbi_cond_init(pthread_cond_t *cond)
41
+ void usbi_cond_init(usbi_cond_t *cond)
42
42
  {
43
43
  #ifdef HAVE_PTHREAD_CONDATTR_SETCLOCK
44
44
  pthread_condattr_t condattr;
@@ -52,8 +52,8 @@ void usbi_cond_init(pthread_cond_t *cond)
52
52
  #endif
53
53
  }
54
54
 
55
- int usbi_cond_timedwait(pthread_cond_t *cond,
56
- pthread_mutex_t *mutex, const struct timeval *tv)
55
+ int usbi_cond_timedwait(usbi_cond_t *cond,
56
+ usbi_mutex_t *mutex, const struct timeval *tv)
57
57
  {
58
58
  struct timespec timeout;
59
59
  int r;
@@ -51,21 +51,27 @@ static inline void usbi_mutex_unlock(usbi_mutex_t *mutex)
51
51
  }
52
52
  static inline int usbi_mutex_trylock(usbi_mutex_t *mutex)
53
53
  {
54
- return pthread_mutex_trylock(mutex) == 0;
54
+ int mutexIsLocked = pthread_mutex_trylock(mutex) == 0;
55
+ return mutexIsLocked;
55
56
  }
56
57
  static inline void usbi_mutex_destroy(usbi_mutex_t *mutex)
57
58
  {
58
59
  PTHREAD_CHECK(pthread_mutex_destroy(mutex));
59
60
  }
60
61
 
62
+ #define USBI_COND_INITIALIZER PTHREAD_COND_INITIALIZER
61
63
  typedef pthread_cond_t usbi_cond_t;
62
- void usbi_cond_init(pthread_cond_t *cond);
64
+ void usbi_cond_init(usbi_cond_t *cond);
63
65
  static inline void usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex)
64
66
  {
65
67
  PTHREAD_CHECK(pthread_cond_wait(cond, mutex));
66
68
  }
67
69
  int usbi_cond_timedwait(usbi_cond_t *cond,
68
70
  usbi_mutex_t *mutex, const struct timeval *tv);
71
+ static inline void usbi_cond_signal(usbi_cond_t *cond)
72
+ {
73
+ PTHREAD_CHECK(pthread_cond_signal(cond));
74
+ }
69
75
  static inline void usbi_cond_broadcast(usbi_cond_t *cond)
70
76
  {
71
77
  PTHREAD_CHECK(pthread_cond_broadcast(cond));
@@ -50,7 +50,8 @@ static inline void usbi_mutex_unlock(usbi_mutex_t *mutex)
50
50
  }
51
51
  static inline int usbi_mutex_trylock(usbi_mutex_t *mutex)
52
52
  {
53
- return TryEnterCriticalSection(mutex) != 0;
53
+ int mutexIsLocked = TryEnterCriticalSection(mutex) != 0;
54
+ return mutexIsLocked;
54
55
  }
55
56
  static inline void usbi_mutex_destroy(usbi_mutex_t *mutex)
56
57
  {
@@ -29,6 +29,10 @@
29
29
  #include "libusbi.h"
30
30
  #include "windows_common.h"
31
31
 
32
+ #if defined(LIBUSB_WINDOWS_HOTPLUG)
33
+ #include "windows_hotplug.h"
34
+ #endif
35
+
32
36
  #define EPOCH_TIME UINT64_C(116444736000000000) // 1970.01.01 00:00:000 in MS Filetime
33
37
 
34
38
  #define STATUS_SUCCESS ((ULONG_PTR)0UL)
@@ -492,9 +496,11 @@ static unsigned __stdcall windows_iocp_thread(void *arg)
492
496
  }
493
497
 
494
498
  itransfer = TRANSFER_PRIV_TO_USBI_TRANSFER(transfer_priv);
499
+ #ifdef ENABLE_LOGGING
495
500
  struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
496
501
  usbi_dbg(ctx, "transfer %p completed, length %lu",
497
502
  transfer, ULONG_CAST(num_bytes));
503
+ #endif
498
504
  usbi_signal_transfer_completion(itransfer);
499
505
  }
500
506
 
@@ -565,6 +571,18 @@ static int windows_init(struct libusb_context *ctx)
565
571
 
566
572
  r = LIBUSB_SUCCESS;
567
573
 
574
+ #if defined(LIBUSB_WINDOWS_HOTPLUG)
575
+ if (init_count == 1) {
576
+ r = windows_start_event_monitor(); // Start-up hotplug event handler
577
+ if (r != LIBUSB_SUCCESS) {
578
+ usbi_err(ctx, "error starting hotplug event monitor");
579
+ goto init_exit;
580
+ }
581
+ }
582
+
583
+ windows_initial_scan_devices(ctx);
584
+ #endif
585
+
568
586
  init_exit: // Holds semaphore here
569
587
  if ((init_count == 1) && (r != LIBUSB_SUCCESS)) { // First init failed?
570
588
  if (usbdk_available) {
@@ -596,6 +614,9 @@ static void windows_exit(struct libusb_context *ctx)
596
614
 
597
615
  // Only works if exits and inits are balanced exactly
598
616
  if (--init_count == 0) { // Last exit
617
+ #if defined(LIBUSB_WINDOWS_HOTPLUG)
618
+ windows_stop_event_monitor();
619
+ #endif
599
620
  if (usbdk_available) {
600
621
  usbdk_backend.exit(ctx);
601
622
  usbdk_available = false;
@@ -624,11 +645,23 @@ static int windows_set_option(struct libusb_context *ctx, enum libusb_option opt
624
645
  return LIBUSB_ERROR_NOT_SUPPORTED;
625
646
  }
626
647
 
648
+ #if !defined(LIBUSB_WINDOWS_HOTPLUG)
627
649
  static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **discdevs)
628
650
  {
629
651
  struct windows_context_priv *priv = usbi_get_context_priv(ctx);
630
652
  return priv->backend->get_device_list(ctx, discdevs);
631
653
  }
654
+ #endif
655
+
656
+ static int windows_get_device_string(libusb_device *dev,
657
+ enum libusb_device_string_type string_type, char *data, int length)
658
+ {
659
+ struct windows_context_priv* priv = usbi_get_context_priv(DEVICE_CTX(dev));
660
+ if (NULL != priv->backend->get_device_string) {
661
+ return priv->backend->get_device_string(dev, string_type, data, length);
662
+ }
663
+ return LIBUSB_ERROR_NOT_SUPPORTED;
664
+ }
632
665
 
633
666
  static int windows_open(struct libusb_device_handle *dev_handle)
634
667
  {
@@ -717,6 +750,37 @@ static void windows_destroy_device(struct libusb_device *dev)
717
750
  priv->backend->destroy_device(dev);
718
751
  }
719
752
 
753
+ static int windows_endpoint_supports_raw_io(libusb_device_handle* dev_handle,
754
+ uint8_t endpoint)
755
+ {
756
+ struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
757
+ if (priv->backend->endpoint_supports_raw_io)
758
+ return priv->backend->endpoint_supports_raw_io(dev_handle, endpoint);
759
+ return LIBUSB_ERROR_NOT_SUPPORTED;
760
+ }
761
+
762
+ static int windows_endpoint_set_raw_io(libusb_device_handle* dev_handle,
763
+ uint8_t endpoint, int enable)
764
+ {
765
+ struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
766
+
767
+ if (priv->backend->endpoint_supports_raw_io == NULL
768
+ || priv->backend->endpoint_supports_raw_io(dev_handle, endpoint) != 1
769
+ || priv->backend->endpoint_set_raw_io == NULL)
770
+ return LIBUSB_ERROR_NOT_SUPPORTED;
771
+
772
+ return priv->backend->endpoint_set_raw_io(dev_handle, endpoint, enable);
773
+ }
774
+
775
+ static int windows_get_max_raw_io_transfer_size(struct libusb_device_handle *dev_handle,
776
+ uint8_t endpoint)
777
+ {
778
+ struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
779
+ if (priv->backend->get_max_raw_io_transfer_size)
780
+ return priv->backend->get_max_raw_io_transfer_size(dev_handle, endpoint);
781
+ return LIBUSB_ERROR_NOT_SUPPORTED;
782
+ }
783
+
720
784
  static int windows_submit_transfer(struct usbi_transfer *itransfer)
721
785
  {
722
786
  struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
@@ -800,15 +864,26 @@ static int windows_handle_transfer_completion(struct usbi_transfer *itransfer)
800
864
  struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
801
865
  enum libusb_transfer_status status, istatus;
802
866
  DWORD result, bytes_transferred;
867
+ HANDLE transfer_handle;
868
+
869
+ /*
870
+ * The submit path runs with itransfer->lock held. Grab the handle under
871
+ * the same lock so we do not race with submission/completion bookkeeping.
872
+ */
873
+ usbi_mutex_lock(&itransfer->lock);
874
+ transfer_handle = transfer_priv->handle;
875
+ usbi_mutex_unlock(&itransfer->lock);
803
876
 
804
- if (GetOverlappedResult(transfer_priv->handle, &transfer_priv->overlapped, &bytes_transferred, FALSE))
877
+ if (GetOverlappedResult(transfer_handle, &transfer_priv->overlapped, &bytes_transferred, FALSE))
805
878
  result = NO_ERROR;
806
879
  else
807
880
  result = GetLastError();
808
881
 
882
+ #ifdef ENABLE_LOGGING
809
883
  struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
810
884
  usbi_dbg(ctx, "handling transfer %p completion with errcode %lu, length %lu",
811
885
  transfer, ULONG_CAST(result), ULONG_CAST(bytes_transferred));
886
+ #endif
812
887
 
813
888
  switch (result) {
814
889
  case NO_ERROR:
@@ -843,7 +918,9 @@ static int windows_handle_transfer_completion(struct usbi_transfer *itransfer)
843
918
  break;
844
919
  }
845
920
 
921
+ usbi_mutex_lock(&itransfer->lock);
846
922
  transfer_priv->handle = NULL;
923
+ usbi_mutex_unlock(&itransfer->lock);
847
924
 
848
925
  // Backend-specific cleanup
849
926
  backend->clear_transfer_priv(itransfer);
@@ -888,7 +965,12 @@ const struct usbi_os_backend usbi_backend = {
888
965
  windows_init,
889
966
  windows_exit,
890
967
  windows_set_option,
968
+ #if defined(LIBUSB_WINDOWS_HOTPLUG)
969
+ NULL, /* get_device_list */
970
+ #else
891
971
  windows_get_device_list,
972
+ #endif
973
+ windows_get_device_string,
892
974
  NULL, /* hotplug_poll */
893
975
  NULL, /* wrap_sys_device */
894
976
  windows_open,
@@ -910,6 +992,9 @@ const struct usbi_os_backend usbi_backend = {
910
992
  NULL, /* kernel_driver_active */
911
993
  NULL, /* detach_kernel_driver */
912
994
  NULL, /* attach_kernel_driver */
995
+ windows_endpoint_supports_raw_io,
996
+ windows_endpoint_set_raw_io,
997
+ windows_get_max_raw_io_transfer_size,
913
998
  windows_destroy_device,
914
999
  windows_submit_transfer,
915
1000
  windows_cancel_transfer,
@@ -242,13 +242,23 @@ struct usbdk_device_priv {
242
242
 
243
243
  struct winusb_device_priv {
244
244
  bool initialized;
245
+ #if defined(LIBUSB_WINDOWS_HOTPLUG)
246
+ bool seen_during_scan; // set true for each device encountered during windows_get_device_list
247
+ bool seen_before_scan; // set true for each device encountered before windows_get_device_list
248
+ #endif
245
249
  bool root_hub;
246
250
  uint8_t active_config;
251
+ uint16_t langid; // cached USB language ID for string descriptor requests
247
252
  uint8_t depth; // distance to HCD
248
253
  const struct windows_usb_api_backend *apib;
249
254
  char *dev_id;
250
255
  char *path; // device interface path
251
256
  int sub_api; // for WinUSB-like APIs
257
+ usbi_mutex_t interface_lock; // protects usb_interface[] against concurrent
258
+ // claim/release/altsetting from different handles,
259
+ // and concurrent enumeration setup
260
+ // (set_composite_interface, set_hid_interface,
261
+ // and HUB_PASS/DEV_PASS in winusb_get_device_list)
252
262
  struct {
253
263
  char *path; // each interface needs a device interface path,
254
264
  const struct windows_usb_api_backend *apib; // an API backend (multiple drivers support),
@@ -275,7 +285,7 @@ struct usbdk_device_handle_priv {
275
285
  // Not currently used
276
286
  char dummy;
277
287
  };
278
-
288
+
279
289
  enum WINUSB_ZLP {
280
290
  WINUSB_ZLP_UNSET = 0,
281
291
  WINUSB_ZLP_OFF = 1,
@@ -320,6 +330,8 @@ struct windows_backend {
320
330
  void (*exit)(struct libusb_context *ctx);
321
331
  int (*get_device_list)(struct libusb_context *ctx,
322
332
  struct discovered_devs **discdevs);
333
+ int (*get_device_string)(libusb_device *dev,
334
+ enum libusb_device_string_type string_type, char *data, int length);
323
335
  int (*open)(struct libusb_device_handle *dev_handle);
324
336
  void (*close)(struct libusb_device_handle *dev_handle);
325
337
  int (*get_active_config_descriptor)(struct libusb_device *device,
@@ -342,6 +354,13 @@ struct windows_backend {
342
354
  int (*cancel_transfer)(struct usbi_transfer *itransfer);
343
355
  void (*clear_transfer_priv)(struct usbi_transfer *itransfer);
344
356
  enum libusb_transfer_status (*copy_transfer_data)(struct usbi_transfer *itransfer, DWORD length);
357
+ int (*endpoint_supports_raw_io)(struct libusb_device_handle *dev_handle,
358
+ uint8_t endpoint);
359
+ int (*endpoint_set_raw_io)(struct libusb_device_handle *dev_handle,
360
+ uint8_t endpoint, int enable);
361
+ int (*get_max_raw_io_transfer_size)(
362
+ struct libusb_device_handle *dev_handle,
363
+ uint8_t endpoint);
345
364
  };
346
365
 
347
366
  struct windows_context_priv {