1 /*
2 * windows backend for libusb 1.0
3 * Copyright © 2009-2012 Pete Batard <[email protected]>
4 * With contributions from Michael Plante, Orin Eman et al.
5 * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
6 * HID Reports IOCTLs inspired from HIDAPI by Alan Ott, Signal 11 Software
7 * Hash table functions adapted from glibc, by Ulrich Drepper et al.
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 <config.h>
26
27 #include <stdio.h>
28
29 #include "libusbi.h"
30 #include "windows_common.h"
31
32 #define EPOCH_TIME UINT64_C(116444736000000000) // 1970.01.01 00:00:000 in MS Filetime
33
34 #define STATUS_SUCCESS ((ULONG_PTR)0UL)
35
36 // Public
37 enum windows_version windows_version = WINDOWS_UNDEFINED;
38
39 // Global variables for init/exit
40 static unsigned int init_count;
41 static bool usbdk_available;
42
43 /*
44 * Converts a windows error to human readable string
45 * uses retval as errorcode, or, if 0, use GetLastError()
46 */
47 #if defined(ENABLE_LOGGING)
windows_error_str(DWORD error_code)48 const char *windows_error_str(DWORD error_code)
49 {
50 static char err_string[256];
51
52 DWORD size;
53 int len;
54
55 if (error_code == 0)
56 error_code = GetLastError();
57
58 len = sprintf(err_string, "[%lu] ", ULONG_CAST(error_code));
59
60 // Translate codes returned by SetupAPI. The ones we are dealing with are either
61 // in 0x0000xxxx or 0xE000xxxx and can be distinguished from standard error codes.
62 // See http://msdn.microsoft.com/en-us/library/windows/hardware/ff545011.aspx
63 switch (error_code & 0xE0000000) {
64 case 0:
65 error_code = HRESULT_FROM_WIN32(error_code); // Still leaves ERROR_SUCCESS unmodified
66 break;
67 case 0xE0000000:
68 error_code = 0x80000000 | (FACILITY_SETUPAPI << 16) | (error_code & 0x0000FFFF);
69 break;
70 default:
71 break;
72 }
73
74 size = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
75 NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
76 &err_string[len], sizeof(err_string) - len, NULL);
77 if (size == 0) {
78 DWORD format_error = GetLastError();
79 if (format_error)
80 snprintf(err_string, sizeof(err_string),
81 "Windows error code %lu (FormatMessage error code %lu)",
82 ULONG_CAST(error_code), ULONG_CAST(format_error));
83 else
84 snprintf(err_string, sizeof(err_string), "Unknown error code %lu",
85 ULONG_CAST(error_code));
86 } else {
87 // Remove CRLF from end of message, if present
88 size_t pos = len + size - 2;
89 if (err_string[pos] == '\r')
90 err_string[pos] = '\0';
91 }
92
93 return err_string;
94 }
95 #endif
96
97 /*
98 * Dynamically loads a DLL from the Windows system directory. Unlike the
99 * LoadLibraryA() function, this function will not search through any
100 * directories to try and find the library.
101 */
load_system_library(struct libusb_context * ctx,const char * name)102 HMODULE load_system_library(struct libusb_context *ctx, const char *name)
103 {
104 char library_path[MAX_PATH];
105 char *filename_start;
106 UINT length;
107
108 length = GetSystemDirectoryA(library_path, sizeof(library_path));
109 if ((length == 0) || (length >= (UINT)sizeof(library_path))) {
110 usbi_err(ctx, "program assertion failed - could not get system directory");
111 return NULL;
112 }
113
114 filename_start = library_path + length;
115 // Append '\' + name + ".dll" + NUL
116 length += 1 + (UINT)strlen(name) + 4 + 1;
117 if (length >= (UINT)sizeof(library_path)) {
118 usbi_err(ctx, "program assertion failed - library path buffer overflow");
119 return NULL;
120 }
121
122 sprintf(filename_start, "\\%s.dll", name);
123 return LoadLibraryA(library_path);
124 }
125
126 /* Hash table functions - modified From glibc 2.3.2:
127 [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
128 [Knuth] The Art of Computer Programming, part 3 (6.4) */
129
130 #define HTAB_SIZE 1021UL // *MUST* be a prime number!!
131
132 typedef struct htab_entry {
133 unsigned long used;
134 char *str;
135 } htab_entry;
136
137 static htab_entry *htab_table;
138 static usbi_mutex_t htab_mutex;
139 static unsigned long htab_filled;
140
141 /* Before using the hash table we must allocate memory for it.
142 We allocate one element more as the found prime number says.
143 This is done for more effective indexing as explained in the
144 comment for the hash function. */
htab_create(struct libusb_context * ctx)145 static bool htab_create(struct libusb_context *ctx)
146 {
147 if (htab_table != NULL) {
148 usbi_err(ctx, "program assertion failed - hash table already allocated");
149 return true;
150 }
151
152 // Create a mutex
153 usbi_mutex_init(&htab_mutex);
154
155 usbi_dbg(ctx, "using %lu entries hash table", HTAB_SIZE);
156 htab_filled = 0;
157
158 // allocate memory and zero out.
159 htab_table = calloc(HTAB_SIZE + 1, sizeof(htab_entry));
160 if (htab_table == NULL) {
161 usbi_err(ctx, "could not allocate space for hash table");
162 return false;
163 }
164
165 return true;
166 }
167
168 /* After using the hash table it has to be destroyed. */
htab_destroy(void)169 static void htab_destroy(void)
170 {
171 unsigned long i;
172
173 if (htab_table == NULL)
174 return;
175
176 for (i = 0; i < HTAB_SIZE; i++)
177 free(htab_table[i].str);
178
179 safe_free(htab_table);
180
181 usbi_mutex_destroy(&htab_mutex);
182 }
183
184 /* This is the search function. It uses double hashing with open addressing.
185 We use a trick to speed up the lookup. The table is created with one
186 more element available. This enables us to use the index zero special.
187 This index will never be used because we store the first hash index in
188 the field used where zero means not used. Every other value means used.
189 The used field can be used as a first fast comparison for equality of
190 the stored and the parameter value. This helps to prevent unnecessary
191 expensive calls of strcmp. */
htab_hash(const char * str)192 unsigned long htab_hash(const char *str)
193 {
194 unsigned long hval, hval2;
195 unsigned long idx;
196 unsigned long r = 5381UL;
197 int c;
198 const char *sz = str;
199
200 if (str == NULL)
201 return 0;
202
203 // Compute main hash value (algorithm suggested by Nokia)
204 while ((c = *sz++) != 0)
205 r = ((r << 5) + r) + c;
206 if (r == 0)
207 ++r;
208
209 // compute table hash: simply take the modulus
210 hval = r % HTAB_SIZE;
211 if (hval == 0)
212 ++hval;
213
214 // Try the first index
215 idx = hval;
216
217 // Mutually exclusive access (R/W lock would be better)
218 usbi_mutex_lock(&htab_mutex);
219
220 if (htab_table[idx].used) {
221 if ((htab_table[idx].used == hval) && (strcmp(str, htab_table[idx].str) == 0))
222 goto out_unlock; // existing hash
223
224 usbi_dbg(NULL, "hash collision ('%s' vs '%s')", str, htab_table[idx].str);
225
226 // Second hash function, as suggested in [Knuth]
227 hval2 = 1UL + hval % (HTAB_SIZE - 2);
228
229 do {
230 // Because size is prime this guarantees to step through all available indexes
231 if (idx <= hval2)
232 idx = HTAB_SIZE + idx - hval2;
233 else
234 idx -= hval2;
235
236 // If we visited all entries leave the loop unsuccessfully
237 if (idx == hval)
238 break;
239
240 // If entry is found use it.
241 if ((htab_table[idx].used == hval) && (strcmp(str, htab_table[idx].str) == 0))
242 goto out_unlock;
243 } while (htab_table[idx].used);
244 }
245
246 // Not found => New entry
247
248 // If the table is full return an error
249 if (htab_filled >= HTAB_SIZE) {
250 usbi_err(NULL, "hash table is full (%lu entries)", HTAB_SIZE);
251 idx = 0UL;
252 goto out_unlock;
253 }
254
255 htab_table[idx].str = _strdup(str);
256 if (htab_table[idx].str == NULL) {
257 usbi_err(NULL, "could not duplicate string for hash table");
258 idx = 0UL;
259 goto out_unlock;
260 }
261
262 htab_table[idx].used = hval;
263 ++htab_filled;
264
265 out_unlock:
266 usbi_mutex_unlock(&htab_mutex);
267
268 return idx;
269 }
270
usbd_status_to_libusb_transfer_status(USBD_STATUS status)271 enum libusb_transfer_status usbd_status_to_libusb_transfer_status(USBD_STATUS status)
272 {
273 if (USBD_SUCCESS(status))
274 return LIBUSB_TRANSFER_COMPLETED;
275
276 switch (status) {
277 case USBD_STATUS_TIMEOUT:
278 return LIBUSB_TRANSFER_TIMED_OUT;
279 case USBD_STATUS_CANCELED:
280 return LIBUSB_TRANSFER_CANCELLED;
281 case USBD_STATUS_ENDPOINT_HALTED:
282 case USBD_STATUS_STALL_PID:
283 return LIBUSB_TRANSFER_STALL;
284 case USBD_STATUS_DEVICE_GONE:
285 return LIBUSB_TRANSFER_NO_DEVICE;
286 default:
287 usbi_dbg(NULL, "USBD_STATUS 0x%08lx translated to LIBUSB_TRANSFER_ERROR", ULONG_CAST(status));
288 return LIBUSB_TRANSFER_ERROR;
289 }
290 }
291
292 /*
293 * Make a transfer complete synchronously
294 */
windows_force_sync_completion(struct usbi_transfer * itransfer,ULONG size)295 void windows_force_sync_completion(struct usbi_transfer *itransfer, ULONG size)
296 {
297 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
298 struct windows_context_priv *priv = usbi_get_context_priv(TRANSFER_CTX(transfer));
299 struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
300 OVERLAPPED *overlapped = &transfer_priv->overlapped;
301
302 usbi_dbg(TRANSFER_CTX(transfer), "transfer %p, length %lu", transfer, ULONG_CAST(size));
303
304 overlapped->Internal = (ULONG_PTR)STATUS_SUCCESS;
305 overlapped->InternalHigh = (ULONG_PTR)size;
306
307 if (!PostQueuedCompletionStatus(priv->completion_port, (DWORD)size, (ULONG_PTR)transfer->dev_handle, overlapped))
308 usbi_err(TRANSFER_CTX(transfer), "failed to post I/O completion: %s", windows_error_str(0));
309 }
310
311 /* Windows version detection */
is_x64(void)312 static BOOL is_x64(void)
313 {
314 BOOL ret = FALSE;
315
316 // Detect if we're running a 32 or 64 bit system
317 if (sizeof(uintptr_t) < 8) {
318 IsWow64Process(GetCurrentProcess(), &ret);
319 } else {
320 ret = TRUE;
321 }
322
323 return ret;
324 }
325
get_windows_version(void)326 static enum windows_version get_windows_version(void)
327 {
328 enum windows_version winver;
329 OSVERSIONINFOEXA vi, vi2;
330 unsigned major, minor, version;
331 ULONGLONG major_equal, minor_equal;
332 const char *w, *arch;
333 bool ws;
334
335 #ifndef ENABLE_LOGGING
336 UNUSED(w); UNUSED(arch);
337 #endif
338 memset(&vi, 0, sizeof(vi));
339 vi.dwOSVersionInfoSize = sizeof(vi);
340 if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
341 memset(&vi, 0, sizeof(vi));
342 vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
343 if (!GetVersionExA((OSVERSIONINFOA *)&vi))
344 return WINDOWS_UNDEFINED;
345 }
346
347 if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT)
348 return WINDOWS_UNDEFINED;
349
350 if ((vi.dwMajorVersion > 6) || ((vi.dwMajorVersion == 6) && (vi.dwMinorVersion >= 2))) {
351 // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the actual OS version
352 // See: http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
353 // And starting with Windows 10 Preview 2, Windows enforces the use of the application/supportedOS
354 // manifest in order for VerSetConditionMask() to report the ACTUAL OS major and minor...
355
356 major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
357 for (major = vi.dwMajorVersion; major <= 9; major++) {
358 memset(&vi2, 0, sizeof(vi2));
359 vi2.dwOSVersionInfoSize = sizeof(vi2);
360 vi2.dwMajorVersion = major;
361 if (!VerifyVersionInfoA(&vi2, VER_MAJORVERSION, major_equal))
362 continue;
363
364 if (vi.dwMajorVersion < major) {
365 vi.dwMajorVersion = major;
366 vi.dwMinorVersion = 0;
367 }
368
369 minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL);
370 for (minor = vi.dwMinorVersion; minor <= 9; minor++) {
371 memset(&vi2, 0, sizeof(vi2));
372 vi2.dwOSVersionInfoSize = sizeof(vi2);
373 vi2.dwMinorVersion = minor;
374 if (!VerifyVersionInfoA(&vi2, VER_MINORVERSION, minor_equal))
375 continue;
376
377 vi.dwMinorVersion = minor;
378 break;
379 }
380
381 break;
382 }
383 }
384
385 if ((vi.dwMajorVersion > 0xf) || (vi.dwMinorVersion > 0xf))
386 return WINDOWS_UNDEFINED;
387
388 ws = (vi.wProductType <= VER_NT_WORKSTATION);
389 version = vi.dwMajorVersion << 4 | vi.dwMinorVersion;
390
391 switch (version) {
392 case 0x50: winver = WINDOWS_2000; w = "2000"; break;
393 case 0x51: winver = WINDOWS_XP; w = "XP"; break;
394 case 0x52: winver = WINDOWS_2003; w = "2003"; break;
395 case 0x60: winver = WINDOWS_VISTA; w = (ws ? "Vista" : "2008"); break;
396 case 0x61: winver = WINDOWS_7; w = (ws ? "7" : "2008_R2"); break;
397 case 0x62: winver = WINDOWS_8; w = (ws ? "8" : "2012"); break;
398 case 0x63: winver = WINDOWS_8_1; w = (ws ? "8.1" : "2012_R2"); break;
399 case 0x64: // Early Windows 10 Insider Previews and Windows Server 2017 Technical Preview 1 used version 6.4
400 case 0xA0: winver = WINDOWS_10; w = (ws ? "10" : "2016");
401 if (vi.dwBuildNumber < 20000)
402 break;
403 // fallthrough
404 case 0xB0: winver = WINDOWS_11; w = (ws ? "11" : "2022"); break;
405 default:
406 if (version < 0x50)
407 return WINDOWS_UNDEFINED;
408 winver = WINDOWS_12_OR_LATER;
409 w = "12 or later";
410 }
411
412 // We cannot tell if we are on 8, 10, or 11 without "app manifest"
413 if (version == 0x62 && vi.dwBuildNumber == 9200)
414 w = "8 (or later)";
415
416 arch = is_x64() ? "64-bit" : "32-bit";
417
418 if (vi.wServicePackMinor)
419 usbi_dbg(NULL, "Windows %s SP%u.%u %s", w, vi.wServicePackMajor, vi.wServicePackMinor, arch);
420 else if (vi.wServicePackMajor)
421 usbi_dbg(NULL, "Windows %s SP%u %s", w, vi.wServicePackMajor, arch);
422 else
423 usbi_dbg(NULL, "Windows %s %s", w, arch);
424
425 return winver;
426 }
427
windows_iocp_thread(void * arg)428 static unsigned __stdcall windows_iocp_thread(void *arg)
429 {
430 struct libusb_context *ctx = arg;
431 struct windows_context_priv *priv = usbi_get_context_priv(ctx);
432 HANDLE iocp = priv->completion_port;
433 DWORD num_bytes;
434 ULONG_PTR completion_key;
435 OVERLAPPED *overlapped;
436 struct libusb_device_handle *dev_handle;
437 struct libusb_device_handle *opened_device_handle;
438 struct windows_device_handle_priv *handle_priv;
439 struct windows_transfer_priv *transfer_priv;
440 struct usbi_transfer *itransfer;
441 bool found;
442
443 usbi_dbg(ctx, "I/O completion thread started");
444
445 while (true) {
446 overlapped = NULL;
447 if (!GetQueuedCompletionStatus(iocp, &num_bytes, &completion_key, &overlapped, INFINITE) && (overlapped == NULL)) {
448 usbi_err(ctx, "GetQueuedCompletionStatus failed: %s", windows_error_str(0));
449 break;
450 }
451
452 if (overlapped == NULL) {
453 // Signal to quit
454 if (completion_key != (ULONG_PTR)ctx)
455 usbi_err(ctx, "program assertion failed - overlapped is NULL");
456 break;
457 }
458
459 // Find the transfer associated with the OVERLAPPED that just completed.
460 // If we cannot find a match, the I/O operation originated from outside of libusb
461 // (e.g. within libusbK) and we need to ignore it.
462 dev_handle = (struct libusb_device_handle *)completion_key;
463
464 found = false;
465 transfer_priv = NULL;
466
467 // Issue 912: lock opened device handles in context to search the current device handle
468 // to avoid accessing unallocated memory after device has been closed
469 usbi_mutex_lock(&ctx->open_devs_lock);
470 for_each_open_device(ctx, opened_device_handle) {
471 if (dev_handle == opened_device_handle) {
472 handle_priv = usbi_get_device_handle_priv(dev_handle);
473
474 usbi_mutex_lock(&dev_handle->lock);
475 list_for_each_entry(transfer_priv, &handle_priv->active_transfers, list, struct windows_transfer_priv) {
476 if (overlapped == &transfer_priv->overlapped) {
477 // This OVERLAPPED belongs to us, remove the transfer from the device handle's list
478 list_del(&transfer_priv->list);
479 found = true;
480 break;
481 }
482 }
483 usbi_mutex_unlock(&dev_handle->lock);
484 }
485 }
486 usbi_mutex_unlock(&ctx->open_devs_lock);
487
488 if (!found) {
489 usbi_dbg(ctx, "ignoring overlapped %p for handle %p",
490 overlapped, dev_handle);
491 continue;
492 }
493
494 itransfer = TRANSFER_PRIV_TO_USBI_TRANSFER(transfer_priv);
495 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
496 usbi_dbg(ctx, "transfer %p completed, length %lu",
497 transfer, ULONG_CAST(num_bytes));
498 usbi_signal_transfer_completion(itransfer);
499 }
500
501 usbi_dbg(ctx, "I/O completion thread exiting");
502
503 return 0;
504 }
505
windows_init(struct libusb_context * ctx)506 static int windows_init(struct libusb_context *ctx)
507 {
508 struct windows_context_priv *priv = usbi_get_context_priv(ctx);
509 bool winusb_backend_init = false;
510 int r;
511
512 // NB: concurrent usage supposes that init calls are equally balanced with
513 // exit calls. If init is called more than exit, we will not exit properly
514 if (++init_count == 1) { // First init?
515 windows_version = get_windows_version();
516 if (windows_version == WINDOWS_UNDEFINED) {
517 usbi_err(ctx, "failed to detect Windows version");
518 r = LIBUSB_ERROR_NOT_SUPPORTED;
519 goto init_exit;
520 } else if (windows_version < WINDOWS_VISTA) {
521 usbi_err(ctx, "Windows version is too old");
522 r = LIBUSB_ERROR_NOT_SUPPORTED;
523 goto init_exit;
524 }
525
526 if (!htab_create(ctx)) {
527 r = LIBUSB_ERROR_NO_MEM;
528 goto init_exit;
529 }
530
531 r = winusb_backend.init(ctx);
532 if (r != LIBUSB_SUCCESS)
533 goto init_exit;
534 winusb_backend_init = true;
535
536 r = usbdk_backend.init(ctx);
537 if (r == LIBUSB_SUCCESS) {
538 usbi_dbg(ctx, "UsbDk backend is available");
539 usbdk_available = true;
540 } else {
541 usbi_info(ctx, "UsbDk backend is not available");
542 // Do not report this as an error
543 }
544 }
545
546 // By default, new contexts will use the WinUSB backend
547 priv->backend = &winusb_backend;
548
549 r = LIBUSB_ERROR_NO_MEM;
550
551 // Use an I/O completion port to manage all transfers for this context
552 priv->completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
553 if (priv->completion_port == NULL) {
554 usbi_err(ctx, "failed to create I/O completion port: %s", windows_error_str(0));
555 goto init_exit;
556 }
557
558 // And a dedicated thread to wait for I/O completions
559 priv->completion_port_thread = (HANDLE)_beginthreadex(NULL, 0, windows_iocp_thread, ctx, 0, NULL);
560 if (priv->completion_port_thread == NULL) {
561 usbi_err(ctx, "failed to create I/O completion port thread");
562 CloseHandle(priv->completion_port);
563 goto init_exit;
564 }
565
566 r = LIBUSB_SUCCESS;
567
568 init_exit: // Holds semaphore here
569 if ((init_count == 1) && (r != LIBUSB_SUCCESS)) { // First init failed?
570 if (usbdk_available) {
571 usbdk_backend.exit(ctx);
572 usbdk_available = false;
573 }
574 if (winusb_backend_init)
575 winusb_backend.exit(ctx);
576 htab_destroy();
577 --init_count;
578 }
579
580 return r;
581 }
582
windows_exit(struct libusb_context * ctx)583 static void windows_exit(struct libusb_context *ctx)
584 {
585 struct windows_context_priv *priv = usbi_get_context_priv(ctx);
586
587 // A NULL completion status will indicate to the thread that it is time to exit
588 if (!PostQueuedCompletionStatus(priv->completion_port, 0, (ULONG_PTR)ctx, NULL))
589 usbi_err(ctx, "failed to post I/O completion: %s", windows_error_str(0));
590
591 if (WaitForSingleObject(priv->completion_port_thread, INFINITE) == WAIT_FAILED)
592 usbi_err(ctx, "failed to wait for I/O completion port thread: %s", windows_error_str(0));
593
594 CloseHandle(priv->completion_port_thread);
595 CloseHandle(priv->completion_port);
596
597 // Only works if exits and inits are balanced exactly
598 if (--init_count == 0) { // Last exit
599 if (usbdk_available) {
600 usbdk_backend.exit(ctx);
601 usbdk_available = false;
602 }
603 winusb_backend.exit(ctx);
604 htab_destroy();
605 }
606 }
607
windows_set_option(struct libusb_context * ctx,enum libusb_option option,va_list ap)608 static int windows_set_option(struct libusb_context *ctx, enum libusb_option option, va_list ap)
609 {
610 struct windows_context_priv *priv = usbi_get_context_priv(ctx);
611
612 UNUSED(ap);
613
614 if (option == LIBUSB_OPTION_USE_USBDK) {
615 if (!usbdk_available) {
616 usbi_err(ctx, "UsbDk backend not available");
617 return LIBUSB_ERROR_NOT_FOUND;
618 }
619 usbi_dbg(ctx, "switching context %p to use UsbDk backend", ctx);
620 priv->backend = &usbdk_backend;
621 return LIBUSB_SUCCESS;
622 }
623
624 return LIBUSB_ERROR_NOT_SUPPORTED;
625 }
626
windows_get_device_list(struct libusb_context * ctx,struct discovered_devs ** discdevs)627 static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **discdevs)
628 {
629 struct windows_context_priv *priv = usbi_get_context_priv(ctx);
630 return priv->backend->get_device_list(ctx, discdevs);
631 }
632
windows_open(struct libusb_device_handle * dev_handle)633 static int windows_open(struct libusb_device_handle *dev_handle)
634 {
635 struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
636 struct windows_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle);
637
638 list_init(&handle_priv->active_transfers);
639 return priv->backend->open(dev_handle);
640 }
641
windows_close(struct libusb_device_handle * dev_handle)642 static void windows_close(struct libusb_device_handle *dev_handle)
643 {
644 struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
645 priv->backend->close(dev_handle);
646 }
647
windows_get_active_config_descriptor(struct libusb_device * dev,void * buffer,size_t len)648 static int windows_get_active_config_descriptor(struct libusb_device *dev,
649 void *buffer, size_t len)
650 {
651 struct windows_context_priv *priv = usbi_get_context_priv(DEVICE_CTX(dev));
652 return priv->backend->get_active_config_descriptor(dev, buffer, len);
653 }
654
windows_get_config_descriptor(struct libusb_device * dev,uint8_t config_index,void * buffer,size_t len)655 static int windows_get_config_descriptor(struct libusb_device *dev,
656 uint8_t config_index, void *buffer, size_t len)
657 {
658 struct windows_context_priv *priv = usbi_get_context_priv(DEVICE_CTX(dev));
659 return priv->backend->get_config_descriptor(dev, config_index, buffer, len);
660 }
661
windows_get_config_descriptor_by_value(struct libusb_device * dev,uint8_t bConfigurationValue,void ** buffer)662 static int windows_get_config_descriptor_by_value(struct libusb_device *dev,
663 uint8_t bConfigurationValue, void **buffer)
664 {
665 struct windows_context_priv *priv = usbi_get_context_priv(DEVICE_CTX(dev));
666 return priv->backend->get_config_descriptor_by_value(dev, bConfigurationValue, buffer);
667 }
668
windows_get_configuration(struct libusb_device_handle * dev_handle,uint8_t * config)669 static int windows_get_configuration(struct libusb_device_handle *dev_handle, uint8_t *config)
670 {
671 struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
672 return priv->backend->get_configuration(dev_handle, config);
673 }
674
windows_set_configuration(struct libusb_device_handle * dev_handle,int config)675 static int windows_set_configuration(struct libusb_device_handle *dev_handle, int config)
676 {
677 struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
678 if (config == -1)
679 config = 0;
680 return priv->backend->set_configuration(dev_handle, (uint8_t)config);
681 }
682
windows_claim_interface(struct libusb_device_handle * dev_handle,uint8_t interface_number)683 static int windows_claim_interface(struct libusb_device_handle *dev_handle, uint8_t interface_number)
684 {
685 struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
686 return priv->backend->claim_interface(dev_handle, interface_number);
687 }
688
windows_release_interface(struct libusb_device_handle * dev_handle,uint8_t interface_number)689 static int windows_release_interface(struct libusb_device_handle *dev_handle, uint8_t interface_number)
690 {
691 struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
692 return priv->backend->release_interface(dev_handle, interface_number);
693 }
694
windows_set_interface_altsetting(struct libusb_device_handle * dev_handle,uint8_t interface_number,uint8_t altsetting)695 static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle,
696 uint8_t interface_number, uint8_t altsetting)
697 {
698 struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
699 return priv->backend->set_interface_altsetting(dev_handle, interface_number, altsetting);
700 }
701
windows_clear_halt(struct libusb_device_handle * dev_handle,unsigned char endpoint)702 static int windows_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
703 {
704 struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
705 return priv->backend->clear_halt(dev_handle, endpoint);
706 }
707
windows_reset_device(struct libusb_device_handle * dev_handle)708 static int windows_reset_device(struct libusb_device_handle *dev_handle)
709 {
710 struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
711 return priv->backend->reset_device(dev_handle);
712 }
713
windows_destroy_device(struct libusb_device * dev)714 static void windows_destroy_device(struct libusb_device *dev)
715 {
716 struct windows_context_priv *priv = usbi_get_context_priv(DEVICE_CTX(dev));
717 priv->backend->destroy_device(dev);
718 }
719
windows_submit_transfer(struct usbi_transfer * itransfer)720 static int windows_submit_transfer(struct usbi_transfer *itransfer)
721 {
722 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
723 struct libusb_device_handle *dev_handle = transfer->dev_handle;
724 struct libusb_context *ctx = HANDLE_CTX(dev_handle);
725 struct windows_context_priv *priv = usbi_get_context_priv(ctx);
726 struct windows_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle);
727 struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
728 int r;
729
730 switch (transfer->type) {
731 case LIBUSB_TRANSFER_TYPE_CONTROL:
732 case LIBUSB_TRANSFER_TYPE_BULK:
733 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
734 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
735 break;
736 case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
737 usbi_warn(ctx, "bulk stream transfers are not yet supported on this platform");
738 return LIBUSB_ERROR_NOT_SUPPORTED;
739 default:
740 usbi_err(ctx, "unknown endpoint type %d", transfer->type);
741 return LIBUSB_ERROR_INVALID_PARAM;
742 }
743
744 if (transfer_priv->handle != NULL) {
745 usbi_err(ctx, "program assertion failed - transfer HANDLE is not NULL");
746 transfer_priv->handle = NULL;
747 }
748
749 // Add transfer to the device handle's list
750 usbi_mutex_lock(&dev_handle->lock);
751 list_add_tail(&transfer_priv->list, &handle_priv->active_transfers);
752 usbi_mutex_unlock(&dev_handle->lock);
753
754 r = priv->backend->submit_transfer(itransfer);
755 if (r != LIBUSB_SUCCESS) {
756 // Remove the unsuccessful transfer from the device handle's list
757 usbi_mutex_lock(&dev_handle->lock);
758 list_del(&transfer_priv->list);
759 usbi_mutex_unlock(&dev_handle->lock);
760
761 // Always call the backend's clear_transfer_priv() function on failure
762 priv->backend->clear_transfer_priv(itransfer);
763 transfer_priv->handle = NULL;
764 return r;
765 }
766
767 // The backend should set the HANDLE used for each submitted transfer
768 // by calling set_transfer_priv_handle()
769 if (transfer_priv->handle == NULL)
770 usbi_err(ctx, "program assertion failed - transfer HANDLE is NULL after transfer was submitted");
771
772 return r;
773 }
774
windows_cancel_transfer(struct usbi_transfer * itransfer)775 static int windows_cancel_transfer(struct usbi_transfer *itransfer)
776 {
777 struct windows_context_priv *priv = usbi_get_context_priv(ITRANSFER_CTX(itransfer));
778 struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
779
780 // Try CancelIoEx() on the transfer
781 // If that fails, fall back to the backend's cancel_transfer()
782 // function if it is available
783 if (CancelIoEx(transfer_priv->handle, &transfer_priv->overlapped))
784 return LIBUSB_SUCCESS;
785 else if (GetLastError() == ERROR_NOT_FOUND)
786 return LIBUSB_ERROR_NOT_FOUND;
787
788 if (priv->backend->cancel_transfer)
789 return priv->backend->cancel_transfer(itransfer);
790
791 usbi_warn(ITRANSFER_CTX(itransfer), "cancellation not supported for this transfer's driver");
792 return LIBUSB_ERROR_NOT_SUPPORTED;
793 }
794
windows_handle_transfer_completion(struct usbi_transfer * itransfer)795 static int windows_handle_transfer_completion(struct usbi_transfer *itransfer)
796 {
797 struct libusb_context *ctx = ITRANSFER_CTX(itransfer);
798 struct windows_context_priv *priv = usbi_get_context_priv(ctx);
799 const struct windows_backend *backend = priv->backend;
800 struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
801 enum libusb_transfer_status status, istatus;
802 DWORD result, bytes_transferred;
803
804 if (GetOverlappedResult(transfer_priv->handle, &transfer_priv->overlapped, &bytes_transferred, FALSE))
805 result = NO_ERROR;
806 else
807 result = GetLastError();
808
809 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
810 usbi_dbg(ctx, "handling transfer %p completion with errcode %lu, length %lu",
811 transfer, ULONG_CAST(result), ULONG_CAST(bytes_transferred));
812
813 switch (result) {
814 case NO_ERROR:
815 status = backend->copy_transfer_data(itransfer, bytes_transferred);
816 break;
817 case ERROR_GEN_FAILURE:
818 usbi_dbg(ctx, "detected endpoint stall");
819 status = LIBUSB_TRANSFER_STALL;
820 break;
821 case ERROR_SEM_TIMEOUT:
822 usbi_dbg(ctx, "detected semaphore timeout");
823 status = LIBUSB_TRANSFER_TIMED_OUT;
824 break;
825 case ERROR_OPERATION_ABORTED:
826 istatus = backend->copy_transfer_data(itransfer, bytes_transferred);
827 if (istatus != LIBUSB_TRANSFER_COMPLETED)
828 usbi_dbg(ctx, "failed to copy partial data in aborted operation: %d", (int)istatus);
829
830 usbi_dbg(ctx, "detected operation aborted");
831 status = LIBUSB_TRANSFER_CANCELLED;
832 break;
833 case ERROR_FILE_NOT_FOUND:
834 case ERROR_DEVICE_NOT_CONNECTED:
835 case ERROR_NO_SUCH_DEVICE:
836 usbi_dbg(ctx, "detected device removed");
837 status = LIBUSB_TRANSFER_NO_DEVICE;
838 break;
839 default:
840 usbi_err(ctx, "detected I/O error %lu: %s",
841 ULONG_CAST(result), windows_error_str(result));
842 status = LIBUSB_TRANSFER_ERROR;
843 break;
844 }
845
846 transfer_priv->handle = NULL;
847
848 // Backend-specific cleanup
849 backend->clear_transfer_priv(itransfer);
850
851 if (status == LIBUSB_TRANSFER_CANCELLED)
852 return usbi_handle_transfer_cancellation(itransfer);
853 else
854 return usbi_handle_transfer_completion(itransfer, status);
855 }
856
857 #ifndef HAVE_CLOCK_GETTIME
usbi_get_monotonic_time(struct timespec * tp)858 void usbi_get_monotonic_time(struct timespec *tp)
859 {
860 static LONG hires_counter_init;
861 static uint64_t hires_ticks_to_ps;
862 static uint64_t hires_frequency;
863 LARGE_INTEGER hires_counter;
864
865 if (InterlockedExchange(&hires_counter_init, 1L) == 0L) {
866 LARGE_INTEGER li_frequency;
867
868 // Microsoft says that the QueryPerformanceFrequency() and
869 // QueryPerformanceCounter() functions always succeed on XP and later
870 QueryPerformanceFrequency(&li_frequency);
871
872 // The hires frequency can go as high as 4 GHz, so we'll use a conversion
873 // to picoseconds to compute the tv_nsecs part
874 hires_frequency = li_frequency.QuadPart;
875 hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency;
876 }
877
878 QueryPerformanceCounter(&hires_counter);
879 tp->tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
880 tp->tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency) * hires_ticks_to_ps) / UINT64_C(1000));
881 }
882 #endif
883
884 // NB: MSVC6 does not support named initializers.
885 const struct usbi_os_backend usbi_backend = {
886 "Windows",
887 USBI_CAP_HAS_HID_ACCESS,
888 windows_init,
889 windows_exit,
890 windows_set_option,
891 windows_get_device_list,
892 NULL, /* hotplug_poll */
893 NULL, /* wrap_sys_device */
894 windows_open,
895 windows_close,
896 windows_get_active_config_descriptor,
897 windows_get_config_descriptor,
898 windows_get_config_descriptor_by_value,
899 windows_get_configuration,
900 windows_set_configuration,
901 windows_claim_interface,
902 windows_release_interface,
903 windows_set_interface_altsetting,
904 windows_clear_halt,
905 windows_reset_device,
906 NULL, /* alloc_streams */
907 NULL, /* free_streams */
908 NULL, /* dev_mem_alloc */
909 NULL, /* dev_mem_free */
910 NULL, /* kernel_driver_active */
911 NULL, /* detach_kernel_driver */
912 NULL, /* attach_kernel_driver */
913 windows_destroy_device,
914 windows_submit_transfer,
915 windows_cancel_transfer,
916 NULL, /* clear_transfer_priv */
917 NULL, /* handle_events */
918 windows_handle_transfer_completion,
919 sizeof(struct windows_context_priv),
920 sizeof(union windows_device_priv),
921 sizeof(struct windows_device_handle_priv),
922 sizeof(struct windows_transfer_priv),
923 };
924