libusb 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. data/.gitignore +8 -0
  2. data/.travis.yml +10 -0
  3. data/.yardopts +6 -1
  4. data/Gemfile +16 -0
  5. data/{History.txt → History.md} +28 -16
  6. data/README.md +144 -0
  7. data/Rakefile +28 -24
  8. data/ext/extconf.rb +33 -0
  9. data/ext/libusbx-1.0.14/AUTHORS +50 -0
  10. data/ext/libusbx-1.0.14/COPYING +504 -0
  11. data/ext/libusbx-1.0.14/ChangeLog +139 -0
  12. data/ext/libusbx-1.0.14/INSTALL +234 -0
  13. data/ext/libusbx-1.0.14/Makefile.am +23 -0
  14. data/ext/libusbx-1.0.14/Makefile.in +803 -0
  15. data/ext/libusbx-1.0.14/NEWS +2 -0
  16. data/ext/libusbx-1.0.14/PORTING +94 -0
  17. data/ext/libusbx-1.0.14/README +28 -0
  18. data/ext/libusbx-1.0.14/THANKS +7 -0
  19. data/ext/libusbx-1.0.14/TODO +2 -0
  20. data/ext/libusbx-1.0.14/aclocal.m4 +9480 -0
  21. data/ext/libusbx-1.0.14/compile +143 -0
  22. data/ext/libusbx-1.0.14/config.guess +1501 -0
  23. data/ext/libusbx-1.0.14/config.h.in +116 -0
  24. data/ext/libusbx-1.0.14/config.sub +1705 -0
  25. data/ext/libusbx-1.0.14/configure +14818 -0
  26. data/ext/libusbx-1.0.14/configure.ac +230 -0
  27. data/ext/libusbx-1.0.14/depcomp +630 -0
  28. data/ext/libusbx-1.0.14/doc/Makefile.am +9 -0
  29. data/ext/libusbx-1.0.14/doc/Makefile.in +380 -0
  30. data/ext/libusbx-1.0.14/doc/doxygen.cfg.in +1288 -0
  31. data/ext/libusbx-1.0.14/examples/Makefile.am +18 -0
  32. data/ext/libusbx-1.0.14/examples/Makefile.in +596 -0
  33. data/ext/libusbx-1.0.14/examples/dpfp.c +506 -0
  34. data/ext/libusbx-1.0.14/examples/dpfp_threaded.c +544 -0
  35. data/ext/libusbx-1.0.14/examples/ezusb.c +616 -0
  36. data/ext/libusbx-1.0.14/examples/ezusb.h +107 -0
  37. data/ext/libusbx-1.0.14/examples/fxload.c +261 -0
  38. data/ext/libusbx-1.0.14/examples/getopt/getopt.c +1060 -0
  39. data/ext/libusbx-1.0.14/examples/getopt/getopt.h +180 -0
  40. data/ext/libusbx-1.0.14/examples/getopt/getopt1.c +188 -0
  41. data/ext/libusbx-1.0.14/examples/listdevs.c +63 -0
  42. data/ext/libusbx-1.0.14/examples/xusb.c +1036 -0
  43. data/ext/libusbx-1.0.14/install-sh +520 -0
  44. data/ext/libusbx-1.0.14/libusb-1.0.pc.in +11 -0
  45. data/ext/libusbx-1.0.14/libusb/Makefile.am +56 -0
  46. data/ext/libusbx-1.0.14/libusb/Makefile.in +721 -0
  47. data/ext/libusbx-1.0.14/libusb/core.c +1951 -0
  48. data/ext/libusbx-1.0.14/libusb/descriptor.c +731 -0
  49. data/ext/libusbx-1.0.14/libusb/io.c +2450 -0
  50. data/ext/libusbx-1.0.14/libusb/libusb-1.0.def +126 -0
  51. data/ext/libusbx-1.0.14/libusb/libusb-1.0.rc +59 -0
  52. data/ext/libusbx-1.0.14/libusb/libusb.h +1506 -0
  53. data/ext/libusbx-1.0.14/libusb/libusbi.h +910 -0
  54. data/ext/libusbx-1.0.14/libusb/os/darwin_usb.c +1807 -0
  55. data/ext/libusbx-1.0.14/libusb/os/darwin_usb.h +169 -0
  56. data/ext/libusbx-1.0.14/libusb/os/linux_usbfs.c +2569 -0
  57. data/ext/libusbx-1.0.14/libusb/os/linux_usbfs.h +149 -0
  58. data/ext/libusbx-1.0.14/libusb/os/openbsd_usb.c +727 -0
  59. data/ext/libusbx-1.0.14/libusb/os/poll_posix.h +10 -0
  60. data/ext/libusbx-1.0.14/libusb/os/poll_windows.c +747 -0
  61. data/ext/libusbx-1.0.14/libusb/os/poll_windows.h +114 -0
  62. data/ext/libusbx-1.0.14/libusb/os/threads_posix.c +80 -0
  63. data/ext/libusbx-1.0.14/libusb/os/threads_posix.h +50 -0
  64. data/ext/libusbx-1.0.14/libusb/os/threads_windows.c +211 -0
  65. data/ext/libusbx-1.0.14/libusb/os/threads_windows.h +87 -0
  66. data/ext/libusbx-1.0.14/libusb/os/windows_usb.c +4369 -0
  67. data/ext/libusbx-1.0.14/libusb/os/windows_usb.h +979 -0
  68. data/ext/libusbx-1.0.14/libusb/sync.c +321 -0
  69. data/ext/libusbx-1.0.14/libusb/version.h +18 -0
  70. data/ext/libusbx-1.0.14/libusb/version_nano.h +1 -0
  71. data/ext/libusbx-1.0.14/ltmain.sh +9636 -0
  72. data/ext/libusbx-1.0.14/missing +376 -0
  73. data/lib/libusb.rb +2 -3
  74. data/lib/libusb/call.rb +49 -7
  75. data/lib/libusb/compat.rb +15 -9
  76. data/lib/libusb/configuration.rb +15 -3
  77. data/lib/libusb/constants.rb +19 -6
  78. data/lib/libusb/context.rb +181 -3
  79. data/lib/libusb/dev_handle.rb +91 -40
  80. data/lib/libusb/endpoint.rb +41 -14
  81. data/lib/libusb/eventmachine.rb +183 -0
  82. data/lib/libusb/transfer.rb +21 -8
  83. data/lib/libusb/version_gem.rb +19 -0
  84. data/lib/libusb/{version.rb → version_struct.rb} +0 -0
  85. data/libusb.gemspec +31 -0
  86. data/test/test_libusb_compat.rb +1 -1
  87. data/test/test_libusb_compat_mass_storage.rb +2 -2
  88. data/test/test_libusb_descriptors.rb +1 -1
  89. data/test/test_libusb_event_machine.rb +118 -0
  90. data/test/test_libusb_iso_transfer.rb +6 -1
  91. data/test/test_libusb_mass_storage.rb +9 -3
  92. data/test/test_libusb_mass_storage2.rb +1 -1
  93. data/test/test_libusb_structs.rb +45 -0
  94. data/test/test_libusb_threads.rb +89 -0
  95. data/test/test_libusb_version.rb +4 -0
  96. metadata +109 -44
  97. data/.autotest +0 -23
  98. data/.gemtest +0 -0
  99. data/Manifest.txt +0 -3
  100. data/README.rdoc +0 -115
  101. data/test/test_libusb_keyboard.rb +0 -50
@@ -0,0 +1,10 @@
1
+ #ifndef LIBUSB_POLL_POSIX_H
2
+ #define LIBUSB_POLL_POSIX_H
3
+
4
+ #define usbi_write write
5
+ #define usbi_read read
6
+ #define usbi_close close
7
+ #define usbi_pipe pipe
8
+ #define usbi_poll poll
9
+
10
+ #endif /* LIBUSB_POLL_POSIX_H */
@@ -0,0 +1,747 @@
1
+ /*
2
+ * poll_windows: poll compatibility wrapper for Windows
3
+ * Copyright © 2009-2010 Pete Batard <pbatard@gmail.com>
4
+ * With contributions from Michael Plante, Orin Eman et al.
5
+ * Parts of poll implementation from libusb-win32, by Stephan Meyer et al.
6
+ *
7
+ * This library is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * This library is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with this library; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ *
21
+ */
22
+
23
+ /*
24
+ * poll() and pipe() Windows compatibility layer for libusbx 1.0
25
+ *
26
+ * The way this layer works is by using OVERLAPPED with async I/O transfers, as
27
+ * OVERLAPPED have an associated event which is flagged for I/O completion.
28
+ *
29
+ * For USB pollable async I/O, you would typically:
30
+ * - obtain a Windows HANDLE to a file or device that has been opened in
31
+ * OVERLAPPED mode
32
+ * - call usbi_create_fd with this handle to obtain a custom fd.
33
+ * Note that if you need simultaneous R/W access, you need to call create_fd
34
+ * twice, once in _O_RDONLY and once in _O_WRONLY mode to obtain 2 separate
35
+ * pollable fds
36
+ * - leave the core functions call the poll routine and flag POLLIN/POLLOUT
37
+ *
38
+ * The pipe pollable synchronous I/O works using the overlapped event associated
39
+ * with a fake pipe. The read/write functions are only meant to be used in that
40
+ * context.
41
+ */
42
+ #include <errno.h>
43
+ #include <fcntl.h>
44
+ #include <stdio.h>
45
+ #include <stdlib.h>
46
+ #include <io.h>
47
+
48
+ #include <libusbi.h>
49
+
50
+ // Uncomment to debug the polling layer
51
+ //#define DEBUG_POLL_WINDOWS
52
+ #if defined(DEBUG_POLL_WINDOWS)
53
+ #define poll_dbg usbi_dbg
54
+ #else
55
+ // MSVC++ < 2005 cannot use a variadic argument and non MSVC
56
+ // compilers produce warnings if parenthesis are ommitted.
57
+ #if defined(_MSC_VER) && _MSC_VER < 1400
58
+ #define poll_dbg
59
+ #else
60
+ #define poll_dbg(...)
61
+ #endif
62
+ #endif
63
+
64
+ #if defined(_PREFAST_)
65
+ #pragma warning(disable:28719)
66
+ #endif
67
+
68
+ #if defined(__CYGWIN__)
69
+ // cygwin produces a warning unless these prototypes are defined
70
+ extern int _open(char* name, int flags);
71
+ extern int _close(int fd);
72
+ extern int _snprintf(char *buffer, size_t count, const char *format, ...);
73
+ #define NUL_DEVICE "/dev/null"
74
+ #else
75
+ #define NUL_DEVICE "NUL"
76
+ #endif
77
+
78
+ #define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0)
79
+
80
+ // public fd data
81
+ const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, RW_NONE};
82
+ struct winfd poll_fd[MAX_FDS];
83
+ // internal fd data
84
+ struct {
85
+ CRITICAL_SECTION mutex; // lock for fds
86
+ // Additional variables for XP CancelIoEx partial emulation
87
+ HANDLE original_handle;
88
+ DWORD thread_id;
89
+ } _poll_fd[MAX_FDS];
90
+
91
+ // globals
92
+ BOOLEAN is_polling_set = FALSE;
93
+ LONG pipe_number = 0;
94
+ static volatile LONG compat_spinlock = 0;
95
+
96
+ // CancelIoEx, available on Vista and later only, provides the ability to cancel
97
+ // a single transfer (OVERLAPPED) when used. As it may not be part of any of the
98
+ // platform headers, we hook into the Kernel32 system DLL directly to seek it.
99
+ static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
100
+ #define CancelIoEx_Available (pCancelIoEx != NULL)
101
+ static __inline BOOL cancel_io(int _index)
102
+ {
103
+ if ((_index < 0) || (_index >= MAX_FDS)) {
104
+ return FALSE;
105
+ }
106
+
107
+ if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE)
108
+ || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) {
109
+ return TRUE;
110
+ }
111
+ if (CancelIoEx_Available) {
112
+ return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].overlapped);
113
+ }
114
+ if (_poll_fd[_index].thread_id == GetCurrentThreadId()) {
115
+ return CancelIo(poll_fd[_index].handle);
116
+ }
117
+ usbi_warn(NULL, "Unable to cancel I/O that was started from another thread");
118
+ return FALSE;
119
+ }
120
+
121
+ // Init
122
+ void init_polling(void)
123
+ {
124
+ int i;
125
+
126
+ while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) {
127
+ SleepEx(0, TRUE);
128
+ }
129
+ if (!is_polling_set) {
130
+ pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED))
131
+ GetProcAddress(GetModuleHandleA("KERNEL32"), "CancelIoEx");
132
+ usbi_dbg("Will use CancelIo%s for I/O cancellation",
133
+ CancelIoEx_Available?"Ex":"");
134
+ for (i=0; i<MAX_FDS; i++) {
135
+ poll_fd[i] = INVALID_WINFD;
136
+ _poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
137
+ _poll_fd[i].thread_id = 0;
138
+ InitializeCriticalSection(&_poll_fd[i].mutex);
139
+ }
140
+ is_polling_set = TRUE;
141
+ }
142
+ InterlockedExchange((LONG *)&compat_spinlock, 0);
143
+ }
144
+
145
+ // Internal function to retrieve the table index (and lock the fd mutex)
146
+ int _fd_to_index_and_lock(int fd)
147
+ {
148
+ int i;
149
+
150
+ if (fd <= 0)
151
+ return -1;
152
+
153
+ for (i=0; i<MAX_FDS; i++) {
154
+ if (poll_fd[i].fd == fd) {
155
+ EnterCriticalSection(&_poll_fd[i].mutex);
156
+ // fd might have changed before we got to critical
157
+ if (poll_fd[i].fd != fd) {
158
+ LeaveCriticalSection(&_poll_fd[i].mutex);
159
+ continue;
160
+ }
161
+ return i;
162
+ }
163
+ }
164
+ return -1;
165
+ }
166
+
167
+ OVERLAPPED *create_overlapped(void)
168
+ {
169
+ OVERLAPPED *overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED));
170
+ if (overlapped == NULL) {
171
+ return NULL;
172
+ }
173
+ overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
174
+ if(overlapped->hEvent == NULL) {
175
+ free (overlapped);
176
+ return NULL;
177
+ }
178
+ return overlapped;
179
+ }
180
+
181
+ void free_overlapped(OVERLAPPED *overlapped)
182
+ {
183
+ if (overlapped == NULL)
184
+ return;
185
+
186
+ if ( (overlapped->hEvent != 0)
187
+ && (overlapped->hEvent != INVALID_HANDLE_VALUE) ) {
188
+ CloseHandle(overlapped->hEvent);
189
+ }
190
+ free(overlapped);
191
+ }
192
+
193
+ void reset_overlapped(OVERLAPPED *overlapped)
194
+ {
195
+ HANDLE event_handle;
196
+ if (overlapped == NULL)
197
+ return;
198
+
199
+ event_handle = overlapped->hEvent;
200
+ if (event_handle != NULL) {
201
+ ResetEvent(event_handle);
202
+ }
203
+ memset(overlapped, 0, sizeof(OVERLAPPED));
204
+ overlapped->hEvent = event_handle;
205
+ }
206
+
207
+ void exit_polling(void)
208
+ {
209
+ int i;
210
+
211
+ while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) {
212
+ SleepEx(0, TRUE);
213
+ }
214
+ if (is_polling_set) {
215
+ is_polling_set = FALSE;
216
+
217
+ for (i=0; i<MAX_FDS; i++) {
218
+ // Cancel any async I/O (handle can be invalid)
219
+ cancel_io(i);
220
+ // If anything was pending on that I/O, it should be
221
+ // terminating, and we should be able to access the fd
222
+ // mutex lock before too long
223
+ EnterCriticalSection(&_poll_fd[i].mutex);
224
+ if ( (poll_fd[i].fd > 0) && (poll_fd[i].handle != INVALID_HANDLE_VALUE) && (poll_fd[i].handle != 0)
225
+ && (GetFileType(poll_fd[i].handle) == FILE_TYPE_UNKNOWN) ) {
226
+ _close(poll_fd[i].fd);
227
+ }
228
+ free_overlapped(poll_fd[i].overlapped);
229
+ if (!CancelIoEx_Available) {
230
+ // Close duplicate handle
231
+ if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) {
232
+ CloseHandle(poll_fd[i].handle);
233
+ }
234
+ }
235
+ poll_fd[i] = INVALID_WINFD;
236
+ LeaveCriticalSection(&_poll_fd[i].mutex);
237
+ DeleteCriticalSection(&_poll_fd[i].mutex);
238
+ }
239
+ }
240
+ InterlockedExchange((LONG *)&compat_spinlock, 0);
241
+ }
242
+
243
+ /*
244
+ * Create a fake pipe.
245
+ * As libusbx only uses pipes for signaling, all we need from a pipe is an
246
+ * event. To that extent, we create a single wfd and overlapped as a means
247
+ * to access that event.
248
+ */
249
+ int usbi_pipe(int filedes[2])
250
+ {
251
+ int i;
252
+ OVERLAPPED* overlapped;
253
+
254
+ CHECK_INIT_POLLING;
255
+
256
+ overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED));
257
+ if (overlapped == NULL) {
258
+ return -1;
259
+ }
260
+ // The overlapped must have status pending for signaling to work in poll
261
+ overlapped->Internal = STATUS_PENDING;
262
+ overlapped->InternalHigh = 0;
263
+
264
+ // Read end of the "pipe"
265
+ filedes[0] = _open(NUL_DEVICE, _O_WRONLY);
266
+ if (filedes[0] < 0) {
267
+ usbi_err(NULL, "could not create pipe: errno %d", errno);
268
+ goto out1;
269
+ }
270
+ // We can use the same handle for both ends
271
+ filedes[1] = filedes[0];
272
+ poll_dbg("pipe filedes = %d", filedes[0]);
273
+
274
+ // Note: manual reset must be true (second param) as the reset occurs in read
275
+ overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
276
+ if(!overlapped->hEvent) {
277
+ goto out2;
278
+ }
279
+
280
+ for (i=0; i<MAX_FDS; i++) {
281
+ if (poll_fd[i].fd < 0) {
282
+ EnterCriticalSection(&_poll_fd[i].mutex);
283
+ // fd might have been allocated before we got to critical
284
+ if (poll_fd[i].fd >= 0) {
285
+ LeaveCriticalSection(&_poll_fd[i].mutex);
286
+ continue;
287
+ }
288
+
289
+ poll_fd[i].fd = filedes[0];
290
+ poll_fd[i].handle = DUMMY_HANDLE;
291
+ poll_fd[i].overlapped = overlapped;
292
+ // There's no polling on the write end, so we just use READ for our needs
293
+ poll_fd[i].rw = RW_READ;
294
+ _poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
295
+ LeaveCriticalSection(&_poll_fd[i].mutex);
296
+ return 0;
297
+ }
298
+ }
299
+
300
+ CloseHandle(overlapped->hEvent);
301
+ out2:
302
+ _close(filedes[0]);
303
+ out1:
304
+ free(overlapped);
305
+ return -1;
306
+ }
307
+
308
+ /*
309
+ * Create both an fd and an OVERLAPPED from an open Windows handle, so that
310
+ * it can be used with our polling function
311
+ * The handle MUST support overlapped transfers (usually requires CreateFile
312
+ * with FILE_FLAG_OVERLAPPED)
313
+ * Return a pollable file descriptor struct, or INVALID_WINFD on error
314
+ *
315
+ * Note that the fd returned by this function is a per-transfer fd, rather
316
+ * than a per-session fd and cannot be used for anything else but our
317
+ * custom functions (the fd itself points to the NUL: device)
318
+ * if you plan to do R/W on the same handle, you MUST create 2 fds: one for
319
+ * read and one for write. Using a single R/W fd is unsupported and will
320
+ * produce unexpected results
321
+ */
322
+ struct winfd usbi_create_fd(HANDLE handle, int access_mode)
323
+ {
324
+ int i, fd;
325
+ struct winfd wfd = INVALID_WINFD;
326
+ OVERLAPPED* overlapped = NULL;
327
+
328
+ CHECK_INIT_POLLING;
329
+
330
+ if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) {
331
+ return INVALID_WINFD;
332
+ }
333
+
334
+ if ((access_mode != _O_RDONLY) && (access_mode != _O_WRONLY)) {
335
+ usbi_warn(NULL, "only one of _O_RDONLY or _O_WRONLY are supported.\n"
336
+ "If you want to poll for R/W simultaneously, create multiple fds from the same handle.");
337
+ return INVALID_WINFD;
338
+ }
339
+ if (access_mode == _O_RDONLY) {
340
+ wfd.rw = RW_READ;
341
+ } else {
342
+ wfd.rw = RW_WRITE;
343
+ }
344
+
345
+ // Ensure that we get a non system conflicting unique fd, using
346
+ // the same fd attribution system as the pipe ends
347
+ fd = _open(NUL_DEVICE, _O_WRONLY);
348
+ if (fd < 0) {
349
+ return INVALID_WINFD;
350
+ }
351
+
352
+ overlapped = create_overlapped();
353
+ if(overlapped == NULL) {
354
+ _close(fd);
355
+ return INVALID_WINFD;
356
+ }
357
+
358
+ for (i=0; i<MAX_FDS; i++) {
359
+ if (poll_fd[i].fd < 0) {
360
+ EnterCriticalSection(&_poll_fd[i].mutex);
361
+ // fd might have been removed before we got to critical
362
+ if (poll_fd[i].fd >= 0) {
363
+ LeaveCriticalSection(&_poll_fd[i].mutex);
364
+ continue;
365
+ }
366
+ wfd.fd = fd;
367
+ // Attempt to emulate some of the CancelIoEx behaviour on platforms
368
+ // that don't have it
369
+ if (!CancelIoEx_Available) {
370
+ _poll_fd[i].thread_id = GetCurrentThreadId();
371
+ if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
372
+ &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
373
+ usbi_dbg("could not duplicate handle for CancelIo - using original one");
374
+ wfd.handle = handle;
375
+ // Make sure we won't close the original handle on fd deletion then
376
+ _poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
377
+ } else {
378
+ _poll_fd[i].original_handle = handle;
379
+ }
380
+ } else {
381
+ wfd.handle = handle;
382
+ }
383
+ wfd.overlapped = overlapped;
384
+ memcpy(&poll_fd[i], &wfd, sizeof(struct winfd));
385
+ LeaveCriticalSection(&_poll_fd[i].mutex);
386
+ return wfd;
387
+ }
388
+ }
389
+ free_overlapped(overlapped);
390
+ _close(fd);
391
+ return INVALID_WINFD;
392
+ }
393
+
394
+ void _free_index(int _index)
395
+ {
396
+ // Cancel any async IO (Don't care about the validity of our handles for this)
397
+ cancel_io(_index);
398
+ // close fake handle for devices
399
+ if ( (poll_fd[_index].handle != INVALID_HANDLE_VALUE) && (poll_fd[_index].handle != 0)
400
+ && (GetFileType(poll_fd[_index].handle) == FILE_TYPE_UNKNOWN) ) {
401
+ _close(poll_fd[_index].fd);
402
+ }
403
+ // close the duplicate handle (if we have an actual duplicate)
404
+ if (!CancelIoEx_Available) {
405
+ if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) {
406
+ CloseHandle(poll_fd[_index].handle);
407
+ }
408
+ _poll_fd[_index].original_handle = INVALID_HANDLE_VALUE;
409
+ _poll_fd[_index].thread_id = 0;
410
+ }
411
+ free_overlapped(poll_fd[_index].overlapped);
412
+ poll_fd[_index] = INVALID_WINFD;
413
+ }
414
+
415
+ /*
416
+ * Release a pollable file descriptor.
417
+ *
418
+ * Note that the associated Windows handle is not closed by this call
419
+ */
420
+ void usbi_free_fd(int fd)
421
+ {
422
+ int _index;
423
+
424
+ CHECK_INIT_POLLING;
425
+
426
+ _index = _fd_to_index_and_lock(fd);
427
+ if (_index < 0) {
428
+ return;
429
+ }
430
+ _free_index(_index);
431
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
432
+ }
433
+
434
+ /*
435
+ * The functions below perform various conversions between fd, handle and OVERLAPPED
436
+ */
437
+ struct winfd fd_to_winfd(int fd)
438
+ {
439
+ int i;
440
+ struct winfd wfd;
441
+
442
+ CHECK_INIT_POLLING;
443
+
444
+ if (fd <= 0)
445
+ return INVALID_WINFD;
446
+
447
+ for (i=0; i<MAX_FDS; i++) {
448
+ if (poll_fd[i].fd == fd) {
449
+ EnterCriticalSection(&_poll_fd[i].mutex);
450
+ // fd might have been deleted before we got to critical
451
+ if (poll_fd[i].fd != fd) {
452
+ LeaveCriticalSection(&_poll_fd[i].mutex);
453
+ continue;
454
+ }
455
+ memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
456
+ LeaveCriticalSection(&_poll_fd[i].mutex);
457
+ return wfd;
458
+ }
459
+ }
460
+ return INVALID_WINFD;
461
+ }
462
+
463
+ struct winfd handle_to_winfd(HANDLE handle)
464
+ {
465
+ int i;
466
+ struct winfd wfd;
467
+
468
+ CHECK_INIT_POLLING;
469
+
470
+ if ((handle == 0) || (handle == INVALID_HANDLE_VALUE))
471
+ return INVALID_WINFD;
472
+
473
+ for (i=0; i<MAX_FDS; i++) {
474
+ if (poll_fd[i].handle == handle) {
475
+ EnterCriticalSection(&_poll_fd[i].mutex);
476
+ // fd might have been deleted before we got to critical
477
+ if (poll_fd[i].handle != handle) {
478
+ LeaveCriticalSection(&_poll_fd[i].mutex);
479
+ continue;
480
+ }
481
+ memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
482
+ LeaveCriticalSection(&_poll_fd[i].mutex);
483
+ return wfd;
484
+ }
485
+ }
486
+ return INVALID_WINFD;
487
+ }
488
+
489
+ struct winfd overlapped_to_winfd(OVERLAPPED* overlapped)
490
+ {
491
+ int i;
492
+ struct winfd wfd;
493
+
494
+ CHECK_INIT_POLLING;
495
+
496
+ if (overlapped == NULL)
497
+ return INVALID_WINFD;
498
+
499
+ for (i=0; i<MAX_FDS; i++) {
500
+ if (poll_fd[i].overlapped == overlapped) {
501
+ EnterCriticalSection(&_poll_fd[i].mutex);
502
+ // fd might have been deleted before we got to critical
503
+ if (poll_fd[i].overlapped != overlapped) {
504
+ LeaveCriticalSection(&_poll_fd[i].mutex);
505
+ continue;
506
+ }
507
+ memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
508
+ LeaveCriticalSection(&_poll_fd[i].mutex);
509
+ return wfd;
510
+ }
511
+ }
512
+ return INVALID_WINFD;
513
+ }
514
+
515
+ /*
516
+ * POSIX poll equivalent, using Windows OVERLAPPED
517
+ * Currently, this function only accepts one of POLLIN or POLLOUT per fd
518
+ * (but you can create multiple fds from the same handle for read and write)
519
+ */
520
+ int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout)
521
+ {
522
+ unsigned i;
523
+ int _index, object_index, triggered;
524
+ HANDLE *handles_to_wait_on;
525
+ int *handle_to_index;
526
+ DWORD nb_handles_to_wait_on = 0;
527
+ DWORD ret;
528
+
529
+ CHECK_INIT_POLLING;
530
+
531
+ triggered = 0;
532
+ handles_to_wait_on = (HANDLE*) calloc(nfds+1, sizeof(HANDLE)); // +1 for fd_update
533
+ handle_to_index = (int*) calloc(nfds, sizeof(int));
534
+ if ((handles_to_wait_on == NULL) || (handle_to_index == NULL)) {
535
+ errno = ENOMEM;
536
+ triggered = -1;
537
+ goto poll_exit;
538
+ }
539
+
540
+ for (i = 0; i < nfds; ++i) {
541
+ fds[i].revents = 0;
542
+
543
+ // Only one of POLLIN or POLLOUT can be selected with this version of poll (not both)
544
+ if ((fds[i].events & ~POLLIN) && (!(fds[i].events & POLLOUT))) {
545
+ fds[i].revents |= POLLERR;
546
+ errno = EACCES;
547
+ usbi_warn(NULL, "unsupported set of events");
548
+ triggered = -1;
549
+ goto poll_exit;
550
+ }
551
+
552
+ _index = _fd_to_index_and_lock(fds[i].fd);
553
+ poll_dbg("fd[%d]=%d: (overlapped=%p) got events %04X", i, poll_fd[_index].fd, poll_fd[_index].overlapped, fds[i].events);
554
+
555
+ if ( (_index < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE)
556
+ || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL)) {
557
+ fds[i].revents |= POLLNVAL | POLLERR;
558
+ errno = EBADF;
559
+ if (_index >= 0) {
560
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
561
+ }
562
+ usbi_warn(NULL, "invalid fd");
563
+ triggered = -1;
564
+ goto poll_exit;
565
+ }
566
+
567
+ // IN or OUT must match our fd direction
568
+ if ((fds[i].events & POLLIN) && (poll_fd[_index].rw != RW_READ)) {
569
+ fds[i].revents |= POLLNVAL | POLLERR;
570
+ errno = EBADF;
571
+ usbi_warn(NULL, "attempted POLLIN on fd without READ access");
572
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
573
+ triggered = -1;
574
+ goto poll_exit;
575
+ }
576
+
577
+ if ((fds[i].events & POLLOUT) && (poll_fd[_index].rw != RW_WRITE)) {
578
+ fds[i].revents |= POLLNVAL | POLLERR;
579
+ errno = EBADF;
580
+ usbi_warn(NULL, "attempted POLLOUT on fd without WRITE access");
581
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
582
+ triggered = -1;
583
+ goto poll_exit;
584
+ }
585
+
586
+ // The following macro only works if overlapped I/O was reported pending
587
+ if ( (HasOverlappedIoCompleted(poll_fd[_index].overlapped))
588
+ || (HasOverlappedIoCompletedSync(poll_fd[_index].overlapped)) ) {
589
+ poll_dbg(" completed");
590
+ // checks above should ensure this works:
591
+ fds[i].revents = fds[i].events;
592
+ triggered++;
593
+ } else {
594
+ handles_to_wait_on[nb_handles_to_wait_on] = poll_fd[_index].overlapped->hEvent;
595
+ handle_to_index[nb_handles_to_wait_on] = i;
596
+ nb_handles_to_wait_on++;
597
+ }
598
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
599
+ }
600
+
601
+ // If nothing was triggered, wait on all fds that require it
602
+ if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) {
603
+ if (timeout < 0) {
604
+ poll_dbg("starting infinite wait for %d handles...", (int)nb_handles_to_wait_on);
605
+ } else {
606
+ poll_dbg("starting %d ms wait for %d handles...", timeout, (int)nb_handles_to_wait_on);
607
+ }
608
+ ret = WaitForMultipleObjects(nb_handles_to_wait_on, handles_to_wait_on,
609
+ FALSE, (timeout<0)?INFINITE:(DWORD)timeout);
610
+ object_index = ret-WAIT_OBJECT_0;
611
+ if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_wait_on)) {
612
+ poll_dbg(" completed after wait");
613
+ i = handle_to_index[object_index];
614
+ _index = _fd_to_index_and_lock(fds[i].fd);
615
+ fds[i].revents = fds[i].events;
616
+ triggered++;
617
+ if (_index >= 0) {
618
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
619
+ }
620
+ } else if (ret == WAIT_TIMEOUT) {
621
+ poll_dbg(" timed out");
622
+ triggered = 0; // 0 = timeout
623
+ } else {
624
+ errno = EIO;
625
+ triggered = -1; // error
626
+ }
627
+ }
628
+
629
+ poll_exit:
630
+ if (handles_to_wait_on != NULL) {
631
+ free(handles_to_wait_on);
632
+ }
633
+ if (handle_to_index != NULL) {
634
+ free(handle_to_index);
635
+ }
636
+ return triggered;
637
+ }
638
+
639
+ /*
640
+ * close a fake pipe fd
641
+ */
642
+ int usbi_close(int fd)
643
+ {
644
+ int _index;
645
+ int r = -1;
646
+
647
+ CHECK_INIT_POLLING;
648
+
649
+ _index = _fd_to_index_and_lock(fd);
650
+
651
+ if (_index < 0) {
652
+ errno = EBADF;
653
+ } else {
654
+ if (poll_fd[_index].overlapped != NULL) {
655
+ // Must be a different event for each end of the pipe
656
+ CloseHandle(poll_fd[_index].overlapped->hEvent);
657
+ free(poll_fd[_index].overlapped);
658
+ }
659
+ r = _close(poll_fd[_index].fd);
660
+ if (r != 0) {
661
+ errno = EIO;
662
+ }
663
+ poll_fd[_index] = INVALID_WINFD;
664
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
665
+ }
666
+ return r;
667
+ }
668
+
669
+ /*
670
+ * synchronous write for fake "pipe" signaling
671
+ */
672
+ ssize_t usbi_write(int fd, const void *buf, size_t count)
673
+ {
674
+ int _index;
675
+ UNUSED(buf);
676
+
677
+ CHECK_INIT_POLLING;
678
+
679
+ if (count != sizeof(unsigned char)) {
680
+ usbi_err(NULL, "this function should only used for signaling");
681
+ return -1;
682
+ }
683
+
684
+ _index = _fd_to_index_and_lock(fd);
685
+
686
+ if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) {
687
+ errno = EBADF;
688
+ if (_index >= 0) {
689
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
690
+ }
691
+ return -1;
692
+ }
693
+
694
+ poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId());
695
+ SetEvent(poll_fd[_index].overlapped->hEvent);
696
+ poll_fd[_index].overlapped->Internal = STATUS_WAIT_0;
697
+ // If two threads write on the pipe at the same time, we need to
698
+ // process two separate reads => use the overlapped as a counter
699
+ poll_fd[_index].overlapped->InternalHigh++;
700
+
701
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
702
+ return sizeof(unsigned char);
703
+ }
704
+
705
+ /*
706
+ * synchronous read for fake "pipe" signaling
707
+ */
708
+ ssize_t usbi_read(int fd, void *buf, size_t count)
709
+ {
710
+ int _index;
711
+ ssize_t r = -1;
712
+ UNUSED(buf);
713
+
714
+ CHECK_INIT_POLLING;
715
+
716
+ if (count != sizeof(unsigned char)) {
717
+ usbi_err(NULL, "this function should only used for signaling");
718
+ return -1;
719
+ }
720
+
721
+ _index = _fd_to_index_and_lock(fd);
722
+
723
+ if (_index < 0) {
724
+ errno = EBADF;
725
+ return -1;
726
+ }
727
+
728
+ if (WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) {
729
+ usbi_warn(NULL, "waiting for event failed: %d", (int)GetLastError());
730
+ errno = EIO;
731
+ goto out;
732
+ }
733
+
734
+ poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId());
735
+ poll_fd[_index].overlapped->InternalHigh--;
736
+ // Don't reset unless we don't have any more events to process
737
+ if (poll_fd[_index].overlapped->InternalHigh <= 0) {
738
+ ResetEvent(poll_fd[_index].overlapped->hEvent);
739
+ poll_fd[_index].overlapped->Internal = STATUS_PENDING;
740
+ }
741
+
742
+ r = sizeof(unsigned char);
743
+
744
+ out:
745
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
746
+ return r;
747
+ }