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