libusb 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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
  }