libusb 0.2.2 → 0.3.0

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