libusb 0.5.0 → 0.5.1

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 (141) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.travis.yml +1 -0
  5. data/History.md +8 -0
  6. data/README.md +5 -15
  7. data/Rakefile +8 -1
  8. data/ext/extconf.rb +49 -12
  9. data/ext/{libusb-1.0.19 → libusb-1.0.20}/AUTHORS +12 -1
  10. data/ext/{libusb-1.0.19 → libusb-1.0.20}/COPYING +0 -0
  11. data/ext/{libusb-1.0.19 → libusb-1.0.20}/ChangeLog +18 -2
  12. data/ext/{libusb-1.0.19 → libusb-1.0.20}/INSTALL +0 -0
  13. data/ext/{libusb-1.0.19 → libusb-1.0.20}/Makefile.am +0 -0
  14. data/ext/{libusb-1.0.19 → libusb-1.0.20}/Makefile.in +31 -18
  15. data/ext/{libusb-1.0.19 → libusb-1.0.20}/NEWS +0 -0
  16. data/ext/{libusb-1.0.19 → libusb-1.0.20}/PORTING +0 -0
  17. data/ext/{libusb-1.0.19 → libusb-1.0.20}/README +5 -3
  18. data/ext/{libusb-1.0.19 → libusb-1.0.20}/TODO +0 -0
  19. data/ext/{libusb-1.0.19 → libusb-1.0.20}/Xcode/common.xcconfig +0 -0
  20. data/ext/{libusb-1.0.19 → libusb-1.0.20}/Xcode/config.h +0 -0
  21. data/ext/{libusb-1.0.19 → libusb-1.0.20}/Xcode/debug.xcconfig +0 -0
  22. data/ext/{libusb-1.0.19 → libusb-1.0.20}/Xcode/libusb.xcconfig +0 -0
  23. data/ext/libusb-1.0.20/Xcode/libusb.xcodeproj/project.pbxproj +865 -0
  24. data/ext/{libusb-1.0.19 → libusb-1.0.20}/Xcode/libusb_debug.xcconfig +0 -0
  25. data/ext/{libusb-1.0.19 → libusb-1.0.20}/Xcode/libusb_release.xcconfig +0 -0
  26. data/ext/{libusb-1.0.19 → libusb-1.0.20}/Xcode/release.xcconfig +0 -0
  27. data/ext/{libusb-1.0.19 → libusb-1.0.20}/aclocal.m4 +35 -32
  28. data/ext/{libusb-1.0.19 → libusb-1.0.20}/android/README +0 -0
  29. data/ext/{libusb-1.0.19 → libusb-1.0.20}/android/config.h +0 -0
  30. data/ext/{libusb-1.0.19 → libusb-1.0.20}/android/jni/Android.mk +0 -0
  31. data/ext/{libusb-1.0.19 → libusb-1.0.20}/android/jni/Application.mk +0 -0
  32. data/ext/{libusb-1.0.19 → libusb-1.0.20}/android/jni/examples.mk +0 -0
  33. data/ext/{libusb-1.0.19 → libusb-1.0.20}/android/jni/libusb.mk +0 -0
  34. data/ext/{libusb-1.0.19 → libusb-1.0.20}/android/jni/tests.mk +0 -0
  35. data/ext/{libusb-1.0.19 → libusb-1.0.20}/compile +1 -1
  36. data/ext/{libusb-1.0.19 → libusb-1.0.20}/config.guess +13 -160
  37. data/ext/{libusb-1.0.19 → libusb-1.0.20}/config.h.in +6 -0
  38. data/ext/{libusb-1.0.19 → libusb-1.0.20}/config.sub +26 -12
  39. data/ext/{libusb-1.0.19 → libusb-1.0.20}/configure +244 -20
  40. data/ext/{libusb-1.0.19 → libusb-1.0.20}/configure.ac +27 -4
  41. data/ext/{libusb-1.0.19 → libusb-1.0.20}/depcomp +1 -1
  42. data/ext/{libusb-1.0.19 → libusb-1.0.20}/doc/Makefile.am +0 -0
  43. data/ext/{libusb-1.0.19 → libusb-1.0.20}/doc/Makefile.in +19 -6
  44. data/ext/libusb-1.0.20/doc/doxygen.cfg.in +2334 -0
  45. data/ext/{libusb-1.0.19 → libusb-1.0.20}/examples/Makefile.am +0 -0
  46. data/ext/{libusb-1.0.19 → libusb-1.0.20}/examples/Makefile.in +19 -6
  47. data/ext/{libusb-1.0.19 → libusb-1.0.20}/examples/dpfp.c +0 -0
  48. data/ext/{libusb-1.0.19 → libusb-1.0.20}/examples/dpfp_threaded.c +15 -10
  49. data/ext/{libusb-1.0.19 → libusb-1.0.20}/examples/ezusb.c +0 -0
  50. data/ext/{libusb-1.0.19 → libusb-1.0.20}/examples/ezusb.h +0 -0
  51. data/ext/{libusb-1.0.19 → libusb-1.0.20}/examples/fxload.c +28 -7
  52. data/ext/{libusb-1.0.19 → libusb-1.0.20}/examples/getopt/getopt.c +0 -0
  53. data/ext/{libusb-1.0.19 → libusb-1.0.20}/examples/getopt/getopt.h +0 -0
  54. data/ext/{libusb-1.0.19 → libusb-1.0.20}/examples/getopt/getopt1.c +0 -0
  55. data/ext/{libusb-1.0.19 → libusb-1.0.20}/examples/hotplugtest.c +21 -3
  56. data/ext/{libusb-1.0.19 → libusb-1.0.20}/examples/listdevs.c +0 -0
  57. data/ext/{libusb-1.0.19 → libusb-1.0.20}/examples/sam3u_benchmark.c +0 -0
  58. data/ext/{libusb-1.0.19 → libusb-1.0.20}/examples/xusb.c +2 -1
  59. data/ext/{libusb-1.0.19 → libusb-1.0.20}/install-sh +170 -196
  60. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb-1.0.pc.in +0 -0
  61. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/Makefile.am +15 -0
  62. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/Makefile.in +192 -53
  63. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/core.c +218 -100
  64. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/descriptor.c +3 -1
  65. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/hotplug.c +26 -9
  66. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/hotplug.h +8 -0
  67. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/io.c +432 -290
  68. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/libusb-1.0.def +2 -0
  69. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/libusb-1.0.rc +0 -0
  70. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/libusb.h +11 -10
  71. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/libusbi.h +106 -29
  72. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/darwin_usb.c +27 -67
  73. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/darwin_usb.h +3 -7
  74. data/ext/libusb-1.0.20/libusb/os/haiku/Makefile.am +5 -0
  75. data/ext/libusb-1.0.20/libusb/os/haiku/Makefile.in +810 -0
  76. data/ext/libusb-1.0.20/libusb/os/haiku/aclocal.m4 +1193 -0
  77. data/ext/libusb-1.0.20/libusb/os/haiku/compile +347 -0
  78. data/ext/libusb-1.0.20/libusb/os/haiku/config.guess +1421 -0
  79. data/ext/libusb-1.0.20/libusb/os/haiku/config.sub +1807 -0
  80. data/ext/libusb-1.0.20/libusb/os/haiku/configure +17579 -0
  81. data/ext/libusb-1.0.20/libusb/os/haiku/configure.ac +8 -0
  82. data/ext/libusb-1.0.20/libusb/os/haiku/depcomp +791 -0
  83. data/ext/libusb-1.0.20/libusb/os/haiku/haiku_pollfs.cpp +378 -0
  84. data/ext/libusb-1.0.20/libusb/os/haiku/haiku_usb.h +112 -0
  85. data/ext/libusb-1.0.20/libusb/os/haiku/haiku_usb_backend.cpp +550 -0
  86. data/ext/libusb-1.0.20/libusb/os/haiku/haiku_usb_raw.cpp +255 -0
  87. data/ext/libusb-1.0.20/libusb/os/haiku/haiku_usb_raw.h +180 -0
  88. data/ext/libusb-1.0.20/libusb/os/haiku/install-sh +501 -0
  89. data/ext/{libusb-1.0.19 → libusb-1.0.20/libusb/os/haiku}/ltmain.sh +0 -0
  90. data/ext/{libusb-1.0.19 → libusb-1.0.20/libusb/os/haiku}/m4/libtool.m4 +0 -0
  91. data/ext/{libusb-1.0.19 → libusb-1.0.20/libusb/os/haiku}/m4/ltoptions.m4 +0 -0
  92. data/ext/{libusb-1.0.19 → libusb-1.0.20/libusb/os/haiku}/m4/ltsugar.m4 +0 -0
  93. data/ext/{libusb-1.0.19 → libusb-1.0.20/libusb/os/haiku}/m4/ltversion.m4 +0 -0
  94. data/ext/{libusb-1.0.19 → libusb-1.0.20/libusb/os/haiku}/m4/lt~obsolete.m4 +0 -0
  95. data/ext/{libusb-1.0.19 → libusb-1.0.20/libusb/os/haiku}/missing +1 -1
  96. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/linux_netlink.c +4 -4
  97. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/linux_udev.c +1 -2
  98. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/linux_usbfs.c +46 -49
  99. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/linux_usbfs.h +1 -1
  100. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/netbsd_usb.c +9 -73
  101. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/openbsd_usb.c +9 -73
  102. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/poll_posix.c +2 -0
  103. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/poll_posix.h +0 -0
  104. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/poll_windows.c +3 -1
  105. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/poll_windows.h +0 -0
  106. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/threads_posix.c +3 -3
  107. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/threads_posix.h +0 -0
  108. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/threads_windows.c +3 -1
  109. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/threads_windows.h +0 -0
  110. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/wince_usb.c +87 -250
  111. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/wince_usb.h +0 -0
  112. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/windows_common.h +1 -1
  113. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/windows_usb.c +267 -181
  114. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/os/windows_usb.h +22 -7
  115. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/strerror.c +5 -2
  116. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/sync.c +2 -1
  117. data/ext/{libusb-1.0.19 → libusb-1.0.20}/libusb/version.h +1 -1
  118. data/ext/libusb-1.0.20/libusb/version_nano.h +1 -0
  119. data/ext/libusb-1.0.20/ltmain.sh +9655 -0
  120. data/ext/libusb-1.0.20/m4/libtool.m4 +7992 -0
  121. data/ext/libusb-1.0.20/m4/ltoptions.m4 +384 -0
  122. data/ext/libusb-1.0.20/m4/ltsugar.m4 +123 -0
  123. data/ext/libusb-1.0.20/m4/ltversion.m4 +23 -0
  124. data/ext/libusb-1.0.20/m4/lt~obsolete.m4 +98 -0
  125. data/ext/libusb-1.0.20/missing +215 -0
  126. data/ext/{libusb-1.0.19 → libusb-1.0.20}/tests/Makefile.am +0 -0
  127. data/ext/{libusb-1.0.19 → libusb-1.0.20}/tests/Makefile.in +19 -6
  128. data/ext/{libusb-1.0.19 → libusb-1.0.20}/tests/libusb_testlib.h +0 -0
  129. data/ext/{libusb-1.0.19 → libusb-1.0.20}/tests/stress.c +0 -0
  130. data/ext/{libusb-1.0.19 → libusb-1.0.20}/tests/testlib.c +0 -0
  131. data/lib/libusb.rb +1 -0
  132. data/lib/libusb/call.rb +1 -0
  133. data/lib/libusb/context.rb +5 -2
  134. data/lib/libusb/stdio.rb +25 -0
  135. data/lib/libusb/version_gem.rb +1 -1
  136. data/libusb.gemspec +2 -1
  137. metadata +152 -115
  138. metadata.gz.sig +0 -0
  139. data/ext/libusb-1.0.19/Xcode/libusb.xcodeproj/project.pbxproj +0 -1
  140. data/ext/libusb-1.0.19/doc/doxygen.cfg.in +0 -1288
  141. data/ext/libusb-1.0.19/libusb/version_nano.h +0 -1
@@ -39,7 +39,7 @@
39
39
 
40
40
  #define safe_free(p) do {if (p != NULL) {free((void*)p); p = NULL;}} while(0)
41
41
  #define safe_closehandle(h) do {if (h != INVALID_HANDLE_VALUE) {CloseHandle(h); h = INVALID_HANDLE_VALUE;}} while(0)
42
- #define safe_min(a, b) min((size_t)(a), (size_t)(b))
42
+ #define safe_min(a, b) MIN((size_t)(a), (size_t)(b))
43
43
  #define safe_strcp(dst, dst_max, src, count) do {memcpy(dst, src, safe_min(count, dst_max)); \
44
44
  ((char*)dst)[safe_min(count, dst_max)-1] = 0;} while(0)
45
45
  #define safe_strcpy(dst, dst_max, src) safe_strcp(dst, dst_max, src, safe_strlen(src)+1)
@@ -23,6 +23,7 @@
23
23
  */
24
24
 
25
25
  #include <config.h>
26
+
26
27
  #include <windows.h>
27
28
  #include <setupapi.h>
28
29
  #include <ctype.h>
@@ -106,13 +107,8 @@ static char windows_version_str[128] = "Windows Undefined";
106
107
  static int concurrent_usage = -1;
107
108
  usbi_mutex_t autoclaim_lock;
108
109
  // Timer thread
109
- // NB: index 0 is for monotonic and 1 is for the thread exit event
110
110
  HANDLE timer_thread = NULL;
111
- HANDLE timer_mutex = NULL;
112
- struct timespec timer_tp;
113
- volatile LONG request_count[2] = {0, 1}; // last one must be > 0
114
- HANDLE timer_request[2] = { NULL, NULL };
115
- HANDLE timer_response = NULL;
111
+ DWORD timer_thread_id = 0;
116
112
  // API globals
117
113
  #define CHECK_WINUSBX_AVAILABLE(sub_api) do { if (sub_api == SUB_API_NOTSET) sub_api = priv->sub_api; \
118
114
  if (!WinUSBX[sub_api].initialized) return LIBUSB_ERROR_ACCESS; } while(0)
@@ -257,6 +253,9 @@ static int init_dlls(void)
257
253
  DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiOpenDeviceInterfaceRegKey, TRUE);
258
254
  DLL_LOAD_PREFIXED(AdvAPI32.dll, p, RegQueryValueExW, TRUE);
259
255
  DLL_LOAD_PREFIXED(AdvAPI32.dll, p, RegCloseKey, TRUE);
256
+ DLL_LOAD_PREFIXED(User32.dll, p, GetMessageA, TRUE);
257
+ DLL_LOAD_PREFIXED(User32.dll, p, PeekMessageA, TRUE);
258
+ DLL_LOAD_PREFIXED(User32.dll, p, PostThreadMessageA, TRUE);
260
259
  return LIBUSB_SUCCESS;
261
260
  }
262
261
 
@@ -661,6 +660,32 @@ static unsigned long get_ancestor_session_id(DWORD devinst, unsigned level)
661
660
  return session_id;
662
661
  }
663
662
 
663
+ /*
664
+ * Determine which interface the given endpoint address belongs to
665
+ */
666
+ static int get_interface_by_endpoint(struct libusb_config_descriptor *conf_desc, uint8_t ep)
667
+ {
668
+ const struct libusb_interface *intf;
669
+ const struct libusb_interface_descriptor *intf_desc;
670
+ int i, j, k;
671
+
672
+ for (i = 0; i < conf_desc->bNumInterfaces; i++) {
673
+ intf = &conf_desc->interface[i];
674
+ for (j = 0; j < intf->num_altsetting; j++) {
675
+ intf_desc = &intf->altsetting[j];
676
+ for (k = 0; k < intf_desc->bNumEndpoints; k++) {
677
+ if (intf_desc->endpoint[k].bEndpointAddress == ep) {
678
+ usbi_dbg("found endpoint %02X on interface %d", intf_desc->bInterfaceNumber);
679
+ return intf_desc->bInterfaceNumber;
680
+ }
681
+ }
682
+ }
683
+ }
684
+
685
+ usbi_dbg("endpoint %02X not found on any interface", ep);
686
+ return LIBUSB_ERROR_NOT_FOUND;
687
+ }
688
+
664
689
  /*
665
690
  * Populate the endpoints addresses of the device_priv interface helper structs
666
691
  */
@@ -672,7 +697,7 @@ static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, int
672
697
  const struct libusb_interface_descriptor *if_desc;
673
698
  struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
674
699
 
675
- r = libusb_get_config_descriptor(dev_handle->dev, 0, &conf_desc);
700
+ r = libusb_get_config_descriptor(dev_handle->dev, (uint8_t)(priv->active_config-1), &conf_desc);
676
701
  if (r != LIBUSB_SUCCESS) {
677
702
  usbi_warn(ctx, "could not read config descriptor: error %d", r);
678
703
  return r;
@@ -889,13 +914,13 @@ static void get_windows_version(void)
889
914
  break;
890
915
  case 0x63: w = (ws?"8.1":"2012_R2");
891
916
  break;
892
- case 0x64: w = (ws?"8.2":"2012_R3");
917
+ case 0x64: w = (ws?"10":"2015");
893
918
  break;
894
919
  default:
895
920
  if (windows_version < 0x50)
896
921
  windows_version = WINDOWS_UNSUPPORTED;
897
922
  else
898
- w = "9 or later";
923
+ w = "11 or later";
899
924
  break;
900
925
  }
901
926
  }
@@ -927,7 +952,10 @@ static void get_windows_version(void)
927
952
  static int windows_init(struct libusb_context *ctx)
928
953
  {
929
954
  int i, r = LIBUSB_ERROR_OTHER;
955
+ DWORD_PTR affinity, dummy;
956
+ HANDLE event = NULL;
930
957
  HANDLE semaphore;
958
+ LARGE_INTEGER li_frequency;
931
959
  char sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID)
932
960
 
933
961
  sprintf(sem_name, "libusb_init%08X", (unsigned int)GetCurrentProcessId()&0xFFFFFFFF);
@@ -965,7 +993,7 @@ static int windows_init(struct libusb_context *ctx)
965
993
  // Load DLL imports
966
994
  if (init_dlls() != LIBUSB_SUCCESS) {
967
995
  usbi_err(ctx, "could not resolve DLL functions");
968
- return LIBUSB_ERROR_NOT_FOUND;
996
+ goto init_exit;
969
997
  }
970
998
 
971
999
  // Initialize the low level APIs (we don't care about errors at this stage)
@@ -973,38 +1001,53 @@ static int windows_init(struct libusb_context *ctx)
973
1001
  usb_api_backend[i].init(SUB_API_NOTSET, ctx);
974
1002
  }
975
1003
 
976
- // Because QueryPerformanceCounter might report different values when
977
- // running on different cores, we create a separate thread for the timer
978
- // calls, which we glue to the first core always to prevent timing discrepancies.
979
- r = LIBUSB_ERROR_NO_MEM;
980
- for (i = 0; i < 2; i++) {
981
- timer_request[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
982
- if (timer_request[i] == NULL) {
983
- usbi_err(ctx, "could not create timer request event %d - aborting", i);
1004
+ if (QueryPerformanceFrequency(&li_frequency)) {
1005
+ // The hires frequency can go as high as 4 GHz, so we'll use a conversion
1006
+ // to picoseconds to compute the tv_nsecs part in clock_gettime
1007
+ hires_frequency = li_frequency.QuadPart;
1008
+ hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency;
1009
+ usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency);
1010
+
1011
+ // Because QueryPerformanceCounter might report different values when
1012
+ // running on different cores, we create a separate thread for the timer
1013
+ // calls, which we glue to the first available core always to prevent timing discrepancies.
1014
+ if (!GetProcessAffinityMask(GetCurrentProcess(), &affinity, &dummy) || (affinity == 0)) {
1015
+ usbi_err(ctx, "could not get process affinity: %s", windows_error_str(0));
984
1016
  goto init_exit;
985
1017
  }
986
- }
987
- timer_response = CreateSemaphore(NULL, 0, MAX_TIMER_SEMAPHORES, NULL);
988
- if (timer_response == NULL) {
989
- usbi_err(ctx, "could not create timer response semaphore - aborting");
990
- goto init_exit;
991
- }
992
- timer_mutex = CreateMutex(NULL, FALSE, NULL);
993
- if (timer_mutex == NULL) {
994
- usbi_err(ctx, "could not create timer mutex - aborting");
995
- goto init_exit;
996
- }
997
- timer_thread = (HANDLE)_beginthreadex(NULL, 0, windows_clock_gettime_threaded, NULL, 0, NULL);
998
- if (timer_thread == NULL) {
999
- usbi_err(ctx, "Unable to create timer thread - aborting");
1000
- goto init_exit;
1001
- }
1002
- SetThreadAffinityMask(timer_thread, 0);
1018
+ // The process affinity mask is a bitmask where each set bit represents a core on
1019
+ // which this process is allowed to run, so we find the first set bit
1020
+ for (i = 0; !(affinity & (DWORD_PTR)(1 << i)); i++);
1021
+ affinity = (DWORD_PTR)(1 << i);
1003
1022
 
1004
- // Wait for timer thread to init before continuing.
1005
- if (WaitForSingleObject(timer_response, INFINITE) != WAIT_OBJECT_0) {
1006
- usbi_err(ctx, "Failed to wait for timer thread to become ready - aborting");
1007
- goto init_exit;
1023
+ usbi_dbg("timer thread will run on core #%d", i);
1024
+
1025
+ r = LIBUSB_ERROR_NO_MEM;
1026
+ event = CreateEvent(NULL, FALSE, FALSE, NULL);
1027
+ if (event == NULL) {
1028
+ usbi_err(ctx, "could not create event: %s", windows_error_str(0));
1029
+ goto init_exit;
1030
+ }
1031
+ timer_thread = (HANDLE)_beginthreadex(NULL, 0, windows_clock_gettime_threaded, (void *)event,
1032
+ 0, (unsigned int *)&timer_thread_id);
1033
+ if (timer_thread == NULL) {
1034
+ usbi_err(ctx, "unable to create timer thread - aborting");
1035
+ goto init_exit;
1036
+ }
1037
+ if (!SetThreadAffinityMask(timer_thread, affinity)) {
1038
+ usbi_warn(ctx, "unable to set timer thread affinity, timer discrepancies may arise");
1039
+ }
1040
+
1041
+ // Wait for timer thread to init before continuing.
1042
+ if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) {
1043
+ usbi_err(ctx, "failed to wait for timer thread to become ready - aborting");
1044
+ goto init_exit;
1045
+ }
1046
+ }
1047
+ else {
1048
+ usbi_dbg("no hires timer available on this platform");
1049
+ hires_frequency = 0;
1050
+ hires_ticks_to_ps = UINT64_C(0);
1008
1051
  }
1009
1052
 
1010
1053
  // Create a hash table to store session ids. Second parameter is better if prime
@@ -1016,35 +1059,27 @@ static int windows_init(struct libusb_context *ctx)
1016
1059
  init_exit: // Holds semaphore here.
1017
1060
  if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed?
1018
1061
  if (timer_thread) {
1019
- SetEvent(timer_request[1]); // actually the signal to quit the thread.
1020
- if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) {
1062
+ // actually the signal to quit the thread.
1063
+ if (!pPostThreadMessageA(timer_thread_id, WM_TIMER_EXIT, 0, 0) ||
1064
+ (WaitForSingleObject(timer_thread, INFINITE) != WAIT_OBJECT_0)) {
1021
1065
  usbi_warn(ctx, "could not wait for timer thread to quit");
1022
- TerminateThread(timer_thread, 1); // shouldn't happen, but we're destroying
1023
- // all objects it might have held anyway.
1066
+ TerminateThread(timer_thread, 1);
1067
+ // shouldn't happen, but we're destroying
1068
+ // all objects it might have held anyway.
1024
1069
  }
1025
1070
  CloseHandle(timer_thread);
1026
1071
  timer_thread = NULL;
1027
- }
1028
- for (i = 0; i < 2; i++) {
1029
- if (timer_request[i]) {
1030
- CloseHandle(timer_request[i]);
1031
- timer_request[i] = NULL;
1032
- }
1033
- }
1034
- if (timer_response) {
1035
- CloseHandle(timer_response);
1036
- timer_response = NULL;
1037
- }
1038
- if (timer_mutex) {
1039
- CloseHandle(timer_mutex);
1040
- timer_mutex = NULL;
1072
+ timer_thread_id = 0;
1041
1073
  }
1042
1074
  htab_destroy();
1075
+ usbi_mutex_destroy(&autoclaim_lock);
1043
1076
  }
1044
1077
 
1045
1078
  if (r != LIBUSB_SUCCESS)
1046
1079
  --concurrent_usage; // Not expected to call libusb_exit if we failed.
1047
1080
 
1081
+ if (event)
1082
+ CloseHandle(event);
1048
1083
  ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
1049
1084
  CloseHandle(semaphore);
1050
1085
  return r;
@@ -1124,7 +1159,7 @@ static int cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handle
1124
1159
  cd_buf_short.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
1125
1160
  cd_buf_short.req.SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
1126
1161
  cd_buf_short.req.SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i;
1127
- cd_buf_short.req.SetupPacket.wIndex = i;
1162
+ cd_buf_short.req.SetupPacket.wIndex = 0;
1128
1163
  cd_buf_short.req.SetupPacket.wLength = (USHORT)(size - sizeof(USB_DESCRIPTOR_REQUEST));
1129
1164
 
1130
1165
  // Dummy call to get the required data size. Initial failures are reported as info rather
@@ -1153,7 +1188,7 @@ static int cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handle
1153
1188
  cd_buf_actual->SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
1154
1189
  cd_buf_actual->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
1155
1190
  cd_buf_actual->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i;
1156
- cd_buf_actual->SetupPacket.wIndex = i;
1191
+ cd_buf_actual->SetupPacket.wIndex = 0;
1157
1192
  cd_buf_actual->SetupPacket.wLength = (USHORT)(size - sizeof(USB_DESCRIPTOR_REQUEST));
1158
1193
 
1159
1194
  if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, cd_buf_actual, size,
@@ -1199,6 +1234,7 @@ static int init_device(struct libusb_device* dev, struct libusb_device* parent_d
1199
1234
  struct windows_device_priv *priv, *parent_priv;
1200
1235
  struct libusb_context *ctx;
1201
1236
  struct libusb_device* tmp_dev;
1237
+ unsigned long tmp_id;
1202
1238
  unsigned i;
1203
1239
 
1204
1240
  if ((dev == NULL) || (parent_dev == NULL)) {
@@ -1216,8 +1252,10 @@ static int init_device(struct libusb_device* dev, struct libusb_device* parent_d
1216
1252
  // If that's the case, lookup the ancestors to set the bus number
1217
1253
  if (parent_dev->bus_number == 0) {
1218
1254
  for (i=2; ; i++) {
1219
- tmp_dev = usbi_get_device_by_session_id(ctx, get_ancestor_session_id(devinst, i));
1220
- if (tmp_dev == NULL) break;
1255
+ tmp_id = get_ancestor_session_id(devinst, i);
1256
+ if (tmp_id == 0) break;
1257
+ tmp_dev = usbi_get_device_by_session_id(ctx, tmp_id);
1258
+ if (tmp_dev == NULL) continue;
1221
1259
  if (tmp_dev->bus_number != 0) {
1222
1260
  usbi_dbg("got bus number from ancestor #%d", i);
1223
1261
  parent_dev->bus_number = tmp_dev->bus_number;
@@ -1525,7 +1563,7 @@ static int windows_get_device_list(struct libusb_context *ctx, struct discovered
1525
1563
  //#define ENUM_DEBUG
1526
1564
  #ifdef ENUM_DEBUG
1527
1565
  const char *passname[] = { "HCD", "HUB", "GEN", "DEV", "HID", "EXT" };
1528
- usbi_dbg("\n#### PROCESSING %ss %s", passname[(pass<=HID_PASS)?pass:HID_PASS+1],
1566
+ usbi_dbg("#### PROCESSING %ss %s", passname[(pass<=HID_PASS)?pass:HID_PASS+1],
1529
1567
  (pass!=GEN_PASS)?guid_to_string(guid[pass]):"");
1530
1568
  #endif
1531
1569
  for (i = 0; ; i++) {
@@ -1627,6 +1665,10 @@ static int windows_get_device_list(struct libusb_context *ctx, struct discovered
1627
1665
  LOOP_BREAK(LIBUSB_ERROR_OVERFLOW);
1628
1666
  }
1629
1667
  if_guid = (GUID*) calloc(1, sizeof(GUID));
1668
+ if (if_guid == NULL) {
1669
+ usbi_err(ctx, "could not calloc for if_guid: not enough memory");
1670
+ LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
1671
+ }
1630
1672
  pCLSIDFromString(guid_string_w, if_guid);
1631
1673
  guid[nb_guids++] = if_guid;
1632
1674
  usbi_dbg("extra GUID: %s", guid_to_string(if_guid));
@@ -1849,29 +1891,18 @@ static void windows_exit(void)
1849
1891
  exit_polling();
1850
1892
 
1851
1893
  if (timer_thread) {
1852
- SetEvent(timer_request[1]); // actually the signal to quit the thread.
1853
- if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) {
1894
+ // actually the signal to quit the thread.
1895
+ if (!pPostThreadMessageA(timer_thread_id, WM_TIMER_EXIT, 0, 0) ||
1896
+ (WaitForSingleObject(timer_thread, INFINITE) != WAIT_OBJECT_0)) {
1854
1897
  usbi_dbg("could not wait for timer thread to quit");
1855
1898
  TerminateThread(timer_thread, 1);
1856
1899
  }
1857
1900
  CloseHandle(timer_thread);
1858
1901
  timer_thread = NULL;
1859
- }
1860
- for (i = 0; i < 2; i++) {
1861
- if (timer_request[i]) {
1862
- CloseHandle(timer_request[i]);
1863
- timer_request[i] = NULL;
1864
- }
1865
- }
1866
- if (timer_response) {
1867
- CloseHandle(timer_response);
1868
- timer_response = NULL;
1869
- }
1870
- if (timer_mutex) {
1871
- CloseHandle(timer_mutex);
1872
- timer_mutex = NULL;
1902
+ timer_thread_id = 0;
1873
1903
  }
1874
1904
  htab_destroy();
1905
+ usbi_mutex_destroy(&autoclaim_lock);
1875
1906
  }
1876
1907
 
1877
1908
  ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
@@ -1903,7 +1934,7 @@ static int windows_get_config_descriptor(struct libusb_device *dev, uint8_t conf
1903
1934
 
1904
1935
  config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptor[config_index];
1905
1936
 
1906
- size = min(config_header->wTotalLength, len);
1937
+ size = MIN(config_header->wTotalLength, len);
1907
1938
  memcpy(buffer, priv->config_descriptor[config_index], size);
1908
1939
  *host_endian = 0;
1909
1940
 
@@ -1986,9 +2017,6 @@ static int windows_claim_interface(struct libusb_device_handle *dev_handle, int
1986
2017
  int r = LIBUSB_SUCCESS;
1987
2018
  struct windows_device_priv *priv = _device_priv(dev_handle->dev);
1988
2019
 
1989
- if (iface >= USB_MAXINTERFACES)
1990
- return LIBUSB_ERROR_INVALID_PARAM;
1991
-
1992
2020
  safe_free(priv->usb_interface[iface].endpoint);
1993
2021
  priv->usb_interface[iface].nb_endpoints= 0;
1994
2022
 
@@ -2084,7 +2112,6 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer)
2084
2112
  usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
2085
2113
  (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
2086
2114
 
2087
- itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
2088
2115
  return LIBUSB_SUCCESS;
2089
2116
  }
2090
2117
 
@@ -2104,7 +2131,6 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer)
2104
2131
  usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
2105
2132
  (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
2106
2133
 
2107
- itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
2108
2134
  return LIBUSB_SUCCESS;
2109
2135
  }
2110
2136
 
@@ -2123,7 +2149,6 @@ static int submit_control_transfer(struct usbi_transfer *itransfer)
2123
2149
 
2124
2150
  usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN);
2125
2151
 
2126
- itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
2127
2152
  return LIBUSB_SUCCESS;
2128
2153
 
2129
2154
  }
@@ -2251,7 +2276,7 @@ static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds,
2251
2276
  {
2252
2277
  struct windows_transfer_priv* transfer_priv = NULL;
2253
2278
  POLL_NFDS_TYPE i = 0;
2254
- bool found = false;
2279
+ bool found;
2255
2280
  struct usbi_transfer *transfer;
2256
2281
  DWORD io_size, io_result;
2257
2282
 
@@ -2269,6 +2294,7 @@ static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds,
2269
2294
  // Because a Windows OVERLAPPED is used for poll emulation,
2270
2295
  // a pollable fd is created and stored with each transfer
2271
2296
  usbi_mutex_lock(&ctx->flying_transfers_lock);
2297
+ found = false;
2272
2298
  list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
2273
2299
  transfer_priv = usbi_transfer_get_os_priv(transfer);
2274
2300
  if (transfer_priv->pollable_fd.fd == fds[i].fd) {
@@ -2296,6 +2322,7 @@ static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds,
2296
2322
  // newly allocated wfd that took the place of the one from the transfer.
2297
2323
  windows_handle_callback(transfer, io_result, io_size);
2298
2324
  } else {
2325
+ usbi_mutex_unlock(&ctx->open_devs_lock);
2299
2326
  usbi_err(ctx, "could not find a matching transfer for fd %x", fds[i]);
2300
2327
  return LIBUSB_ERROR_NOT_FOUND;
2301
2328
  }
@@ -2310,66 +2337,42 @@ static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds,
2310
2337
  */
2311
2338
  unsigned __stdcall windows_clock_gettime_threaded(void* param)
2312
2339
  {
2313
- LARGE_INTEGER hires_counter, li_frequency;
2314
- LONG nb_responses;
2315
- int timer_index;
2316
-
2317
- // Init - find out if we have access to a monotonic (hires) timer
2318
- if (!QueryPerformanceFrequency(&li_frequency)) {
2319
- usbi_dbg("no hires timer available on this platform");
2320
- hires_frequency = 0;
2321
- hires_ticks_to_ps = UINT64_C(0);
2322
- } else {
2323
- hires_frequency = li_frequency.QuadPart;
2324
- // The hires frequency can go as high as 4 GHz, so we'll use a conversion
2325
- // to picoseconds to compute the tv_nsecs part in clock_gettime
2326
- hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency;
2327
- usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency);
2328
- }
2340
+ struct timer_request *request;
2341
+ LARGE_INTEGER hires_counter;
2342
+ MSG msg;
2343
+
2344
+ // The following call will create this thread's message queue
2345
+ // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms644946.aspx
2346
+ pPeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
2329
2347
 
2330
2348
  // Signal windows_init() that we're ready to service requests
2331
- if (ReleaseSemaphore(timer_response, 1, NULL) == 0) {
2332
- usbi_dbg("unable to release timer semaphore: %s", windows_error_str(0));
2349
+ if (!SetEvent((HANDLE)param)) {
2350
+ usbi_dbg("SetEvent failed for timer init event: %s", windows_error_str(0));
2333
2351
  }
2352
+ param = NULL;
2334
2353
 
2335
2354
  // Main loop - wait for requests
2336
2355
  while (1) {
2337
- timer_index = WaitForMultipleObjects(2, timer_request, FALSE, INFINITE) - WAIT_OBJECT_0;
2338
- if ( (timer_index != 0) && (timer_index != 1) ) {
2339
- usbi_dbg("failure to wait on requests: %s", windows_error_str(0));
2340
- continue;
2341
- }
2342
- if (request_count[timer_index] == 0) {
2343
- // Request already handled
2344
- ResetEvent(timer_request[timer_index]);
2345
- // There's still a possiblity that a thread sends a request between the
2346
- // time we test request_count[] == 0 and we reset the event, in which case
2347
- // the request would be ignored. The simple solution to that is to test
2348
- // request_count again and process requests if non zero.
2349
- if (request_count[timer_index] == 0)
2350
- continue;
2356
+ if (pGetMessageA(&msg, NULL, WM_TIMER_REQUEST, WM_TIMER_EXIT) == -1) {
2357
+ usbi_err(NULL, "GetMessage failed for timer thread: %s", windows_error_str(0));
2358
+ return 1;
2351
2359
  }
2352
- switch (timer_index) {
2353
- case 0:
2354
- WaitForSingleObject(timer_mutex, INFINITE);
2360
+
2361
+ switch (msg.message) {
2362
+ case WM_TIMER_REQUEST:
2355
2363
  // Requests to this thread are for hires always
2356
- if ((QueryPerformanceCounter(&hires_counter) != 0) && (hires_frequency != 0)) {
2357
- timer_tp.tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
2358
- timer_tp.tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency)/1000) * hires_ticks_to_ps);
2359
- } else {
2360
- // Fallback to real-time if we can't get monotonic value
2361
- // Note that real-time clock does not wait on the mutex or this thread.
2362
- windows_clock_gettime(USBI_CLOCK_REALTIME, &timer_tp);
2364
+ // Microsoft says that this function always succeeds on XP and later
2365
+ // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms644904.aspx
2366
+ request = (struct timer_request *)msg.lParam;
2367
+ QueryPerformanceCounter(&hires_counter);
2368
+ request->tp->tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
2369
+ request->tp->tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency) / 1000) * hires_ticks_to_ps);
2370
+ if (!SetEvent(request->event)) {
2371
+ usbi_err(NULL, "SetEvent failed for timer request: %s", windows_error_str(0));
2363
2372
  }
2364
- ReleaseMutex(timer_mutex);
2373
+ break;
2365
2374
 
2366
- nb_responses = InterlockedExchange((LONG*)&request_count[0], 0);
2367
- if ( (nb_responses)
2368
- && (ReleaseSemaphore(timer_response, nb_responses, NULL) == 0) ) {
2369
- usbi_dbg("unable to release timer semaphore: %s", windows_error_str(0));
2370
- }
2371
- continue;
2372
- case 1: // time to quit
2375
+ case WM_TIMER_EXIT:
2373
2376
  usbi_dbg("timer thread quitting");
2374
2377
  return 0;
2375
2378
  }
@@ -2378,29 +2381,41 @@ unsigned __stdcall windows_clock_gettime_threaded(void* param)
2378
2381
 
2379
2382
  static int windows_clock_gettime(int clk_id, struct timespec *tp)
2380
2383
  {
2384
+ struct timer_request request;
2381
2385
  FILETIME filetime;
2382
2386
  ULARGE_INTEGER rtime;
2383
2387
  DWORD r;
2384
2388
  switch(clk_id) {
2385
2389
  case USBI_CLOCK_MONOTONIC:
2386
- if (hires_frequency != 0) {
2387
- while (1) {
2388
- InterlockedIncrement((LONG*)&request_count[0]);
2389
- SetEvent(timer_request[0]);
2390
- r = WaitForSingleObject(timer_response, TIMER_REQUEST_RETRY_MS);
2391
- switch(r) {
2392
- case WAIT_OBJECT_0:
2393
- WaitForSingleObject(timer_mutex, INFINITE);
2394
- *tp = timer_tp;
2395
- ReleaseMutex(timer_mutex);
2396
- return LIBUSB_SUCCESS;
2397
- case WAIT_TIMEOUT:
2390
+ if (timer_thread) {
2391
+ request.tp = tp;
2392
+ request.event = CreateEvent(NULL, FALSE, FALSE, NULL);
2393
+ if (request.event == NULL) {
2394
+ return LIBUSB_ERROR_NO_MEM;
2395
+ }
2396
+
2397
+ if (!pPostThreadMessageA(timer_thread_id, WM_TIMER_REQUEST, 0, (LPARAM)&request)) {
2398
+ usbi_err(NULL, "PostThreadMessage failed for timer thread: %s", windows_error_str(0));
2399
+ CloseHandle(request.event);
2400
+ return LIBUSB_ERROR_OTHER;
2401
+ }
2402
+
2403
+ do {
2404
+ r = WaitForSingleObject(request.event, TIMER_REQUEST_RETRY_MS);
2405
+ if (r == WAIT_TIMEOUT) {
2398
2406
  usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?");
2399
- break; // Retry until successful
2400
- default:
2401
- usbi_dbg("WaitForSingleObject failed: %s", windows_error_str(0));
2402
- return LIBUSB_ERROR_OTHER;
2403
2407
  }
2408
+ else if (r == WAIT_FAILED) {
2409
+ usbi_err(NULL, "WaitForSingleObject failed: %s", windows_error_str(0));
2410
+ }
2411
+ } while (r == WAIT_TIMEOUT);
2412
+ CloseHandle(request.event);
2413
+
2414
+ if (r == WAIT_OBJECT_0) {
2415
+ return LIBUSB_SUCCESS;
2416
+ }
2417
+ else {
2418
+ return LIBUSB_ERROR_OTHER;
2404
2419
  }
2405
2420
  }
2406
2421
  // Fall through and return real-time if monotonic was not detected @ timer init
@@ -2462,6 +2477,7 @@ const struct usbi_os_backend windows_backend = {
2462
2477
  windows_clear_transfer_priv,
2463
2478
 
2464
2479
  windows_handle_events,
2480
+ NULL, /* handle_transfer_completion() */
2465
2481
 
2466
2482
  windows_clock_gettime,
2467
2483
  #if defined(USBI_TIMERFD_AVAILABLE)
@@ -2470,7 +2486,6 @@ const struct usbi_os_backend windows_backend = {
2470
2486
  sizeof(struct windows_device_priv),
2471
2487
  sizeof(struct windows_device_handle_priv),
2472
2488
  sizeof(struct windows_transfer_priv),
2473
- 0,
2474
2489
  };
2475
2490
 
2476
2491
 
@@ -2668,7 +2683,7 @@ static int winusbx_init(int sub_api, struct libusb_context *ctx)
2668
2683
  if (h == NULL) {
2669
2684
  h = LoadLibraryA("WinUSB");
2670
2685
  } if (h == NULL) {
2671
- usbi_warn(ctx, "WinUSB DLL is not available either,\n"
2686
+ usbi_warn(ctx, "WinUSB DLL is not available either, "
2672
2687
  "you will not be able to access devices outside of enumeration");
2673
2688
  return LIBUSB_ERROR_NOT_FOUND;
2674
2689
  }
@@ -2769,7 +2784,7 @@ static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle)
2769
2784
  {
2770
2785
  struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
2771
2786
  struct windows_device_priv *priv = _device_priv(dev_handle->dev);
2772
- HANDLE file_handle;
2787
+ HANDLE handle;
2773
2788
  int i;
2774
2789
 
2775
2790
  if (sub_api == SUB_API_NOTSET)
@@ -2777,13 +2792,39 @@ static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle)
2777
2792
  if (!WinUSBX[sub_api].initialized)
2778
2793
  return;
2779
2794
 
2780
- for (i = 0; i < USB_MAXINTERFACES; i++) {
2781
- if (priv->usb_interface[i].apib->id == USB_API_WINUSBX) {
2782
- file_handle = handle_priv->interface_handle[i].dev_handle;
2783
- if ( (file_handle != 0) && (file_handle != INVALID_HANDLE_VALUE)) {
2784
- CloseHandle(file_handle);
2795
+ if (priv->apib->id == USB_API_COMPOSITE) {
2796
+ // If this is a composite device, just free and close all WinUSB-like
2797
+ // interfaces directly (each is independent and not associated with another)
2798
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
2799
+ if (priv->usb_interface[i].apib->id == USB_API_WINUSBX) {
2800
+ handle = handle_priv->interface_handle[i].api_handle;
2801
+ if ((handle != 0) && (handle != INVALID_HANDLE_VALUE)) {
2802
+ WinUSBX[sub_api].Free(handle);
2803
+ }
2804
+ handle = handle_priv->interface_handle[i].dev_handle;
2805
+ if ((handle != 0) && (handle != INVALID_HANDLE_VALUE)) {
2806
+ CloseHandle(handle);
2807
+ }
2808
+ }
2809
+ }
2810
+ }
2811
+ else {
2812
+ // If this is a WinUSB device, free all interfaces above interface 0,
2813
+ // then free and close interface 0 last
2814
+ for (i = 1; i < USB_MAXINTERFACES; i++) {
2815
+ handle = handle_priv->interface_handle[i].api_handle;
2816
+ if ((handle != 0) && (handle != INVALID_HANDLE_VALUE)) {
2817
+ WinUSBX[sub_api].Free(handle);
2785
2818
  }
2786
2819
  }
2820
+ handle = handle_priv->interface_handle[0].api_handle;
2821
+ if ((handle != 0) && (handle != INVALID_HANDLE_VALUE)) {
2822
+ WinUSBX[sub_api].Free(handle);
2823
+ }
2824
+ handle = handle_priv->interface_handle[0].dev_handle;
2825
+ if ((handle != 0) && (handle != INVALID_HANDLE_VALUE)) {
2826
+ CloseHandle(handle);
2827
+ }
2787
2828
  }
2788
2829
  }
2789
2830
 
@@ -3579,7 +3620,7 @@ static int _hid_get_descriptor(struct hid_device_priv* dev, HANDLE hid_handle, i
3579
3620
  return LIBUSB_ERROR_OTHER;
3580
3621
  }
3581
3622
  usbi_dbg("unsupported");
3582
- return LIBUSB_ERROR_INVALID_PARAM;
3623
+ return LIBUSB_ERROR_NOT_SUPPORTED;
3583
3624
  }
3584
3625
 
3585
3626
  static int _hid_get_report(struct hid_device_priv* dev, HANDLE hid_handle, int id, void *data,
@@ -4086,7 +4127,7 @@ static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itrans
4086
4127
  r = LIBUSB_COMPLETED;
4087
4128
  } else {
4088
4129
  usbi_warn(ctx, "cannot set configuration other than the default one");
4089
- r = LIBUSB_ERROR_INVALID_PARAM;
4130
+ r = LIBUSB_ERROR_NOT_SUPPORTED;
4090
4131
  }
4091
4132
  break;
4092
4133
  case LIBUSB_REQUEST_GET_INTERFACE:
@@ -4102,7 +4143,7 @@ static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itrans
4102
4143
  break;
4103
4144
  default:
4104
4145
  usbi_warn(ctx, "unsupported HID control request");
4105
- r = LIBUSB_ERROR_INVALID_PARAM;
4146
+ r = LIBUSB_ERROR_NOT_SUPPORTED;
4106
4147
  break;
4107
4148
  }
4108
4149
  break;
@@ -4113,7 +4154,7 @@ static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itrans
4113
4154
  break;
4114
4155
  default:
4115
4156
  usbi_warn(ctx, "unsupported HID control request");
4116
- r = LIBUSB_ERROR_INVALID_PARAM;
4157
+ r = LIBUSB_ERROR_NOT_SUPPORTED;
4117
4158
  break;
4118
4159
  }
4119
4160
 
@@ -4387,24 +4428,31 @@ static void composite_close(int sub_api, struct libusb_device_handle *dev_handle
4387
4428
  {
4388
4429
  struct windows_device_priv *priv = _device_priv(dev_handle->dev);
4389
4430
  uint8_t i;
4390
- bool available[SUB_API_MAX];
4391
-
4392
- for (i = 0; i<SUB_API_MAX; i++) {
4393
- available[i] = false;
4394
- }
4431
+ // SUB_API_MAX+1 as the SUB_API_MAX pos is used to indicate availability of HID
4432
+ bool available[SUB_API_MAX+1] = {0};
4395
4433
 
4396
4434
  for (i=0; i<USB_MAXINTERFACES; i++) {
4397
- if ( (priv->usb_interface[i].apib->id == USB_API_WINUSBX)
4398
- && (priv->usb_interface[i].sub_api != SUB_API_NOTSET) ) {
4399
- available[priv->usb_interface[i].sub_api] = true;
4435
+ switch (priv->usb_interface[i].apib->id) {
4436
+ case USB_API_WINUSBX:
4437
+ if (priv->usb_interface[i].sub_api != SUB_API_NOTSET)
4438
+ available[priv->usb_interface[i].sub_api] = true;
4439
+ break;
4440
+ case USB_API_HID:
4441
+ available[SUB_API_MAX] = true;
4442
+ break;
4443
+ default:
4444
+ break;
4400
4445
  }
4401
4446
  }
4402
4447
 
4403
- for (i=0; i<SUB_API_MAX; i++) {
4448
+ for (i=0; i<SUB_API_MAX; i++) { // WinUSB-like drivers
4404
4449
  if (available[i]) {
4405
4450
  usb_api_backend[USB_API_WINUSBX].close(i, dev_handle);
4406
4451
  }
4407
4452
  }
4453
+ if (available[SUB_API_MAX]) { // HID driver
4454
+ hid_close(SUB_API_NOTSET, dev_handle);
4455
+ }
4408
4456
  }
4409
4457
 
4410
4458
  static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface)
@@ -4433,19 +4481,57 @@ static int composite_submit_control_transfer(int sub_api, struct usbi_transfer *
4433
4481
  struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
4434
4482
  struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
4435
4483
  struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
4436
- int i, pass;
4484
+ struct libusb_config_descriptor *conf_desc;
4485
+ WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *) transfer->buffer;
4486
+ int iface, pass, r;
4437
4487
 
4438
4488
  // Interface shouldn't matter for control, but it does in practice, with Windows'
4439
- // restrictions with regards to accessing HID keyboards and mice. Try a 2 pass approach
4489
+ // restrictions with regards to accessing HID keyboards and mice. Try to target
4490
+ // a specific interface first, if possible.
4491
+ switch (LIBUSB_REQ_RECIPIENT(setup->request_type)) {
4492
+ case LIBUSB_RECIPIENT_INTERFACE:
4493
+ iface = setup->index & 0xFF;
4494
+ break;
4495
+ case LIBUSB_RECIPIENT_ENDPOINT:
4496
+ r = libusb_get_config_descriptor(transfer->dev_handle->dev, (uint8_t)(priv->active_config-1), &conf_desc);
4497
+ if (r == LIBUSB_SUCCESS) {
4498
+ iface = get_interface_by_endpoint(conf_desc, (setup->index & 0xFF));
4499
+ libusb_free_config_descriptor(conf_desc);
4500
+ break;
4501
+ }
4502
+ // Fall through if not able to determine interface
4503
+ default:
4504
+ iface = -1;
4505
+ break;
4506
+ }
4507
+
4508
+ // Try and target a specific interface if the control setup indicates such
4509
+ if ((iface >= 0) && (iface < USB_MAXINTERFACES)) {
4510
+ usbi_dbg("attempting control transfer targeted to interface %d", iface);
4511
+ if (priv->usb_interface[iface].path != NULL) {
4512
+ r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer);
4513
+ if (r == LIBUSB_SUCCESS) {
4514
+ return r;
4515
+ }
4516
+ }
4517
+ }
4518
+
4519
+ // Either not targeted to a specific interface or no luck in doing so.
4520
+ // Try a 2 pass approach with all interfaces.
4440
4521
  for (pass = 0; pass < 2; pass++) {
4441
- for (i=0; i<USB_MAXINTERFACES; i++) {
4442
- if (priv->usb_interface[i].path != NULL) {
4443
- if ((pass == 0) && (priv->usb_interface[i].restricted_functionality)) {
4444
- usbi_dbg("trying to skip restricted interface #%d (HID keyboard or mouse?)", i);
4522
+ for (iface = 0; iface < USB_MAXINTERFACES; iface++) {
4523
+ if (priv->usb_interface[iface].path != NULL) {
4524
+ if ((pass == 0) && (priv->usb_interface[iface].restricted_functionality)) {
4525
+ usbi_dbg("trying to skip restricted interface #%d (HID keyboard or mouse?)", iface);
4445
4526
  continue;
4446
4527
  }
4447
- usbi_dbg("using interface %d", i);
4448
- return priv->usb_interface[i].apib->submit_control_transfer(priv->usb_interface[i].sub_api, itransfer);
4528
+ usbi_dbg("using interface %d", iface);
4529
+ r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer);
4530
+ // If not supported on this API, it may be supported on another, so don't give up yet!!
4531
+ if (r == LIBUSB_ERROR_NOT_SUPPORTED) {
4532
+ continue;
4533
+ }
4534
+ return r;
4449
4535
  }
4450
4536
  }
4451
4537
  }