libusb 0.3.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Gemfile +1 -0
  5. data/History.md +10 -0
  6. data/README.md +19 -6
  7. data/Rakefile +1 -1
  8. data/ext/extconf.rb +17 -1
  9. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/AUTHORS +18 -6
  10. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/COPYING +0 -0
  11. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/ChangeLog +58 -1
  12. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/INSTALL +0 -0
  13. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/Makefile.am +6 -1
  14. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/Makefile.in +248 -174
  15. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/NEWS +2 -2
  16. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/PORTING +0 -0
  17. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/README +2 -1
  18. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/TODO +0 -0
  19. data/ext/libusbx-1.0.17/Xcode/common.xcconfig +40 -0
  20. data/ext/libusbx-1.0.17/Xcode/config.h +28 -0
  21. data/ext/libusbx-1.0.17/Xcode/debug.xcconfig +29 -0
  22. data/ext/libusbx-1.0.17/Xcode/libusbx.xcconfig +21 -0
  23. data/ext/libusbx-1.0.17/Xcode/libusbx.xcodeproj/project.pbxproj +864 -0
  24. data/ext/libusbx-1.0.17/Xcode/libusbx_debug.xcconfig +21 -0
  25. data/ext/libusbx-1.0.17/Xcode/libusbx_release.xcconfig +21 -0
  26. data/ext/libusbx-1.0.17/Xcode/release.xcconfig +29 -0
  27. data/ext/libusbx-1.0.17/aclocal.m4 +1112 -0
  28. data/ext/libusbx-1.0.17/android/README +114 -0
  29. data/ext/libusbx-1.0.17/android/config.h +90 -0
  30. data/ext/libusbx-1.0.17/android/jni/Android.mk +23 -0
  31. data/ext/libusbx-1.0.17/android/jni/Application.mk +19 -0
  32. data/ext/libusbx-1.0.17/android/jni/examples.mk +134 -0
  33. data/ext/libusbx-1.0.17/android/jni/libusb.mk +54 -0
  34. data/ext/libusbx-1.0.17/android/jni/tests.mk +56 -0
  35. data/ext/libusbx-1.0.17/compile +347 -0
  36. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/config.guess +164 -130
  37. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/config.h.in +37 -1
  38. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/config.sub +174 -89
  39. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/configure +723 -302
  40. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/configure.ac +71 -20
  41. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/depcomp +345 -185
  42. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/doc/Makefile.am +0 -0
  43. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/doc/Makefile.in +95 -32
  44. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/doc/doxygen.cfg.in +1 -1
  45. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/examples/Makefile.am +5 -4
  46. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/examples/Makefile.in +208 -104
  47. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/examples/dpfp.c +1 -1
  48. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/examples/dpfp_threaded.c +1 -1
  49. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/examples/ezusb.c +188 -8
  50. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/examples/ezusb.h +18 -5
  51. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/examples/fxload.c +90 -64
  52. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/examples/getopt/getopt.c +0 -0
  53. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/examples/getopt/getopt.h +0 -0
  54. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/examples/getopt/getopt1.c +0 -0
  55. data/ext/libusbx-1.0.17/examples/hotplugtest.c +97 -0
  56. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/examples/listdevs.c +12 -4
  57. data/ext/libusbx-1.0.17/examples/sam3u_benchmark.c +193 -0
  58. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/examples/xusb.c +106 -49
  59. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/install-sh +21 -14
  60. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb-1.0.pc.in +1 -1
  61. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/Makefile.am +29 -10
  62. data/ext/libusbx-1.0.17/libusb/Makefile.in +914 -0
  63. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/core.c +378 -87
  64. data/ext/libusbx-1.0.17/libusb/descriptor.c +1199 -0
  65. data/ext/libusbx-1.0.17/libusb/hotplug.c +322 -0
  66. data/ext/libusbx-1.0.17/libusb/hotplug.h +82 -0
  67. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/io.c +182 -62
  68. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/libusb-1.0.def +32 -0
  69. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/libusb-1.0.rc +2 -0
  70. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/libusb.h +481 -32
  71. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/libusbi.h +135 -38
  72. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/os/darwin_usb.c +591 -496
  73. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/os/darwin_usb.h +39 -46
  74. data/ext/libusbx-1.0.17/libusb/os/linux_netlink.c +345 -0
  75. data/ext/libusbx-1.0.17/libusb/os/linux_udev.c +306 -0
  76. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/os/linux_usbfs.c +653 -617
  77. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/os/linux_usbfs.h +32 -0
  78. data/ext/{libusbx-1.0.14/libusb/os/openbsd_usb.c → libusbx-1.0.17/libusb/os/netbsd_usb.c} +70 -63
  79. data/ext/libusbx-1.0.17/libusb/os/openbsd_usb.c +823 -0
  80. data/ext/libusbx-1.0.17/libusb/os/poll_posix.c +51 -0
  81. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/os/poll_posix.h +2 -1
  82. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/os/poll_windows.c +85 -106
  83. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/os/poll_windows.h +14 -3
  84. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/os/threads_posix.c +3 -1
  85. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/os/threads_posix.h +0 -0
  86. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/os/threads_windows.c +6 -5
  87. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/os/threads_windows.h +0 -0
  88. data/ext/libusbx-1.0.17/libusb/os/wince_usb.c +1026 -0
  89. data/ext/libusbx-1.0.17/libusb/os/wince_usb.h +131 -0
  90. data/ext/libusbx-1.0.17/libusb/os/windows_common.h +108 -0
  91. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/os/windows_usb.c +92 -57
  92. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/os/windows_usb.h +2 -63
  93. data/ext/libusbx-1.0.17/libusb/strerror.c +184 -0
  94. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/sync.c +24 -38
  95. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/libusb/version.h +1 -1
  96. data/ext/libusbx-1.0.17/libusb/version_nano.h +1 -0
  97. data/ext/{libusbx-1.0.14 → libusbx-1.0.17}/ltmain.sh +60 -41
  98. data/ext/{libusbx-1.0.14/aclocal.m4 → libusbx-1.0.17/m4/libtool.m4} +229 -1723
  99. data/ext/libusbx-1.0.17/m4/ltoptions.m4 +384 -0
  100. data/ext/libusbx-1.0.17/m4/ltsugar.m4 +123 -0
  101. data/ext/libusbx-1.0.17/m4/ltversion.m4 +23 -0
  102. data/ext/libusbx-1.0.17/m4/lt~obsolete.m4 +98 -0
  103. data/ext/libusbx-1.0.17/missing +215 -0
  104. data/ext/libusbx-1.0.17/tests/Makefile.am +6 -0
  105. data/ext/libusbx-1.0.17/tests/Makefile.in +583 -0
  106. data/ext/libusbx-1.0.17/tests/libusbx_testlib.h +107 -0
  107. data/ext/libusbx-1.0.17/tests/stress.c +160 -0
  108. data/ext/libusbx-1.0.17/tests/testlib.c +276 -0
  109. data/lib/libusb.rb +4 -0
  110. data/lib/libusb/call.rb +43 -1
  111. data/lib/libusb/constants.rb +5 -0
  112. data/lib/libusb/context.rb +100 -0
  113. data/lib/libusb/dev_handle.rb +27 -0
  114. data/lib/libusb/device.rb +10 -4
  115. data/lib/libusb/version_gem.rb +1 -1
  116. data/test/test_libusb_capability.rb +2 -2
  117. data/test/test_libusb_compat.rb +2 -2
  118. data/test/test_libusb_compat_mass_storage.rb +2 -2
  119. data/test/test_libusb_descriptors.rb +4 -2
  120. data/test/test_libusb_event_machine.rb +2 -2
  121. data/test/test_libusb_gc.rb +2 -2
  122. data/test/test_libusb_hotplug.rb +115 -0
  123. data/test/test_libusb_iso_transfer.rb +3 -3
  124. data/test/test_libusb_mass_storage.rb +6 -16
  125. data/test/test_libusb_mass_storage2.rb +26 -3
  126. data/test/test_libusb_structs.rb +2 -2
  127. data/test/test_libusb_threads.rb +2 -2
  128. data/test/test_libusb_version.rb +2 -2
  129. metadata +127 -68
  130. metadata.gz.sig +0 -0
  131. data/ext/libusbx-1.0.14/THANKS +0 -7
  132. data/ext/libusbx-1.0.14/compile +0 -143
  133. data/ext/libusbx-1.0.14/libusb/Makefile.in +0 -721
  134. data/ext/libusbx-1.0.14/libusb/descriptor.c +0 -731
  135. data/ext/libusbx-1.0.14/libusb/version_nano.h +0 -1
  136. data/ext/libusbx-1.0.14/missing +0 -376
@@ -1,6 +1,7 @@
1
1
  /*
2
2
  * Windows compat: POSIX compatibility wrapper
3
- * Copyright © 2009-2010 Pete Batard <pbatard@gmail.com>
3
+ * Copyright © 2012-2013 RealVNC Ltd.
4
+ * Copyright © 2009-2010 Pete Batard <pete@akeo.ie>
4
5
  * With contributions from Michael Plante, Orin Eman et al.
5
6
  * Parts of poll implementation from libusb-win32, by Stephan Meyer et al.
6
7
  *
@@ -31,12 +32,17 @@
31
32
  #define STATUS_REPARSE ((LONG)0x00000104L)
32
33
  #endif
33
34
  #define STATUS_COMPLETED_SYNCHRONOUSLY STATUS_REPARSE
35
+ #if defined(_WIN32_WCE)
36
+ // WinCE doesn't have a HasOverlappedIoCompleted() macro, so attempt to emulate it
37
+ #define HasOverlappedIoCompleted(lpOverlapped) (((DWORD)(lpOverlapped)->Internal) != STATUS_PENDING)
38
+ #endif
34
39
  #define HasOverlappedIoCompletedSync(lpOverlapped) (((DWORD)(lpOverlapped)->Internal) == STATUS_COMPLETED_SYNCHRONOUSLY)
35
40
 
36
41
  #define DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2)
37
42
 
38
43
  enum windows_version {
39
44
  WINDOWS_UNSUPPORTED,
45
+ WINDOWS_CE,
40
46
  WINDOWS_XP,
41
47
  WINDOWS_2003, // also includes XP 64
42
48
  WINDOWS_VISTA_AND_LATER,
@@ -66,10 +72,14 @@ enum rw_type {
66
72
  };
67
73
 
68
74
  // fd struct that can be used for polling on Windows
75
+ typedef int cancel_transfer(struct usbi_transfer *itransfer);
76
+
69
77
  struct winfd {
70
78
  int fd; // what's exposed to libusb core
71
79
  HANDLE handle; // what we need to attach overlapped to the I/O op, so we can poll it
72
80
  OVERLAPPED* overlapped; // what will report our I/O status
81
+ struct usbi_transfer *itransfer; // Associated transfer, or NULL if completed
82
+ cancel_transfer *cancel_fn; // Function pointer to cancel transfer API
73
83
  enum rw_type rw; // I/O transfer direction: read *XOR* write (NOT BOTH)
74
84
  };
75
85
  extern const struct winfd INVALID_WINFD;
@@ -82,8 +92,9 @@ int usbi_close(int fd);
82
92
 
83
93
  void init_polling(void);
84
94
  void exit_polling(void);
85
- struct winfd usbi_create_fd(HANDLE handle, int access_mode);
86
- void usbi_free_fd(int fd);
95
+ struct winfd usbi_create_fd(HANDLE handle, int access_mode,
96
+ struct usbi_transfer *transfer, cancel_transfer *cancel_fn);
97
+ void usbi_free_fd(struct winfd* winfd);
87
98
  struct winfd fd_to_winfd(int fd);
88
99
  struct winfd handle_to_winfd(HANDLE handle);
89
100
  struct winfd overlapped_to_winfd(OVERLAPPED* overlapped);
@@ -63,7 +63,9 @@ finish:
63
63
  int usbi_get_tid(void)
64
64
  {
65
65
  int ret = -1;
66
- #if defined(__linux__)
66
+ #if defined(__ANDROID__)
67
+ ret = gettid();
68
+ #elif defined(__linux__)
67
69
  ret = syscall(SYS_gettid);
68
70
  #elif defined(__OpenBSD__)
69
71
  /* The following only works with OpenBSD > 5.1 as it requires
@@ -25,6 +25,7 @@
25
25
 
26
26
  #include "libusbi.h"
27
27
 
28
+ extern const uint64_t epoch_time;
28
29
 
29
30
  int usbi_mutex_init(usbi_mutex_t *mutex,
30
31
  const usbi_mutexattr_t *attr) {
@@ -80,8 +81,6 @@ int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex) {
80
81
  return 0;
81
82
  }
82
83
 
83
-
84
-
85
84
  int usbi_cond_init(usbi_cond_t *cond,
86
85
  const usbi_condattr_t *attr) {
87
86
  UNUSED(attr);
@@ -129,7 +128,7 @@ int usbi_cond_signal(usbi_cond_t *cond) {
129
128
  // The wait function will remove its respective item from the list.
130
129
  return SetEvent(pos->event) ? 0 : ((errno=EINVAL));
131
130
  }
132
- static int __inline usbi_cond_intwait(usbi_cond_t *cond,
131
+ __inline static int usbi_cond_intwait(usbi_cond_t *cond,
133
132
  usbi_mutex_t *mutex,
134
133
  DWORD timeout_ms) {
135
134
  struct usbi_cond_perthread *pos;
@@ -182,9 +181,11 @@ int usbi_cond_timedwait(usbi_cond_t *cond,
182
181
  struct timeval targ_time, cur_time, delta_time;
183
182
  struct timespec cur_time_ns;
184
183
  DWORD millis;
185
- extern const uint64_t epoch_time;
186
184
 
187
- GetSystemTimeAsFileTime(&filetime);
185
+ // GetSystemTimeAsFileTime() is not available on CE
186
+ SYSTEMTIME st;
187
+ GetSystemTime(&st);
188
+ SystemTimeToFileTime(&st, &filetime);
188
189
  rtime.LowPart = filetime.dwLowDateTime;
189
190
  rtime.HighPart = filetime.dwHighDateTime;
190
191
  rtime.QuadPart -= epoch_time;
@@ -0,0 +1,1026 @@
1
+ /*
2
+ * Windows CE backend for libusbx 1.0
3
+ * Copyright © 2011-2013 RealVNC Ltd.
4
+ * Large portions taken from Windows backend, which is
5
+ * Copyright © 2009-2010 Pete Batard <pbatard@gmail.com>
6
+ * With contributions from Michael Plante, Orin Eman et al.
7
+ * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
8
+ * Major code testing contribution by Xiaofan Chen
9
+ *
10
+ * This library is free software; you can redistribute it and/or
11
+ * modify it under the terms of the GNU Lesser General Public
12
+ * License as published by the Free Software Foundation; either
13
+ * version 2.1 of the License, or (at your option) any later version.
14
+ *
15
+ * This library is distributed in the hope that it will be useful,
16
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
+ * Lesser General Public License for more details.
19
+ *
20
+ * You should have received a copy of the GNU Lesser General Public
21
+ * License along with this library; if not, write to the Free Software
22
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23
+ */
24
+
25
+ #include <libusbi.h>
26
+
27
+ #include <stdint.h>
28
+ #include <errno.h>
29
+ #include <inttypes.h>
30
+
31
+ #include "wince_usb.h"
32
+
33
+ // Forward declares
34
+ static int wince_clock_gettime(int clk_id, struct timespec *tp);
35
+ unsigned __stdcall wince_clock_gettime_threaded(void* param);
36
+
37
+ // Global variables
38
+ uint64_t hires_frequency, hires_ticks_to_ps;
39
+ int errno;
40
+ const uint64_t epoch_time = UINT64_C(116444736000000000); // 1970.01.01 00:00:000 in MS Filetime
41
+ enum windows_version windows_version = WINDOWS_CE;
42
+ static int concurrent_usage = -1;
43
+ // Timer thread
44
+ // NB: index 0 is for monotonic and 1 is for the thread exit event
45
+ HANDLE timer_thread = NULL;
46
+ HANDLE timer_mutex = NULL;
47
+ struct timespec timer_tp;
48
+ volatile LONG request_count[2] = {0, 1}; // last one must be > 0
49
+ HANDLE timer_request[2] = { NULL, NULL };
50
+ HANDLE timer_response = NULL;
51
+ HANDLE driver_handle = INVALID_HANDLE_VALUE;
52
+
53
+ /*
54
+ * Converts a windows error to human readable string
55
+ * uses retval as errorcode, or, if 0, use GetLastError()
56
+ */
57
+ #if defined(ENABLE_LOGGING)
58
+ static char* windows_error_str(uint32_t retval)
59
+ {
60
+ static TCHAR wErr_string[ERR_BUFFER_SIZE];
61
+ static char err_string[ERR_BUFFER_SIZE];
62
+
63
+ DWORD size;
64
+ size_t i;
65
+ uint32_t error_code, format_error;
66
+
67
+ error_code = retval?retval:GetLastError();
68
+
69
+ safe_stprintf(wErr_string, ERR_BUFFER_SIZE, _T("[%d] "), error_code);
70
+
71
+ size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code,
72
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &wErr_string[safe_tcslen(wErr_string)],
73
+ ERR_BUFFER_SIZE - (DWORD)safe_tcslen(wErr_string), NULL);
74
+ if (size == 0) {
75
+ format_error = GetLastError();
76
+ if (format_error)
77
+ safe_stprintf(wErr_string, ERR_BUFFER_SIZE,
78
+ _T("Windows error code %u (FormatMessage error code %u)"), error_code, format_error);
79
+ else
80
+ safe_stprintf(wErr_string, ERR_BUFFER_SIZE, _T("Unknown error code %u"), error_code);
81
+ } else {
82
+ // Remove CR/LF terminators
83
+ for (i=safe_tcslen(wErr_string)-1; ((wErr_string[i]==0x0A) || (wErr_string[i]==0x0D)); i--) {
84
+ wErr_string[i] = 0;
85
+ }
86
+ }
87
+ if (WideCharToMultiByte(CP_ACP, 0, wErr_string, -1, err_string, ERR_BUFFER_SIZE, NULL, NULL) < 0)
88
+ {
89
+ strcpy(err_string, "Unable to convert error string");
90
+ }
91
+ return err_string;
92
+ }
93
+ #endif
94
+
95
+ static struct wince_device_priv *_device_priv(struct libusb_device *dev)
96
+ {
97
+ return (struct wince_device_priv *) dev->os_priv;
98
+ }
99
+
100
+ // ceusbkwrapper to libusb error code mapping
101
+ static int translate_driver_error(int error)
102
+ {
103
+ switch (error) {
104
+ case ERROR_INVALID_PARAMETER:
105
+ return LIBUSB_ERROR_INVALID_PARAM;
106
+ case ERROR_CALL_NOT_IMPLEMENTED:
107
+ case ERROR_NOT_SUPPORTED:
108
+ return LIBUSB_ERROR_NOT_SUPPORTED;
109
+ case ERROR_NOT_ENOUGH_MEMORY:
110
+ return LIBUSB_ERROR_NO_MEM;
111
+ case ERROR_INVALID_HANDLE:
112
+ return LIBUSB_ERROR_NO_DEVICE;
113
+ case ERROR_BUSY:
114
+ return LIBUSB_ERROR_BUSY;
115
+
116
+ // Error codes that are either unexpected, or have
117
+ // no suitable LIBUSB_ERROR equivilant.
118
+ case ERROR_CANCELLED:
119
+ case ERROR_INTERNAL_ERROR:
120
+ default:
121
+ return LIBUSB_ERROR_OTHER;
122
+ }
123
+ }
124
+
125
+ static int init_dllimports()
126
+ {
127
+ DLL_LOAD(ceusbkwrapper.dll, UkwOpenDriver, TRUE);
128
+ DLL_LOAD(ceusbkwrapper.dll, UkwGetDeviceList, TRUE);
129
+ DLL_LOAD(ceusbkwrapper.dll, UkwReleaseDeviceList, TRUE);
130
+ DLL_LOAD(ceusbkwrapper.dll, UkwGetDeviceAddress, TRUE);
131
+ DLL_LOAD(ceusbkwrapper.dll, UkwGetDeviceDescriptor, TRUE);
132
+ DLL_LOAD(ceusbkwrapper.dll, UkwGetConfigDescriptor, TRUE);
133
+ DLL_LOAD(ceusbkwrapper.dll, UkwCloseDriver, TRUE);
134
+ DLL_LOAD(ceusbkwrapper.dll, UkwCancelTransfer, TRUE);
135
+ DLL_LOAD(ceusbkwrapper.dll, UkwIssueControlTransfer, TRUE);
136
+ DLL_LOAD(ceusbkwrapper.dll, UkwClaimInterface, TRUE);
137
+ DLL_LOAD(ceusbkwrapper.dll, UkwReleaseInterface, TRUE);
138
+ DLL_LOAD(ceusbkwrapper.dll, UkwSetInterfaceAlternateSetting, TRUE);
139
+ DLL_LOAD(ceusbkwrapper.dll, UkwClearHaltHost, TRUE);
140
+ DLL_LOAD(ceusbkwrapper.dll, UkwClearHaltDevice, TRUE);
141
+ DLL_LOAD(ceusbkwrapper.dll, UkwGetConfig, TRUE);
142
+ DLL_LOAD(ceusbkwrapper.dll, UkwSetConfig, TRUE);
143
+ DLL_LOAD(ceusbkwrapper.dll, UkwResetDevice, TRUE);
144
+ DLL_LOAD(ceusbkwrapper.dll, UkwKernelDriverActive, TRUE);
145
+ DLL_LOAD(ceusbkwrapper.dll, UkwAttachKernelDriver, TRUE);
146
+ DLL_LOAD(ceusbkwrapper.dll, UkwDetachKernelDriver, TRUE);
147
+ DLL_LOAD(ceusbkwrapper.dll, UkwIssueBulkTransfer, TRUE);
148
+ DLL_LOAD(ceusbkwrapper.dll, UkwIsPipeHalted, TRUE);
149
+ return LIBUSB_SUCCESS;
150
+ }
151
+
152
+ static int init_device(struct libusb_device *dev, UKW_DEVICE drv_dev,
153
+ unsigned char bus_addr, unsigned char dev_addr)
154
+ {
155
+ struct wince_device_priv *priv = _device_priv(dev);
156
+ int r = LIBUSB_SUCCESS;
157
+
158
+ dev->bus_number = bus_addr;
159
+ dev->device_address = dev_addr;
160
+ priv->dev = drv_dev;
161
+
162
+ if (!UkwGetDeviceDescriptor(priv->dev, &(priv->desc))) {
163
+ r = translate_driver_error(GetLastError());
164
+ }
165
+ return r;
166
+ }
167
+
168
+ // Internal API functions
169
+ static int wince_init(struct libusb_context *ctx)
170
+ {
171
+ int i, r = LIBUSB_ERROR_OTHER;
172
+ HANDLE semaphore;
173
+ TCHAR sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID)
174
+
175
+ _stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)GetCurrentProcessId()&0xFFFFFFFF);
176
+ semaphore = CreateSemaphore(NULL, 1, 1, sem_name);
177
+ if (semaphore == NULL) {
178
+ usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0));
179
+ return LIBUSB_ERROR_NO_MEM;
180
+ }
181
+
182
+ // A successful wait brings our semaphore count to 0 (unsignaled)
183
+ // => any concurent wait stalls until the semaphore's release
184
+ if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
185
+ usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0));
186
+ CloseHandle(semaphore);
187
+ return LIBUSB_ERROR_NO_MEM;
188
+ }
189
+
190
+ // NB: concurrent usage supposes that init calls are equally balanced with
191
+ // exit calls. If init is called more than exit, we will not exit properly
192
+ if ( ++concurrent_usage == 0 ) { // First init?
193
+ // Initialize pollable file descriptors
194
+ init_polling();
195
+
196
+ // Load DLL imports
197
+ if (init_dllimports() != LIBUSB_SUCCESS) {
198
+ usbi_err(ctx, "could not resolve DLL functions");
199
+ r = LIBUSB_ERROR_NOT_SUPPORTED;
200
+ goto init_exit;
201
+ }
202
+
203
+ // try to open a handle to the driver
204
+ driver_handle = UkwOpenDriver();
205
+ if (driver_handle == INVALID_HANDLE_VALUE) {
206
+ usbi_err(ctx, "could not connect to driver");
207
+ r = LIBUSB_ERROR_NOT_SUPPORTED;
208
+ goto init_exit;
209
+ }
210
+
211
+ // Windows CE doesn't have a way of specifying thread affinity, so this code
212
+ // just has to hope QueryPerformanceCounter doesn't report different values when
213
+ // running on different cores.
214
+ r = LIBUSB_ERROR_NO_MEM;
215
+ for (i = 0; i < 2; i++) {
216
+ timer_request[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
217
+ if (timer_request[i] == NULL) {
218
+ usbi_err(ctx, "could not create timer request event %d - aborting", i);
219
+ goto init_exit;
220
+ }
221
+ }
222
+ timer_response = CreateSemaphore(NULL, 0, MAX_TIMER_SEMAPHORES, NULL);
223
+ if (timer_response == NULL) {
224
+ usbi_err(ctx, "could not create timer response semaphore - aborting");
225
+ goto init_exit;
226
+ }
227
+ timer_mutex = CreateMutex(NULL, FALSE, NULL);
228
+ if (timer_mutex == NULL) {
229
+ usbi_err(ctx, "could not create timer mutex - aborting");
230
+ goto init_exit;
231
+ }
232
+ timer_thread = CreateThread(NULL, 0, wince_clock_gettime_threaded, NULL, 0, NULL);
233
+ if (timer_thread == NULL) {
234
+ usbi_err(ctx, "Unable to create timer thread - aborting");
235
+ goto init_exit;
236
+ }
237
+
238
+ // Wait for timer thread to init before continuing.
239
+ if (WaitForSingleObject(timer_response, INFINITE) != WAIT_OBJECT_0) {
240
+ usbi_err(ctx, "Failed to wait for timer thread to become ready - aborting");
241
+ goto init_exit;
242
+ }
243
+ }
244
+ // At this stage, either we went through full init successfully, or didn't need to
245
+ r = LIBUSB_SUCCESS;
246
+
247
+ init_exit: // Holds semaphore here.
248
+ if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed?
249
+ if (driver_handle != INVALID_HANDLE_VALUE) {
250
+ UkwCloseDriver(driver_handle);
251
+ driver_handle = INVALID_HANDLE_VALUE;
252
+ }
253
+ if (timer_thread) {
254
+ SetEvent(timer_request[1]); // actually the signal to quit the thread.
255
+ if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) {
256
+ usbi_warn(ctx, "could not wait for timer thread to quit");
257
+ TerminateThread(timer_thread, 1); // shouldn't happen, but we're destroying
258
+ // all objects it might have held anyway.
259
+ }
260
+ CloseHandle(timer_thread);
261
+ timer_thread = NULL;
262
+ }
263
+ for (i = 0; i < 2; i++) {
264
+ if (timer_request[i]) {
265
+ CloseHandle(timer_request[i]);
266
+ timer_request[i] = NULL;
267
+ }
268
+ }
269
+ if (timer_response) {
270
+ CloseHandle(timer_response);
271
+ timer_response = NULL;
272
+ }
273
+ if (timer_mutex) {
274
+ CloseHandle(timer_mutex);
275
+ timer_mutex = NULL;
276
+ }
277
+ }
278
+
279
+ if (r != LIBUSB_SUCCESS)
280
+ --concurrent_usage; // Not expected to call libusb_exit if we failed.
281
+
282
+ ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
283
+ CloseHandle(semaphore);
284
+ return r;
285
+ }
286
+
287
+ static void wince_exit(void)
288
+ {
289
+ int i;
290
+ HANDLE semaphore;
291
+ TCHAR sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID)
292
+
293
+ _stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)GetCurrentProcessId()&0xFFFFFFFF);
294
+ semaphore = CreateSemaphore(NULL, 1, 1, sem_name);
295
+ if (semaphore == NULL) {
296
+ return;
297
+ }
298
+
299
+ // A successful wait brings our semaphore count to 0 (unsignaled)
300
+ // => any concurent wait stalls until the semaphore release
301
+ if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
302
+ CloseHandle(semaphore);
303
+ return;
304
+ }
305
+
306
+ // Only works if exits and inits are balanced exactly
307
+ if (--concurrent_usage < 0) { // Last exit
308
+ exit_polling();
309
+
310
+ if (timer_thread) {
311
+ SetEvent(timer_request[1]); // actually the signal to quit the thread.
312
+ if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) {
313
+ usbi_dbg("could not wait for timer thread to quit");
314
+ TerminateThread(timer_thread, 1);
315
+ }
316
+ CloseHandle(timer_thread);
317
+ timer_thread = NULL;
318
+ }
319
+ for (i = 0; i < 2; i++) {
320
+ if (timer_request[i]) {
321
+ CloseHandle(timer_request[i]);
322
+ timer_request[i] = NULL;
323
+ }
324
+ }
325
+ if (timer_response) {
326
+ CloseHandle(timer_response);
327
+ timer_response = NULL;
328
+ }
329
+ if (timer_mutex) {
330
+ CloseHandle(timer_mutex);
331
+ timer_mutex = NULL;
332
+ }
333
+ if (driver_handle != INVALID_HANDLE_VALUE) {
334
+ UkwCloseDriver(driver_handle);
335
+ driver_handle = INVALID_HANDLE_VALUE;
336
+ }
337
+ }
338
+
339
+ ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
340
+ CloseHandle(semaphore);
341
+ }
342
+
343
+ static int wince_get_device_list(
344
+ struct libusb_context *ctx,
345
+ struct discovered_devs **discdevs)
346
+ {
347
+ UKW_DEVICE devices[MAX_DEVICE_COUNT];
348
+ struct discovered_devs * new_devices = *discdevs;
349
+ DWORD count = 0, i;
350
+ struct libusb_device *dev = NULL;
351
+ unsigned char bus_addr, dev_addr;
352
+ unsigned long session_id;
353
+ BOOL success;
354
+ DWORD release_list_offset = 0;
355
+ int r = LIBUSB_SUCCESS;
356
+
357
+ success = UkwGetDeviceList(driver_handle, devices, MAX_DEVICE_COUNT, &count);
358
+ if (!success) {
359
+ int libusbErr = translate_driver_error(GetLastError());
360
+ usbi_err(ctx, "could not get devices: %s", windows_error_str(0));
361
+ return libusbErr;
362
+ }
363
+ for(i = 0; i < count; ++i) {
364
+ release_list_offset = i;
365
+ success = UkwGetDeviceAddress(devices[i], &bus_addr, &dev_addr, &session_id);
366
+ if (!success) {
367
+ r = translate_driver_error(GetLastError());
368
+ usbi_err(ctx, "could not get device address for %d: %s", i, windows_error_str(0));
369
+ goto err_out;
370
+ }
371
+ dev = usbi_get_device_by_session_id(ctx, session_id);
372
+ if (dev) {
373
+ usbi_dbg("using existing device for %d/%d (session %ld)",
374
+ bus_addr, dev_addr, session_id);
375
+ libusb_ref_device(dev);
376
+ // Release just this element in the device list (as we already hold a
377
+ // reference to it).
378
+ UkwReleaseDeviceList(driver_handle, &devices[i], 1);
379
+ release_list_offset++;
380
+ } else {
381
+ usbi_dbg("allocating new device for %d/%d (session %ld)",
382
+ bus_addr, dev_addr, session_id);
383
+ dev = usbi_alloc_device(ctx, session_id);
384
+ if (!dev) {
385
+ r = LIBUSB_ERROR_NO_MEM;
386
+ goto err_out;
387
+ }
388
+ r = init_device(dev, devices[i], bus_addr, dev_addr);
389
+ if (r < 0)
390
+ goto err_out;
391
+ r = usbi_sanitize_device(dev);
392
+ if (r < 0)
393
+ goto err_out;
394
+ }
395
+ new_devices = discovered_devs_append(new_devices, dev);
396
+ if (!discdevs) {
397
+ r = LIBUSB_ERROR_NO_MEM;
398
+ goto err_out;
399
+ }
400
+ safe_unref_device(dev);
401
+ }
402
+ *discdevs = new_devices;
403
+ return r;
404
+ err_out:
405
+ *discdevs = new_devices;
406
+ safe_unref_device(dev);
407
+ // Release the remainder of the unprocessed device list.
408
+ // The devices added to new_devices already will still be passed up to libusb,
409
+ // which can dispose of them at its leisure.
410
+ UkwReleaseDeviceList(driver_handle, &devices[release_list_offset], count - release_list_offset);
411
+ return r;
412
+ }
413
+
414
+ static int wince_open(struct libusb_device_handle *handle)
415
+ {
416
+ // Nothing to do to open devices as a handle to it has
417
+ // been retrieved by wince_get_device_list
418
+ return LIBUSB_SUCCESS;
419
+ }
420
+
421
+ static void wince_close(struct libusb_device_handle *handle)
422
+ {
423
+ // Nothing to do as wince_open does nothing.
424
+ }
425
+
426
+ static int wince_get_device_descriptor(
427
+ struct libusb_device *device,
428
+ unsigned char *buffer, int *host_endian)
429
+ {
430
+ struct wince_device_priv *priv = _device_priv(device);
431
+
432
+ *host_endian = 1;
433
+ memcpy(buffer, &priv->desc, DEVICE_DESC_LENGTH);
434
+ return LIBUSB_SUCCESS;
435
+ }
436
+
437
+ static int wince_get_active_config_descriptor(
438
+ struct libusb_device *device,
439
+ unsigned char *buffer, size_t len, int *host_endian)
440
+ {
441
+ struct wince_device_priv *priv = _device_priv(device);
442
+ DWORD actualSize = len;
443
+ *host_endian = 0;
444
+ if (!UkwGetConfigDescriptor(priv->dev, UKW_ACTIVE_CONFIGURATION, buffer, len, &actualSize)) {
445
+ return translate_driver_error(GetLastError());
446
+ }
447
+ return actualSize;
448
+ }
449
+
450
+ static int wince_get_config_descriptor(
451
+ struct libusb_device *device,
452
+ uint8_t config_index,
453
+ unsigned char *buffer, size_t len, int *host_endian)
454
+ {
455
+ struct wince_device_priv *priv = _device_priv(device);
456
+ DWORD actualSize = len;
457
+ *host_endian = 0;
458
+ if (!UkwGetConfigDescriptor(priv->dev, config_index, buffer, len, &actualSize)) {
459
+ return translate_driver_error(GetLastError());
460
+ }
461
+ return actualSize;
462
+ }
463
+
464
+ static int wince_get_configuration(
465
+ struct libusb_device_handle *handle,
466
+ int *config)
467
+ {
468
+ struct wince_device_priv *priv = _device_priv(handle->dev);
469
+ UCHAR cv = 0;
470
+ if (!UkwGetConfig(priv->dev, &cv)) {
471
+ return translate_driver_error(GetLastError());
472
+ }
473
+ (*config) = cv;
474
+ return LIBUSB_SUCCESS;
475
+ }
476
+
477
+ static int wince_set_configuration(
478
+ struct libusb_device_handle *handle,
479
+ int config)
480
+ {
481
+ struct wince_device_priv *priv = _device_priv(handle->dev);
482
+ // Setting configuration 0 places the device in Address state.
483
+ // This should correspond to the "unconfigured state" required by
484
+ // libusb when the specified configuration is -1.
485
+ UCHAR cv = (config < 0) ? 0 : config;
486
+ if (!UkwSetConfig(priv->dev, cv)) {
487
+ return translate_driver_error(GetLastError());
488
+ }
489
+ return LIBUSB_SUCCESS;
490
+ }
491
+
492
+ static int wince_claim_interface(
493
+ struct libusb_device_handle *handle,
494
+ int interface_number)
495
+ {
496
+ struct wince_device_priv *priv = _device_priv(handle->dev);
497
+ if (!UkwClaimInterface(priv->dev, interface_number)) {
498
+ return translate_driver_error(GetLastError());
499
+ }
500
+ return LIBUSB_SUCCESS;
501
+ }
502
+
503
+ static int wince_release_interface(
504
+ struct libusb_device_handle *handle,
505
+ int interface_number)
506
+ {
507
+ struct wince_device_priv *priv = _device_priv(handle->dev);
508
+ if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, 0)) {
509
+ return translate_driver_error(GetLastError());
510
+ }
511
+ if (!UkwReleaseInterface(priv->dev, interface_number)) {
512
+ return translate_driver_error(GetLastError());
513
+ }
514
+ return LIBUSB_SUCCESS;
515
+ }
516
+
517
+ static int wince_set_interface_altsetting(
518
+ struct libusb_device_handle *handle,
519
+ int interface_number, int altsetting)
520
+ {
521
+ struct wince_device_priv *priv = _device_priv(handle->dev);
522
+ if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, altsetting)) {
523
+ return translate_driver_error(GetLastError());
524
+ }
525
+ return LIBUSB_SUCCESS;
526
+ }
527
+
528
+ static int wince_clear_halt(
529
+ struct libusb_device_handle *handle,
530
+ unsigned char endpoint)
531
+ {
532
+ struct wince_device_priv *priv = _device_priv(handle->dev);
533
+ if (!UkwClearHaltHost(priv->dev, endpoint)) {
534
+ return translate_driver_error(GetLastError());
535
+ }
536
+ if (!UkwClearHaltDevice(priv->dev, endpoint)) {
537
+ return translate_driver_error(GetLastError());
538
+ }
539
+ return LIBUSB_SUCCESS;
540
+ }
541
+
542
+ static int wince_reset_device(
543
+ struct libusb_device_handle *handle)
544
+ {
545
+ struct wince_device_priv *priv = _device_priv(handle->dev);
546
+ if (!UkwResetDevice(priv->dev)) {
547
+ return translate_driver_error(GetLastError());
548
+ }
549
+ return LIBUSB_SUCCESS;
550
+ }
551
+
552
+ static int wince_kernel_driver_active(
553
+ struct libusb_device_handle *handle,
554
+ int interface_number)
555
+ {
556
+ struct wince_device_priv *priv = _device_priv(handle->dev);
557
+ BOOL result = FALSE;
558
+ if (!UkwKernelDriverActive(priv->dev, interface_number, &result)) {
559
+ return translate_driver_error(GetLastError());
560
+ }
561
+ return result ? 1 : 0;
562
+ }
563
+
564
+ static int wince_detach_kernel_driver(
565
+ struct libusb_device_handle *handle,
566
+ int interface_number)
567
+ {
568
+ struct wince_device_priv *priv = _device_priv(handle->dev);
569
+ if (!UkwDetachKernelDriver(priv->dev, interface_number)) {
570
+ return translate_driver_error(GetLastError());
571
+ }
572
+ return LIBUSB_SUCCESS;
573
+ }
574
+
575
+ static int wince_attach_kernel_driver(
576
+ struct libusb_device_handle *handle,
577
+ int interface_number)
578
+ {
579
+ struct wince_device_priv *priv = _device_priv(handle->dev);
580
+ if (!UkwAttachKernelDriver(priv->dev, interface_number)) {
581
+ return translate_driver_error(GetLastError());
582
+ }
583
+ return LIBUSB_SUCCESS;
584
+ }
585
+
586
+ static void wince_destroy_device(
587
+ struct libusb_device *dev)
588
+ {
589
+ struct wince_device_priv *priv = _device_priv(dev);
590
+ UkwReleaseDeviceList(driver_handle, &priv->dev, 1);
591
+ }
592
+
593
+ static void wince_clear_transfer_priv(
594
+ struct usbi_transfer *itransfer)
595
+ {
596
+ struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
597
+ struct winfd wfd = fd_to_winfd(transfer_priv->pollable_fd.fd);
598
+ // No need to cancel transfer as it is either complete or abandoned
599
+ wfd.itransfer = NULL;
600
+ CloseHandle(wfd.handle);
601
+ usbi_free_fd(&transfer_priv->pollable_fd);
602
+ }
603
+
604
+ static int wince_cancel_transfer(
605
+ struct usbi_transfer *itransfer)
606
+ {
607
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
608
+ struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
609
+ struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
610
+
611
+ if (!UkwCancelTransfer(priv->dev, transfer_priv->pollable_fd.overlapped, UKW_TF_NO_WAIT)) {
612
+ return translate_driver_error(GetLastError());
613
+ }
614
+ return LIBUSB_SUCCESS;
615
+ }
616
+
617
+ static int wince_submit_control_or_bulk_transfer(struct usbi_transfer *itransfer)
618
+ {
619
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
620
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
621
+ struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
622
+ struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
623
+ BOOL direction_in, ret;
624
+ struct winfd wfd;
625
+ DWORD flags;
626
+ HANDLE eventHandle;
627
+ PUKW_CONTROL_HEADER setup = NULL;
628
+ const BOOL control_transfer = transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL;
629
+
630
+ transfer_priv->pollable_fd = INVALID_WINFD;
631
+ if (control_transfer) {
632
+ setup = (PUKW_CONTROL_HEADER) transfer->buffer;
633
+ direction_in = setup->bmRequestType & LIBUSB_ENDPOINT_IN;
634
+ } else {
635
+ direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN;
636
+ }
637
+ flags = direction_in ? UKW_TF_IN_TRANSFER : UKW_TF_OUT_TRANSFER;
638
+ flags |= UKW_TF_SHORT_TRANSFER_OK;
639
+
640
+ eventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
641
+ if (eventHandle == NULL) {
642
+ usbi_err(ctx, "Failed to create event for async transfer");
643
+ return LIBUSB_ERROR_NO_MEM;
644
+ }
645
+
646
+ wfd = usbi_create_fd(eventHandle, direction_in ? RW_READ : RW_WRITE, itransfer, &wince_cancel_transfer);
647
+ if (wfd.fd < 0) {
648
+ CloseHandle(eventHandle);
649
+ return LIBUSB_ERROR_NO_MEM;
650
+ }
651
+
652
+ transfer_priv->pollable_fd = wfd;
653
+ if (control_transfer) {
654
+ // Split out control setup header and data buffer
655
+ DWORD bufLen = transfer->length - sizeof(UKW_CONTROL_HEADER);
656
+ PVOID buf = (PVOID) &transfer->buffer[sizeof(UKW_CONTROL_HEADER)];
657
+
658
+ ret = UkwIssueControlTransfer(priv->dev, flags, setup, buf, bufLen, &transfer->actual_length, wfd.overlapped);
659
+ } else {
660
+ ret = UkwIssueBulkTransfer(priv->dev, flags, transfer->endpoint, transfer->buffer,
661
+ transfer->length, &transfer->actual_length, wfd.overlapped);
662
+ }
663
+ if (!ret) {
664
+ int libusbErr = translate_driver_error(GetLastError());
665
+ usbi_err(ctx, "UkwIssue%sTransfer failed: error %d",
666
+ control_transfer ? "Control" : "Bulk", GetLastError());
667
+ wince_clear_transfer_priv(itransfer);
668
+ return libusbErr;
669
+ }
670
+ usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, direction_in ? POLLIN : POLLOUT);
671
+ itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
672
+
673
+ return LIBUSB_SUCCESS;
674
+ }
675
+
676
+ static int wince_submit_iso_transfer(struct usbi_transfer *itransfer)
677
+ {
678
+ return LIBUSB_ERROR_NOT_SUPPORTED;
679
+ }
680
+
681
+ static int wince_submit_transfer(
682
+ struct usbi_transfer *itransfer)
683
+ {
684
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
685
+
686
+ switch (transfer->type) {
687
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
688
+ case LIBUSB_TRANSFER_TYPE_BULK:
689
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
690
+ return wince_submit_control_or_bulk_transfer(itransfer);
691
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
692
+ return wince_submit_iso_transfer(itransfer);
693
+ default:
694
+ usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
695
+ return LIBUSB_ERROR_INVALID_PARAM;
696
+ }
697
+ }
698
+
699
+ static void wince_transfer_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
700
+ {
701
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
702
+ struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
703
+ struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
704
+ int status;
705
+
706
+ usbi_dbg("handling I/O completion with errcode %d", io_result);
707
+
708
+ if (io_result == ERROR_NOT_SUPPORTED &&
709
+ transfer->type != LIBUSB_TRANSFER_TYPE_CONTROL) {
710
+ /* For functional stalls, the WinCE USB layer (and therefore the USB Kernel Wrapper
711
+ * Driver) will report USB_ERROR_STALL/ERROR_NOT_SUPPORTED in situations where the
712
+ * endpoint isn't actually stalled.
713
+ *
714
+ * One example of this is that some devices will occasionally fail to reply to an IN
715
+ * token. The WinCE USB layer carries on with the transaction until it is completed
716
+ * (or cancelled) but then completes it with USB_ERROR_STALL.
717
+ *
718
+ * This code therefore needs to confirm that there really is a stall error, by both
719
+ * checking the pipe status and requesting the endpoint status from the device.
720
+ */
721
+ BOOL halted = FALSE;
722
+ usbi_dbg("checking I/O completion with errcode ERROR_NOT_SUPPORTED is really a stall");
723
+ if (UkwIsPipeHalted(priv->dev, transfer->endpoint, &halted)) {
724
+ /* Pipe status retrieved, so now request endpoint status by sending a GET_STATUS
725
+ * control request to the device. This is done synchronously, which is a bit
726
+ * naughty, but this is a special corner case.
727
+ */
728
+ WORD wStatus = 0;
729
+ DWORD written = 0;
730
+ UKW_CONTROL_HEADER ctrlHeader;
731
+ ctrlHeader.bmRequestType = LIBUSB_REQUEST_TYPE_STANDARD |
732
+ LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_ENDPOINT;
733
+ ctrlHeader.bRequest = LIBUSB_REQUEST_GET_STATUS;
734
+ ctrlHeader.wValue = 0;
735
+ ctrlHeader.wIndex = transfer->endpoint;
736
+ ctrlHeader.wLength = sizeof(wStatus);
737
+ if (UkwIssueControlTransfer(priv->dev,
738
+ UKW_TF_IN_TRANSFER | UKW_TF_SEND_TO_ENDPOINT,
739
+ &ctrlHeader, &wStatus, sizeof(wStatus), &written, NULL)) {
740
+ if (written == sizeof(wStatus) &&
741
+ (wStatus & STATUS_HALT_FLAG) == 0) {
742
+ if (!halted || UkwClearHaltHost(priv->dev, transfer->endpoint)) {
743
+ usbi_dbg("Endpoint doesn't appear to be stalled, overriding error with success");
744
+ io_result = ERROR_SUCCESS;
745
+ } else {
746
+ usbi_dbg("Endpoint doesn't appear to be stalled, but the host is halted, changing error");
747
+ io_result = ERROR_IO_DEVICE;
748
+ }
749
+ }
750
+ }
751
+ }
752
+ }
753
+
754
+ switch(io_result) {
755
+ case ERROR_SUCCESS:
756
+ itransfer->transferred += io_size;
757
+ status = LIBUSB_TRANSFER_COMPLETED;
758
+ break;
759
+ case ERROR_CANCELLED:
760
+ usbi_dbg("detected transfer cancel");
761
+ status = LIBUSB_TRANSFER_CANCELLED;
762
+ break;
763
+ case ERROR_NOT_SUPPORTED:
764
+ case ERROR_GEN_FAILURE:
765
+ usbi_dbg("detected endpoint stall");
766
+ status = LIBUSB_TRANSFER_STALL;
767
+ break;
768
+ case ERROR_SEM_TIMEOUT:
769
+ usbi_dbg("detected semaphore timeout");
770
+ status = LIBUSB_TRANSFER_TIMED_OUT;
771
+ break;
772
+ case ERROR_OPERATION_ABORTED:
773
+ if (itransfer->flags & USBI_TRANSFER_TIMED_OUT) {
774
+ usbi_dbg("detected timeout");
775
+ status = LIBUSB_TRANSFER_TIMED_OUT;
776
+ } else {
777
+ usbi_dbg("detected operation aborted");
778
+ status = LIBUSB_TRANSFER_CANCELLED;
779
+ }
780
+ break;
781
+ default:
782
+ usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error: %s", windows_error_str(io_result));
783
+ status = LIBUSB_TRANSFER_ERROR;
784
+ break;
785
+ }
786
+ wince_clear_transfer_priv(itransfer);
787
+ if (status == LIBUSB_TRANSFER_CANCELLED) {
788
+ usbi_handle_transfer_cancellation(itransfer);
789
+ } else {
790
+ usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status);
791
+ }
792
+ }
793
+
794
+ static void wince_handle_callback (struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
795
+ {
796
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
797
+
798
+ switch (transfer->type) {
799
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
800
+ case LIBUSB_TRANSFER_TYPE_BULK:
801
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
802
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
803
+ wince_transfer_callback (itransfer, io_result, io_size);
804
+ break;
805
+ default:
806
+ usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
807
+ }
808
+ }
809
+
810
+ static int wince_handle_events(
811
+ struct libusb_context *ctx,
812
+ struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready)
813
+ {
814
+ struct wince_transfer_priv* transfer_priv = NULL;
815
+ POLL_NFDS_TYPE i = 0;
816
+ BOOL found = FALSE;
817
+ struct usbi_transfer *transfer;
818
+ DWORD io_size, io_result;
819
+
820
+ usbi_mutex_lock(&ctx->open_devs_lock);
821
+ for (i = 0; i < nfds && num_ready > 0; i++) {
822
+
823
+ usbi_dbg("checking fd %d with revents = %04x", fds[i].fd, fds[i].revents);
824
+
825
+ if (!fds[i].revents) {
826
+ continue;
827
+ }
828
+
829
+ num_ready--;
830
+
831
+ // Because a Windows OVERLAPPED is used for poll emulation,
832
+ // a pollable fd is created and stored with each transfer
833
+ usbi_mutex_lock(&ctx->flying_transfers_lock);
834
+ list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
835
+ transfer_priv = usbi_transfer_get_os_priv(transfer);
836
+ if (transfer_priv->pollable_fd.fd == fds[i].fd) {
837
+ found = TRUE;
838
+ break;
839
+ }
840
+ }
841
+ usbi_mutex_unlock(&ctx->flying_transfers_lock);
842
+
843
+ if (found && HasOverlappedIoCompleted(transfer_priv->pollable_fd.overlapped)) {
844
+ io_result = (DWORD)transfer_priv->pollable_fd.overlapped->Internal;
845
+ io_size = (DWORD)transfer_priv->pollable_fd.overlapped->InternalHigh;
846
+ usbi_remove_pollfd(ctx, transfer_priv->pollable_fd.fd);
847
+ // let handle_callback free the event using the transfer wfd
848
+ // If you don't use the transfer wfd, you run a risk of trying to free a
849
+ // newly allocated wfd that took the place of the one from the transfer.
850
+ wince_handle_callback(transfer, io_result, io_size);
851
+ } else if (found) {
852
+ usbi_err(ctx, "matching transfer for fd %x has not completed", fds[i]);
853
+ return LIBUSB_ERROR_OTHER;
854
+ } else {
855
+ usbi_err(ctx, "could not find a matching transfer for fd %x", fds[i]);
856
+ return LIBUSB_ERROR_NOT_FOUND;
857
+ }
858
+ }
859
+
860
+ usbi_mutex_unlock(&ctx->open_devs_lock);
861
+ return LIBUSB_SUCCESS;
862
+ }
863
+
864
+ /*
865
+ * Monotonic and real time functions
866
+ */
867
+ unsigned __stdcall wince_clock_gettime_threaded(void* param)
868
+ {
869
+ LARGE_INTEGER hires_counter, li_frequency;
870
+ LONG nb_responses;
871
+ int timer_index;
872
+
873
+ // Init - find out if we have access to a monotonic (hires) timer
874
+ if (!QueryPerformanceFrequency(&li_frequency)) {
875
+ usbi_dbg("no hires timer available on this platform");
876
+ hires_frequency = 0;
877
+ hires_ticks_to_ps = UINT64_C(0);
878
+ } else {
879
+ hires_frequency = li_frequency.QuadPart;
880
+ // The hires frequency can go as high as 4 GHz, so we'll use a conversion
881
+ // to picoseconds to compute the tv_nsecs part in clock_gettime
882
+ hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency;
883
+ usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency);
884
+ }
885
+
886
+ // Signal wince_init() that we're ready to service requests
887
+ if (ReleaseSemaphore(timer_response, 1, NULL) == 0) {
888
+ usbi_dbg("unable to release timer semaphore: %s", windows_error_str(0));
889
+ }
890
+
891
+ // Main loop - wait for requests
892
+ while (1) {
893
+ timer_index = WaitForMultipleObjects(2, timer_request, FALSE, INFINITE) - WAIT_OBJECT_0;
894
+ if ( (timer_index != 0) && (timer_index != 1) ) {
895
+ usbi_dbg("failure to wait on requests: %s", windows_error_str(0));
896
+ continue;
897
+ }
898
+ if (request_count[timer_index] == 0) {
899
+ // Request already handled
900
+ ResetEvent(timer_request[timer_index]);
901
+ // There's still a possiblity that a thread sends a request between the
902
+ // time we test request_count[] == 0 and we reset the event, in which case
903
+ // the request would be ignored. The simple solution to that is to test
904
+ // request_count again and process requests if non zero.
905
+ if (request_count[timer_index] == 0)
906
+ continue;
907
+ }
908
+ switch (timer_index) {
909
+ case 0:
910
+ WaitForSingleObject(timer_mutex, INFINITE);
911
+ // Requests to this thread are for hires always
912
+ if (QueryPerformanceCounter(&hires_counter) != 0) {
913
+ timer_tp.tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
914
+ timer_tp.tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency)/1000) * hires_ticks_to_ps);
915
+ } else {
916
+ // Fallback to real-time if we can't get monotonic value
917
+ // Note that real-time clock does not wait on the mutex or this thread.
918
+ wince_clock_gettime(USBI_CLOCK_REALTIME, &timer_tp);
919
+ }
920
+ ReleaseMutex(timer_mutex);
921
+
922
+ nb_responses = InterlockedExchange((LONG*)&request_count[0], 0);
923
+ if ( (nb_responses)
924
+ && (ReleaseSemaphore(timer_response, nb_responses, NULL) == 0) ) {
925
+ usbi_dbg("unable to release timer semaphore: %s", windows_error_str(0));
926
+ }
927
+ continue;
928
+ case 1: // time to quit
929
+ usbi_dbg("timer thread quitting");
930
+ return 0;
931
+ }
932
+ }
933
+ usbi_dbg("ERROR: broken timer thread");
934
+ return 1;
935
+ }
936
+
937
+ static int wince_clock_gettime(int clk_id, struct timespec *tp)
938
+ {
939
+ FILETIME filetime;
940
+ ULARGE_INTEGER rtime;
941
+ DWORD r;
942
+ SYSTEMTIME st;
943
+ switch(clk_id) {
944
+ case USBI_CLOCK_MONOTONIC:
945
+ if (hires_frequency != 0) {
946
+ while (1) {
947
+ InterlockedIncrement((LONG*)&request_count[0]);
948
+ SetEvent(timer_request[0]);
949
+ r = WaitForSingleObject(timer_response, TIMER_REQUEST_RETRY_MS);
950
+ switch(r) {
951
+ case WAIT_OBJECT_0:
952
+ WaitForSingleObject(timer_mutex, INFINITE);
953
+ *tp = timer_tp;
954
+ ReleaseMutex(timer_mutex);
955
+ return LIBUSB_SUCCESS;
956
+ case WAIT_TIMEOUT:
957
+ usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?");
958
+ break; // Retry until successful
959
+ default:
960
+ usbi_dbg("WaitForSingleObject failed: %s", windows_error_str(0));
961
+ return LIBUSB_ERROR_OTHER;
962
+ }
963
+ }
964
+ }
965
+ // Fall through and return real-time if monotonic was not detected @ timer init
966
+ case USBI_CLOCK_REALTIME:
967
+ // We follow http://msdn.microsoft.com/en-us/library/ms724928%28VS.85%29.aspx
968
+ // with a predef epoch_time to have an epoch that starts at 1970.01.01 00:00
969
+ // Note however that our resolution is bounded by the Windows system time
970
+ // functions and is at best of the order of 1 ms (or, usually, worse)
971
+ GetSystemTime(&st);
972
+ SystemTimeToFileTime(&st, &filetime);
973
+ rtime.LowPart = filetime.dwLowDateTime;
974
+ rtime.HighPart = filetime.dwHighDateTime;
975
+ rtime.QuadPart -= epoch_time;
976
+ tp->tv_sec = (long)(rtime.QuadPart / 10000000);
977
+ tp->tv_nsec = (long)((rtime.QuadPart % 10000000)*100);
978
+ return LIBUSB_SUCCESS;
979
+ default:
980
+ return LIBUSB_ERROR_INVALID_PARAM;
981
+ }
982
+ }
983
+
984
+ const struct usbi_os_backend wince_backend = {
985
+ "Windows CE",
986
+ 0,
987
+ wince_init,
988
+ wince_exit,
989
+
990
+ wince_get_device_list,
991
+ NULL, /* hotplug_poll */
992
+ wince_open,
993
+ wince_close,
994
+
995
+ wince_get_device_descriptor,
996
+ wince_get_active_config_descriptor,
997
+ wince_get_config_descriptor,
998
+ NULL, /* get_config_descriptor_by_value() */
999
+
1000
+ wince_get_configuration,
1001
+ wince_set_configuration,
1002
+ wince_claim_interface,
1003
+ wince_release_interface,
1004
+
1005
+ wince_set_interface_altsetting,
1006
+ wince_clear_halt,
1007
+ wince_reset_device,
1008
+
1009
+ wince_kernel_driver_active,
1010
+ wince_detach_kernel_driver,
1011
+ wince_attach_kernel_driver,
1012
+
1013
+ wince_destroy_device,
1014
+
1015
+ wince_submit_transfer,
1016
+ wince_cancel_transfer,
1017
+ wince_clear_transfer_priv,
1018
+
1019
+ wince_handle_events,
1020
+
1021
+ wince_clock_gettime,
1022
+ sizeof(struct wince_device_priv),
1023
+ sizeof(struct wince_device_handle_priv),
1024
+ sizeof(struct wince_transfer_priv),
1025
+ 0,
1026
+ };