Blame libusb/os/windows_nt_common.c

Packit Service b0a153
/*
Packit Service b0a153
 * windows backend for libusb 1.0
Packit Service b0a153
 * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
Packit Service b0a153
 * With contributions from Michael Plante, Orin Eman et al.
Packit Service b0a153
 * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
Packit Service b0a153
 * HID Reports IOCTLs inspired from HIDAPI by Alan Ott, Signal 11 Software
Packit Service b0a153
 * Hash table functions adapted from glibc, by Ulrich Drepper et al.
Packit Service b0a153
 * Major code testing contribution by Xiaofan Chen
Packit Service b0a153
 *
Packit Service b0a153
 * This library is free software; you can redistribute it and/or
Packit Service b0a153
 * modify it under the terms of the GNU Lesser General Public
Packit Service b0a153
 * License as published by the Free Software Foundation; either
Packit Service b0a153
 * version 2.1 of the License, or (at your option) any later version.
Packit Service b0a153
 *
Packit Service b0a153
 * This library is distributed in the hope that it will be useful,
Packit Service b0a153
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service b0a153
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service b0a153
 * Lesser General Public License for more details.
Packit Service b0a153
 *
Packit Service b0a153
 * You should have received a copy of the GNU Lesser General Public
Packit Service b0a153
 * License along with this library; if not, write to the Free Software
Packit Service b0a153
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Packit Service b0a153
 */
Packit Service b0a153
Packit Service b0a153
#include <config.h>
Packit Service b0a153
Packit Service b0a153
#include <inttypes.h>
Packit Service b0a153
#include <process.h>
Packit Service b0a153
#include <stdio.h>
Packit Service b0a153
Packit Service b0a153
#include "libusbi.h"
Packit Service b0a153
#include "windows_common.h"
Packit Service b0a153
#include "windows_nt_common.h"
Packit Service b0a153
Packit Service b0a153
// Public
Packit Service b0a153
BOOL (WINAPI *pCancelIoEx)(HANDLE, LPOVERLAPPED);
Packit Service b0a153
enum windows_version windows_version = WINDOWS_UNDEFINED;
Packit Service b0a153
Packit Service b0a153
 // Global variables for init/exit
Packit Service b0a153
static unsigned int init_count = 0;
Packit Service b0a153
static bool usbdk_available = false;
Packit Service b0a153
Packit Service b0a153
// Global variables for clock_gettime mechanism
Packit Service b0a153
static uint64_t hires_ticks_to_ps;
Packit Service b0a153
static uint64_t hires_frequency;
Packit Service b0a153
Packit Service b0a153
#define TIMER_REQUEST_RETRY_MS	100
Packit Service b0a153
#define WM_TIMER_REQUEST	(WM_USER + 1)
Packit Service b0a153
#define WM_TIMER_EXIT		(WM_USER + 2)
Packit Service b0a153
Packit Service b0a153
// used for monotonic clock_gettime()
Packit Service b0a153
struct timer_request {
Packit Service b0a153
	struct timespec *tp;
Packit Service b0a153
	HANDLE event;
Packit Service b0a153
};
Packit Service b0a153
Packit Service b0a153
// Timer thread
Packit Service b0a153
static HANDLE timer_thread = NULL;
Packit Service b0a153
static DWORD timer_thread_id = 0;
Packit Service b0a153
Packit Service b0a153
/* Kernel32 dependencies */
Packit Service b0a153
DLL_DECLARE_HANDLE(Kernel32);
Packit Service b0a153
/* This call is only available from XP SP2 */
Packit Service b0a153
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, IsWow64Process, (HANDLE, PBOOL));
Packit Service b0a153
Packit Service b0a153
/* User32 dependencies */
Packit Service b0a153
DLL_DECLARE_HANDLE(User32);
Packit Service b0a153
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, GetMessageA, (LPMSG, HWND, UINT, UINT));
Packit Service b0a153
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, PeekMessageA, (LPMSG, HWND, UINT, UINT, UINT));
Packit Service b0a153
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, PostThreadMessageA, (DWORD, UINT, WPARAM, LPARAM));
Packit Service b0a153
Packit Service b0a153
static unsigned __stdcall windows_clock_gettime_threaded(void *param);
Packit Service b0a153
Packit Service b0a153
/*
Packit Service b0a153
* Converts a windows error to human readable string
Packit Service b0a153
* uses retval as errorcode, or, if 0, use GetLastError()
Packit Service b0a153
*/
Packit Service b0a153
#if defined(ENABLE_LOGGING)
Packit Service b0a153
const char *windows_error_str(DWORD error_code)
Packit Service b0a153
{
Packit Service b0a153
	static char err_string[ERR_BUFFER_SIZE];
Packit Service b0a153
Packit Service b0a153
	DWORD size;
Packit Service b0a153
	int len;
Packit Service b0a153
Packit Service b0a153
	if (error_code == 0)
Packit Service b0a153
		error_code = GetLastError();
Packit Service b0a153
Packit Service b0a153
	len = sprintf(err_string, "[%u] ", (unsigned int)error_code);
Packit Service b0a153
Packit Service b0a153
	// Translate codes returned by SetupAPI. The ones we are dealing with are either
Packit Service b0a153
	// in 0x0000xxxx or 0xE000xxxx and can be distinguished from standard error codes.
Packit Service b0a153
	// See http://msdn.microsoft.com/en-us/library/windows/hardware/ff545011.aspx
Packit Service b0a153
	switch (error_code & 0xE0000000) {
Packit Service b0a153
	case 0:
Packit Service b0a153
		error_code = HRESULT_FROM_WIN32(error_code); // Still leaves ERROR_SUCCESS unmodified
Packit Service b0a153
		break;
Packit Service b0a153
	case 0xE0000000:
Packit Service b0a153
		error_code = 0x80000000 | (FACILITY_SETUPAPI << 16) | (error_code & 0x0000FFFF);
Packit Service b0a153
		break;
Packit Service b0a153
	default:
Packit Service b0a153
		break;
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	size = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
Packit Service b0a153
			NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
Packit Service b0a153
			&err_string[len], ERR_BUFFER_SIZE - len, NULL);
Packit Service b0a153
	if (size == 0) {
Packit Service b0a153
		DWORD format_error = GetLastError();
Packit Service b0a153
		if (format_error)
Packit Service b0a153
			snprintf(err_string, ERR_BUFFER_SIZE,
Packit Service b0a153
				"Windows error code %u (FormatMessage error code %u)",
Packit Service b0a153
				(unsigned int)error_code, (unsigned int)format_error);
Packit Service b0a153
		else
Packit Service b0a153
			snprintf(err_string, ERR_BUFFER_SIZE, "Unknown error code %u", (unsigned int)error_code);
Packit Service b0a153
	} else {
Packit Service b0a153
		// Remove CRLF from end of message, if present
Packit Service b0a153
		size_t pos = len + size - 2;
Packit Service b0a153
		if (err_string[pos] == '\r')
Packit Service b0a153
			err_string[pos] = '\0';
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	return err_string;
Packit Service b0a153
}
Packit Service b0a153
#endif
Packit Service b0a153
Packit Service b0a153
static inline struct windows_context_priv *_context_priv(struct libusb_context *ctx)
Packit Service b0a153
{
Packit Service b0a153
	return (struct windows_context_priv *)ctx->os_priv;
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
/* Hash table functions - modified From glibc 2.3.2:
Packit Service b0a153
   [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
Packit Service b0a153
   [Knuth]            The Art of Computer Programming, part 3 (6.4)  */
Packit Service b0a153
Packit Service b0a153
#define HTAB_SIZE 1021UL	// *MUST* be a prime number!!
Packit Service b0a153
Packit Service b0a153
typedef struct htab_entry {
Packit Service b0a153
	unsigned long used;
Packit Service b0a153
	char *str;
Packit Service b0a153
} htab_entry;
Packit Service b0a153
Packit Service b0a153
static htab_entry *htab_table = NULL;
Packit Service b0a153
static usbi_mutex_t htab_mutex;
Packit Service b0a153
static unsigned long htab_filled;
Packit Service b0a153
Packit Service b0a153
/* Before using the hash table we must allocate memory for it.
Packit Service b0a153
   We allocate one element more as the found prime number says.
Packit Service b0a153
   This is done for more effective indexing as explained in the
Packit Service b0a153
   comment for the hash function.  */
Packit Service b0a153
static bool htab_create(struct libusb_context *ctx)
Packit Service b0a153
{
Packit Service b0a153
	if (htab_table != NULL) {
Packit Service b0a153
		usbi_err(ctx, "hash table already allocated");
Packit Service b0a153
		return true;
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	// Create a mutex
Packit Service b0a153
	usbi_mutex_init(&htab_mutex);
Packit Service b0a153
Packit Service b0a153
	usbi_dbg("using %lu entries hash table", HTAB_SIZE);
Packit Service b0a153
	htab_filled = 0;
Packit Service b0a153
Packit Service b0a153
	// allocate memory and zero out.
Packit Service b0a153
	htab_table = calloc(HTAB_SIZE + 1, sizeof(htab_entry));
Packit Service b0a153
	if (htab_table == NULL) {
Packit Service b0a153
		usbi_err(ctx, "could not allocate space for hash table");
Packit Service b0a153
		return false;
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	return true;
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
/* After using the hash table it has to be destroyed.  */
Packit Service b0a153
static void htab_destroy(void)
Packit Service b0a153
{
Packit Service b0a153
	unsigned long i;
Packit Service b0a153
Packit Service b0a153
	if (htab_table == NULL)
Packit Service b0a153
		return;
Packit Service b0a153
Packit Service b0a153
	for (i = 0; i < HTAB_SIZE; i++)
Packit Service b0a153
		free(htab_table[i].str);
Packit Service b0a153
Packit Service b0a153
	safe_free(htab_table);
Packit Service b0a153
Packit Service b0a153
	usbi_mutex_destroy(&htab_mutex);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
/* This is the search function. It uses double hashing with open addressing.
Packit Service b0a153
   We use a trick to speed up the lookup. The table is created with one
Packit Service b0a153
   more element available. This enables us to use the index zero special.
Packit Service b0a153
   This index will never be used because we store the first hash index in
Packit Service b0a153
   the field used where zero means not used. Every other value means used.
Packit Service b0a153
   The used field can be used as a first fast comparison for equality of
Packit Service b0a153
   the stored and the parameter value. This helps to prevent unnecessary
Packit Service b0a153
   expensive calls of strcmp.  */
Packit Service b0a153
unsigned long htab_hash(const char *str)
Packit Service b0a153
{
Packit Service b0a153
	unsigned long hval, hval2;
Packit Service b0a153
	unsigned long idx;
Packit Service b0a153
	unsigned long r = 5381;
Packit Service b0a153
	int c;
Packit Service b0a153
	const char *sz = str;
Packit Service b0a153
Packit Service b0a153
	if (str == NULL)
Packit Service b0a153
		return 0;
Packit Service b0a153
Packit Service b0a153
	// Compute main hash value (algorithm suggested by Nokia)
Packit Service b0a153
	while ((c = *sz++) != 0)
Packit Service b0a153
		r = ((r << 5) + r) + c;
Packit Service b0a153
	if (r == 0)
Packit Service b0a153
		++r;
Packit Service b0a153
Packit Service b0a153
	// compute table hash: simply take the modulus
Packit Service b0a153
	hval = r % HTAB_SIZE;
Packit Service b0a153
	if (hval == 0)
Packit Service b0a153
		++hval;
Packit Service b0a153
Packit Service b0a153
	// Try the first index
Packit Service b0a153
	idx = hval;
Packit Service b0a153
Packit Service b0a153
	// Mutually exclusive access (R/W lock would be better)
Packit Service b0a153
	usbi_mutex_lock(&htab_mutex);
Packit Service b0a153
Packit Service b0a153
	if (htab_table[idx].used) {
Packit Service b0a153
		if ((htab_table[idx].used == hval) && (strcmp(str, htab_table[idx].str) == 0))
Packit Service b0a153
			goto out_unlock; // existing hash
Packit Service b0a153
Packit Service b0a153
		usbi_dbg("hash collision ('%s' vs '%s')", str, htab_table[idx].str);
Packit Service b0a153
Packit Service b0a153
		// Second hash function, as suggested in [Knuth]
Packit Service b0a153
		hval2 = 1 + hval % (HTAB_SIZE - 2);
Packit Service b0a153
Packit Service b0a153
		do {
Packit Service b0a153
			// Because size is prime this guarantees to step through all available indexes
Packit Service b0a153
			if (idx <= hval2)
Packit Service b0a153
				idx = HTAB_SIZE + idx - hval2;
Packit Service b0a153
			else
Packit Service b0a153
				idx -= hval2;
Packit Service b0a153
Packit Service b0a153
			// If we visited all entries leave the loop unsuccessfully
Packit Service b0a153
			if (idx == hval)
Packit Service b0a153
				break;
Packit Service b0a153
Packit Service b0a153
			// If entry is found use it.
Packit Service b0a153
			if ((htab_table[idx].used == hval) && (strcmp(str, htab_table[idx].str) == 0))
Packit Service b0a153
				goto out_unlock;
Packit Service b0a153
		} while (htab_table[idx].used);
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	// Not found => New entry
Packit Service b0a153
Packit Service b0a153
	// If the table is full return an error
Packit Service b0a153
	if (htab_filled >= HTAB_SIZE) {
Packit Service b0a153
		usbi_err(NULL, "hash table is full (%lu entries)", HTAB_SIZE);
Packit Service b0a153
		idx = 0;
Packit Service b0a153
		goto out_unlock;
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	htab_table[idx].str = _strdup(str);
Packit Service b0a153
	if (htab_table[idx].str == NULL) {
Packit Service b0a153
		usbi_err(NULL, "could not duplicate string for hash table");
Packit Service b0a153
		idx = 0;
Packit Service b0a153
		goto out_unlock;
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	htab_table[idx].used = hval;
Packit Service b0a153
	++htab_filled;
Packit Service b0a153
Packit Service b0a153
out_unlock:
Packit Service b0a153
	usbi_mutex_unlock(&htab_mutex);
Packit Service b0a153
Packit Service b0a153
	return idx;
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
/*
Packit Service b0a153
* Make a transfer complete synchronously
Packit Service b0a153
*/
Packit Service b0a153
void windows_force_sync_completion(OVERLAPPED *overlapped, ULONG size)
Packit Service b0a153
{
Packit Service b0a153
	overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
Packit Service b0a153
	overlapped->InternalHigh = size;
Packit Service b0a153
	SetEvent(overlapped->hEvent);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static BOOL windows_init_dlls(void)
Packit Service b0a153
{
Packit Service b0a153
	DLL_GET_HANDLE(Kernel32);
Packit Service b0a153
	DLL_LOAD_FUNC_PREFIXED(Kernel32, p, IsWow64Process, FALSE);
Packit Service b0a153
	pCancelIoEx = (BOOL (WINAPI *)(HANDLE, LPOVERLAPPED))
Packit Service b0a153
		GetProcAddress(DLL_HANDLE_NAME(Kernel32), "CancelIoEx");
Packit Service b0a153
	usbi_dbg("Will use CancelIo%s for I/O cancellation", pCancelIoEx ? "Ex" : "");
Packit Service b0a153
Packit Service b0a153
	DLL_GET_HANDLE(User32);
Packit Service b0a153
	DLL_LOAD_FUNC_PREFIXED(User32, p, GetMessageA, TRUE);
Packit Service b0a153
	DLL_LOAD_FUNC_PREFIXED(User32, p, PeekMessageA, TRUE);
Packit Service b0a153
	DLL_LOAD_FUNC_PREFIXED(User32, p, PostThreadMessageA, TRUE);
Packit Service b0a153
Packit Service b0a153
	return TRUE;
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static void windows_exit_dlls(void)
Packit Service b0a153
{
Packit Service b0a153
	DLL_FREE_HANDLE(Kernel32);
Packit Service b0a153
	DLL_FREE_HANDLE(User32);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static bool windows_init_clock(struct libusb_context *ctx)
Packit Service b0a153
{
Packit Service b0a153
	DWORD_PTR affinity, dummy;
Packit Service b0a153
	HANDLE event;
Packit Service b0a153
	LARGE_INTEGER li_frequency;
Packit Service b0a153
	int i;
Packit Service b0a153
Packit Service b0a153
	if (QueryPerformanceFrequency(&li_frequency)) {
Packit Service b0a153
		// The hires frequency can go as high as 4 GHz, so we'll use a conversion
Packit Service b0a153
		// to picoseconds to compute the tv_nsecs part in clock_gettime
Packit Service b0a153
		hires_frequency = li_frequency.QuadPart;
Packit Service b0a153
		hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency;
Packit Service b0a153
		usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency);
Packit Service b0a153
Packit Service b0a153
		// Because QueryPerformanceCounter might report different values when
Packit Service b0a153
		// running on different cores, we create a separate thread for the timer
Packit Service b0a153
		// calls, which we glue to the first available core always to prevent timing discrepancies.
Packit Service b0a153
		if (!GetProcessAffinityMask(GetCurrentProcess(), &affinity, &dummy) || (affinity == 0)) {
Packit Service b0a153
			usbi_err(ctx, "could not get process affinity: %s", windows_error_str(0));
Packit Service b0a153
			return false;
Packit Service b0a153
		}
Packit Service b0a153
Packit Service b0a153
		// The process affinity mask is a bitmask where each set bit represents a core on
Packit Service b0a153
		// which this process is allowed to run, so we find the first set bit
Packit Service b0a153
		for (i = 0; !(affinity & (DWORD_PTR)(1 << i)); i++);
Packit Service b0a153
		affinity = (DWORD_PTR)(1 << i);
Packit Service b0a153
Packit Service b0a153
		usbi_dbg("timer thread will run on core #%d", i);
Packit Service b0a153
Packit Service b0a153
		event = CreateEvent(NULL, FALSE, FALSE, NULL);
Packit Service b0a153
		if (event == NULL) {
Packit Service b0a153
			usbi_err(ctx, "could not create event: %s", windows_error_str(0));
Packit Service b0a153
			return false;
Packit Service b0a153
		}
Packit Service b0a153
Packit Service b0a153
		timer_thread = (HANDLE)_beginthreadex(NULL, 0, windows_clock_gettime_threaded, (void *)event,
Packit Service b0a153
				0, (unsigned int *)&timer_thread_id);
Packit Service b0a153
		if (timer_thread == NULL) {
Packit Service b0a153
			usbi_err(ctx, "unable to create timer thread - aborting");
Packit Service b0a153
			CloseHandle(event);
Packit Service b0a153
			return false;
Packit Service b0a153
		}
Packit Service b0a153
Packit Service b0a153
		if (!SetThreadAffinityMask(timer_thread, affinity))
Packit Service b0a153
			usbi_warn(ctx, "unable to set timer thread affinity, timer discrepancies may arise");
Packit Service b0a153
Packit Service b0a153
		// Wait for timer thread to init before continuing.
Packit Service b0a153
		if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) {
Packit Service b0a153
			usbi_err(ctx, "failed to wait for timer thread to become ready - aborting");
Packit Service b0a153
			CloseHandle(event);
Packit Service b0a153
			return false;
Packit Service b0a153
		}
Packit Service b0a153
Packit Service b0a153
		CloseHandle(event);
Packit Service b0a153
	} else {
Packit Service b0a153
		usbi_dbg("no hires timer available on this platform");
Packit Service b0a153
		hires_frequency = 0;
Packit Service b0a153
		hires_ticks_to_ps = UINT64_C(0);
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	return true;
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static void windows_destroy_clock(void)
Packit Service b0a153
{
Packit Service b0a153
	if (timer_thread) {
Packit Service b0a153
		// actually the signal to quit the thread.
Packit Service b0a153
		if (!pPostThreadMessageA(timer_thread_id, WM_TIMER_EXIT, 0, 0)
Packit Service b0a153
				|| (WaitForSingleObject(timer_thread, INFINITE) != WAIT_OBJECT_0)) {
Packit Service b0a153
			usbi_dbg("could not wait for timer thread to quit");
Packit Service b0a153
			TerminateThread(timer_thread, 1);
Packit Service b0a153
			// shouldn't happen, but we're destroying
Packit Service b0a153
			// all objects it might have held anyway.
Packit Service b0a153
		}
Packit Service b0a153
		CloseHandle(timer_thread);
Packit Service b0a153
		timer_thread = NULL;
Packit Service b0a153
		timer_thread_id = 0;
Packit Service b0a153
	}
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
/* Windows version detection */
Packit Service b0a153
static BOOL is_x64(void)
Packit Service b0a153
{
Packit Service b0a153
	BOOL ret = FALSE;
Packit Service b0a153
Packit Service b0a153
	// Detect if we're running a 32 or 64 bit system
Packit Service b0a153
	if (sizeof(uintptr_t) < 8) {
Packit Service b0a153
		if (pIsWow64Process != NULL)
Packit Service b0a153
			pIsWow64Process(GetCurrentProcess(), &ret;;
Packit Service b0a153
	} else {
Packit Service b0a153
		ret = TRUE;
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	return ret;
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static void get_windows_version(void)
Packit Service b0a153
{
Packit Service b0a153
	OSVERSIONINFOEXA vi, vi2;
Packit Service b0a153
	const char *arch, *w = NULL;
Packit Service b0a153
	unsigned major, minor, version;
Packit Service b0a153
	ULONGLONG major_equal, minor_equal;
Packit Service b0a153
	BOOL ws;
Packit Service b0a153
Packit Service b0a153
	windows_version = WINDOWS_UNDEFINED;
Packit Service b0a153
Packit Service b0a153
	memset(&vi, 0, sizeof(vi));
Packit Service b0a153
	vi.dwOSVersionInfoSize = sizeof(vi);
Packit Service b0a153
	if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
Packit Service b0a153
		memset(&vi, 0, sizeof(vi));
Packit Service b0a153
		vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
Packit Service b0a153
		if (!GetVersionExA((OSVERSIONINFOA *)&vi))
Packit Service b0a153
			return;
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT)
Packit Service b0a153
		return;
Packit Service b0a153
Packit Service b0a153
	if ((vi.dwMajorVersion > 6) || ((vi.dwMajorVersion == 6) && (vi.dwMinorVersion >= 2))) {
Packit Service b0a153
		// Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the actual OS version
Packit Service b0a153
		// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
Packit Service b0a153
Packit Service b0a153
		major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
Packit Service b0a153
		for (major = vi.dwMajorVersion; major <= 9; major++) {
Packit Service b0a153
			memset(&vi2, 0, sizeof(vi2));
Packit Service b0a153
			vi2.dwOSVersionInfoSize = sizeof(vi2);
Packit Service b0a153
			vi2.dwMajorVersion = major;
Packit Service b0a153
			if (!VerifyVersionInfoA(&vi2, VER_MAJORVERSION, major_equal))
Packit Service b0a153
				continue;
Packit Service b0a153
Packit Service b0a153
			if (vi.dwMajorVersion < major) {
Packit Service b0a153
				vi.dwMajorVersion = major;
Packit Service b0a153
				vi.dwMinorVersion = 0;
Packit Service b0a153
			}
Packit Service b0a153
Packit Service b0a153
			minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL);
Packit Service b0a153
			for (minor = vi.dwMinorVersion; minor <= 9; minor++) {
Packit Service b0a153
				memset(&vi2, 0, sizeof(vi2));
Packit Service b0a153
				vi2.dwOSVersionInfoSize = sizeof(vi2);
Packit Service b0a153
				vi2.dwMinorVersion = minor;
Packit Service b0a153
				if (!VerifyVersionInfoA(&vi2, VER_MINORVERSION, minor_equal))
Packit Service b0a153
					continue;
Packit Service b0a153
Packit Service b0a153
				vi.dwMinorVersion = minor;
Packit Service b0a153
				break;
Packit Service b0a153
			}
Packit Service b0a153
Packit Service b0a153
			break;
Packit Service b0a153
		}
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	if ((vi.dwMajorVersion > 0xf) || (vi.dwMinorVersion > 0xf))
Packit Service b0a153
		return;
Packit Service b0a153
Packit Service b0a153
	ws = (vi.wProductType <= VER_NT_WORKSTATION);
Packit Service b0a153
	version = vi.dwMajorVersion << 4 | vi.dwMinorVersion;
Packit Service b0a153
	switch (version) {
Packit Service b0a153
	case 0x50: windows_version = WINDOWS_2000;  w = "2000";	break;
Packit Service b0a153
	case 0x51: windows_version = WINDOWS_XP;    w = "XP";	break;
Packit Service b0a153
	case 0x52: windows_version = WINDOWS_2003;  w = "2003";	break;
Packit Service b0a153
	case 0x60: windows_version = WINDOWS_VISTA; w = (ws ? "Vista" : "2008");  break;
Packit Service b0a153
	case 0x61: windows_version = WINDOWS_7;	    w = (ws ? "7" : "2008_R2");	  break;
Packit Service b0a153
	case 0x62: windows_version = WINDOWS_8;	    w = (ws ? "8" : "2012");	  break;
Packit Service b0a153
	case 0x63: windows_version = WINDOWS_8_1;   w = (ws ? "8.1" : "2012_R2"); break;
Packit Service b0a153
	case 0x64: // Early Windows 10 Insider Previews and Windows Server 2017 Technical Preview 1 used version 6.4
Packit Service b0a153
	case 0xA0: windows_version = WINDOWS_10;    w = (ws ? "10" : "2016");	  break;
Packit Service b0a153
	default:
Packit Service b0a153
		if (version < 0x50) {
Packit Service b0a153
			return;
Packit Service b0a153
		} else {
Packit Service b0a153
			windows_version = WINDOWS_11_OR_LATER;
Packit Service b0a153
			w = "11 or later";
Packit Service b0a153
		}
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	arch = is_x64() ? "64-bit" : "32-bit";
Packit Service b0a153
Packit Service b0a153
	if (vi.wServicePackMinor)
Packit Service b0a153
		usbi_dbg("Windows %s SP%u.%u %s", w, vi.wServicePackMajor, vi.wServicePackMinor, arch);
Packit Service b0a153
	else if (vi.wServicePackMajor)
Packit Service b0a153
		usbi_dbg("Windows %s SP%u %s", w, vi.wServicePackMajor, arch);
Packit Service b0a153
	else
Packit Service b0a153
		usbi_dbg("Windows %s %s", w, arch);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
/*
Packit Service b0a153
* Monotonic and real time functions
Packit Service b0a153
*/
Packit Service b0a153
static unsigned __stdcall windows_clock_gettime_threaded(void *param)
Packit Service b0a153
{
Packit Service b0a153
	struct timer_request *request;
Packit Service b0a153
	LARGE_INTEGER hires_counter;
Packit Service b0a153
	MSG msg;
Packit Service b0a153
Packit Service b0a153
	// The following call will create this thread's message queue
Packit Service b0a153
	// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms644946.aspx
Packit Service b0a153
	pPeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
Packit Service b0a153
Packit Service b0a153
	// Signal windows_init_clock() that we're ready to service requests
Packit Service b0a153
	if (!SetEvent((HANDLE)param))
Packit Service b0a153
		usbi_dbg("SetEvent failed for timer init event: %s", windows_error_str(0));
Packit Service b0a153
	param = NULL;
Packit Service b0a153
Packit Service b0a153
	// Main loop - wait for requests
Packit Service b0a153
	while (1) {
Packit Service b0a153
		if (pGetMessageA(&msg, NULL, WM_TIMER_REQUEST, WM_TIMER_EXIT) == -1) {
Packit Service b0a153
			usbi_err(NULL, "GetMessage failed for timer thread: %s", windows_error_str(0));
Packit Service b0a153
			return 1;
Packit Service b0a153
		}
Packit Service b0a153
Packit Service b0a153
		switch (msg.message) {
Packit Service b0a153
		case WM_TIMER_REQUEST:
Packit Service b0a153
			// Requests to this thread are for hires always
Packit Service b0a153
			// Microsoft says that this function always succeeds on XP and later
Packit Service b0a153
			// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms644904.aspx
Packit Service b0a153
			request = (struct timer_request *)msg.lParam;
Packit Service b0a153
			QueryPerformanceCounter(&hires_counter);
Packit Service b0a153
			request->tp->tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
Packit Service b0a153
			request->tp->tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency) / 1000) * hires_ticks_to_ps);
Packit Service b0a153
			if (!SetEvent(request->event))
Packit Service b0a153
				usbi_err(NULL, "SetEvent failed for timer request: %s", windows_error_str(0));
Packit Service b0a153
			break;
Packit Service b0a153
		case WM_TIMER_EXIT:
Packit Service b0a153
			usbi_dbg("timer thread quitting");
Packit Service b0a153
			return 0;
Packit Service b0a153
		}
Packit Service b0a153
	}
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static void windows_transfer_callback(const struct windows_backend *backend,
Packit Service b0a153
	struct usbi_transfer *itransfer, DWORD io_result, DWORD io_size)
Packit Service b0a153
{
Packit Service b0a153
	int status, istatus;
Packit Service b0a153
Packit Service b0a153
	usbi_dbg("handling I/O completion with errcode %u, size %u", (unsigned int)io_result, (unsigned int)io_size);
Packit Service b0a153
Packit Service b0a153
	switch (io_result) {
Packit Service b0a153
	case NO_ERROR:
Packit Service b0a153
		status = backend->copy_transfer_data(itransfer, (uint32_t)io_size);
Packit Service b0a153
		break;
Packit Service b0a153
	case ERROR_GEN_FAILURE:
Packit Service b0a153
		usbi_dbg("detected endpoint stall");
Packit Service b0a153
		status = LIBUSB_TRANSFER_STALL;
Packit Service b0a153
		break;
Packit Service b0a153
	case ERROR_SEM_TIMEOUT:
Packit Service b0a153
		usbi_dbg("detected semaphore timeout");
Packit Service b0a153
		status = LIBUSB_TRANSFER_TIMED_OUT;
Packit Service b0a153
		break;
Packit Service b0a153
	case ERROR_OPERATION_ABORTED:
Packit Service b0a153
		istatus = backend->copy_transfer_data(itransfer, (uint32_t)io_size);
Packit Service b0a153
		if (istatus != LIBUSB_TRANSFER_COMPLETED)
Packit Service b0a153
			usbi_dbg("Failed to copy partial data in aborted operation: %d", istatus);
Packit Service b0a153
Packit Service b0a153
		usbi_dbg("detected operation aborted");
Packit Service b0a153
		status = LIBUSB_TRANSFER_CANCELLED;
Packit Service b0a153
		break;
Packit Service b0a153
	case ERROR_FILE_NOT_FOUND:
Packit Service b0a153
		usbi_dbg("detected device removed");
Packit Service b0a153
		status = LIBUSB_TRANSFER_NO_DEVICE;
Packit Service b0a153
		break;
Packit Service b0a153
	default:
Packit Service b0a153
		usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error %u: %s", (unsigned int)io_result, windows_error_str(io_result));
Packit Service b0a153
		status = LIBUSB_TRANSFER_ERROR;
Packit Service b0a153
		break;
Packit Service b0a153
	}
Packit Service b0a153
	backend->clear_transfer_priv(itransfer);	// Cancel polling
Packit Service b0a153
	if (status == LIBUSB_TRANSFER_CANCELLED)
Packit Service b0a153
		usbi_handle_transfer_cancellation(itransfer);
Packit Service b0a153
	else
Packit Service b0a153
		usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static void windows_handle_callback(const struct windows_backend *backend,
Packit Service b0a153
	struct usbi_transfer *itransfer, DWORD io_result, DWORD io_size)
Packit Service b0a153
{
Packit Service b0a153
	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
Packit Service b0a153
Packit Service b0a153
	switch (transfer->type) {
Packit Service b0a153
	case LIBUSB_TRANSFER_TYPE_CONTROL:
Packit Service b0a153
	case LIBUSB_TRANSFER_TYPE_BULK:
Packit Service b0a153
	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
Packit Service b0a153
	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
Packit Service b0a153
		windows_transfer_callback(backend, itransfer, io_result, io_size);
Packit Service b0a153
		break;
Packit Service b0a153
	case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
Packit Service b0a153
		usbi_warn(ITRANSFER_CTX(itransfer), "bulk stream transfers are not yet supported on this platform");
Packit Service b0a153
		break;
Packit Service b0a153
	default:
Packit Service b0a153
		usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
Packit Service b0a153
	}
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_init(struct libusb_context *ctx)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(ctx);
Packit Service b0a153
	HANDLE semaphore;
Packit Service b0a153
	char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
Packit Service b0a153
	int r = LIBUSB_ERROR_OTHER;
Packit Service b0a153
	bool winusb_backend_init = false;
Packit Service b0a153
Packit Service b0a153
	sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF));
Packit Service b0a153
	semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name);
Packit Service b0a153
	if (semaphore == NULL) {
Packit Service b0a153
		usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0));
Packit Service b0a153
		return LIBUSB_ERROR_NO_MEM;
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	// A successful wait brings our semaphore count to 0 (unsignaled)
Packit Service b0a153
	// => any concurent wait stalls until the semaphore's release
Packit Service b0a153
	if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
Packit Service b0a153
		usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0));
Packit Service b0a153
		CloseHandle(semaphore);
Packit Service b0a153
		return LIBUSB_ERROR_NO_MEM;
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	// NB: concurrent usage supposes that init calls are equally balanced with
Packit Service b0a153
	// exit calls. If init is called more than exit, we will not exit properly
Packit Service b0a153
	if (++init_count == 1) { // First init?
Packit Service b0a153
		// Load DLL imports
Packit Service b0a153
		if (!windows_init_dlls()) {
Packit Service b0a153
			usbi_err(ctx, "could not resolve DLL functions");
Packit Service b0a153
			goto init_exit;
Packit Service b0a153
		}
Packit Service b0a153
Packit Service b0a153
		get_windows_version();
Packit Service b0a153
Packit Service b0a153
		if (windows_version == WINDOWS_UNDEFINED) {
Packit Service b0a153
			usbi_err(ctx, "failed to detect Windows version");
Packit Service b0a153
			r = LIBUSB_ERROR_NOT_SUPPORTED;
Packit Service b0a153
			goto init_exit;
Packit Service b0a153
		}
Packit Service b0a153
Packit Service b0a153
		if (!windows_init_clock(ctx))
Packit Service b0a153
			goto init_exit;
Packit Service b0a153
Packit Service b0a153
		if (!htab_create(ctx))
Packit Service b0a153
			goto init_exit;
Packit Service b0a153
Packit Service b0a153
		r = winusb_backend.init(ctx);
Packit Service b0a153
		if (r != LIBUSB_SUCCESS)
Packit Service b0a153
			goto init_exit;
Packit Service b0a153
		winusb_backend_init = true;
Packit Service b0a153
Packit Service b0a153
		r = usbdk_backend.init(ctx);
Packit Service b0a153
		if (r == LIBUSB_SUCCESS) {
Packit Service b0a153
			usbi_dbg("UsbDk backend is available");
Packit Service b0a153
			usbdk_available = true;
Packit Service b0a153
		} else {
Packit Service b0a153
			usbi_info(ctx, "UsbDk backend is not available");
Packit Service b0a153
			// Do not report this as an error
Packit Service b0a153
			r = LIBUSB_SUCCESS;
Packit Service b0a153
		}
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	// By default, new contexts will use the WinUSB backend
Packit Service b0a153
	priv->backend = &winusb_backend;
Packit Service b0a153
Packit Service b0a153
	r = LIBUSB_SUCCESS;
Packit Service b0a153
Packit Service b0a153
init_exit: // Holds semaphore here
Packit Service b0a153
	if ((init_count == 1) && (r != LIBUSB_SUCCESS)) { // First init failed?
Packit Service b0a153
		if (winusb_backend_init)
Packit Service b0a153
			winusb_backend.exit(ctx);
Packit Service b0a153
		htab_destroy();
Packit Service b0a153
		windows_destroy_clock();
Packit Service b0a153
		windows_exit_dlls();
Packit Service b0a153
		--init_count;
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
Packit Service b0a153
	CloseHandle(semaphore);
Packit Service b0a153
	return r;
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static void windows_exit(struct libusb_context *ctx)
Packit Service b0a153
{
Packit Service b0a153
	HANDLE semaphore;
Packit Service b0a153
	char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
Packit Service b0a153
	UNUSED(ctx);
Packit Service b0a153
Packit Service b0a153
	sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF));
Packit Service b0a153
	semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name);
Packit Service b0a153
	if (semaphore == NULL)
Packit Service b0a153
		return;
Packit Service b0a153
Packit Service b0a153
	// A successful wait brings our semaphore count to 0 (unsignaled)
Packit Service b0a153
	// => any concurent wait stalls until the semaphore release
Packit Service b0a153
	if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
Packit Service b0a153
		CloseHandle(semaphore);
Packit Service b0a153
		return;
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	// Only works if exits and inits are balanced exactly
Packit Service b0a153
	if (--init_count == 0) { // Last exit
Packit Service b0a153
		if (usbdk_available) {
Packit Service b0a153
			usbdk_backend.exit(ctx);
Packit Service b0a153
			usbdk_available = false;
Packit Service b0a153
		}
Packit Service b0a153
		winusb_backend.exit(ctx);
Packit Service b0a153
		htab_destroy();
Packit Service b0a153
		windows_destroy_clock();
Packit Service b0a153
		windows_exit_dlls();
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
	ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
Packit Service b0a153
	CloseHandle(semaphore);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_set_option(struct libusb_context *ctx, enum libusb_option option, va_list ap)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(ctx);
Packit Service b0a153
Packit Service b0a153
	UNUSED(ap);
Packit Service b0a153
Packit Service b0a153
	switch (option) {
Packit Service b0a153
	case LIBUSB_OPTION_USE_USBDK:
Packit Service b0a153
		if (usbdk_available) {
Packit Service b0a153
			usbi_dbg("switching context %p to use UsbDk backend", ctx);
Packit Service b0a153
			priv->backend = &usbdk_backend;
Packit Service b0a153
		} else {
Packit Service b0a153
			usbi_err(ctx, "UsbDk backend not available");
Packit Service b0a153
			return LIBUSB_ERROR_NOT_FOUND;
Packit Service b0a153
		}
Packit Service b0a153
		return LIBUSB_SUCCESS;
Packit Service b0a153
	default:
Packit Service b0a153
		return LIBUSB_ERROR_NOT_SUPPORTED;
Packit Service b0a153
	}
Packit Service b0a153
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **discdevs)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(ctx);
Packit Service b0a153
	return priv->backend->get_device_list(ctx, discdevs);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_open(struct libusb_device_handle *dev_handle)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
Packit Service b0a153
	return priv->backend->open(dev_handle);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static void windows_close(struct libusb_device_handle *dev_handle)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
Packit Service b0a153
	priv->backend->close(dev_handle);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_get_device_descriptor(struct libusb_device *dev,
Packit Service b0a153
	unsigned char *buffer, int *host_endian)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
Packit Service b0a153
	*host_endian = 0;
Packit Service b0a153
	return priv->backend->get_device_descriptor(dev, buffer);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_get_active_config_descriptor(struct libusb_device *dev,
Packit Service b0a153
	unsigned char *buffer, size_t len, int *host_endian)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
Packit Service b0a153
	*host_endian = 0;
Packit Service b0a153
	return priv->backend->get_active_config_descriptor(dev, buffer, len);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_get_config_descriptor(struct libusb_device *dev,
Packit Service b0a153
	uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
Packit Service b0a153
	*host_endian = 0;
Packit Service b0a153
	return priv->backend->get_config_descriptor(dev, config_index, buffer, len);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_get_config_descriptor_by_value(struct libusb_device *dev,
Packit Service b0a153
	uint8_t bConfigurationValue, unsigned char **buffer, int *host_endian)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
Packit Service b0a153
	*host_endian = 0;
Packit Service b0a153
	return priv->backend->get_config_descriptor_by_value(dev, bConfigurationValue, buffer);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_get_configuration(struct libusb_device_handle *dev_handle, int *config)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
Packit Service b0a153
	return priv->backend->get_configuration(dev_handle, config);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_set_configuration(struct libusb_device_handle *dev_handle, int config)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
Packit Service b0a153
	return priv->backend->set_configuration(dev_handle, config);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_claim_interface(struct libusb_device_handle *dev_handle, int interface_number)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
Packit Service b0a153
	return priv->backend->claim_interface(dev_handle, interface_number);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_release_interface(struct libusb_device_handle *dev_handle, int interface_number)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
Packit Service b0a153
	return priv->backend->release_interface(dev_handle, interface_number);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle,
Packit Service b0a153
	int interface_number, int altsetting)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
Packit Service b0a153
	return priv->backend->set_interface_altsetting(dev_handle, interface_number, altsetting);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
Packit Service b0a153
	return priv->backend->clear_halt(dev_handle, endpoint);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_reset_device(struct libusb_device_handle *dev_handle)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
Packit Service b0a153
	return priv->backend->reset_device(dev_handle);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static void windows_destroy_device(struct libusb_device *dev)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
Packit Service b0a153
	priv->backend->destroy_device(dev);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_submit_transfer(struct usbi_transfer *itransfer)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer));
Packit Service b0a153
	return priv->backend->submit_transfer(itransfer);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_cancel_transfer(struct usbi_transfer *itransfer)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer));
Packit Service b0a153
	return priv->backend->cancel_transfer(itransfer);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static void windows_clear_transfer_priv(struct usbi_transfer *itransfer)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer));
Packit Service b0a153
	priv->backend->clear_transfer_priv(itransfer);
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready)
Packit Service b0a153
{
Packit Service b0a153
	struct windows_context_priv *priv = _context_priv(ctx);
Packit Service b0a153
	struct usbi_transfer *itransfer;
Packit Service b0a153
	DWORD io_size, io_result;
Packit Service b0a153
	POLL_NFDS_TYPE i;
Packit Service b0a153
	bool found;
Packit Service b0a153
	int transfer_fd;
Packit Service b0a153
	int r = LIBUSB_SUCCESS;
Packit Service b0a153
Packit Service b0a153
	usbi_mutex_lock(&ctx->open_devs_lock);
Packit Service b0a153
	for (i = 0; i < nfds && num_ready > 0; i++) {
Packit Service b0a153
Packit Service b0a153
		usbi_dbg("checking fd %d with revents = %04x", fds[i].fd, fds[i].revents);
Packit Service b0a153
Packit Service b0a153
		if (!fds[i].revents)
Packit Service b0a153
			continue;
Packit Service b0a153
Packit Service b0a153
		num_ready--;
Packit Service b0a153
Packit Service b0a153
		// Because a Windows OVERLAPPED is used for poll emulation,
Packit Service b0a153
		// a pollable fd is created and stored with each transfer
Packit Service b0a153
		found = false;
Packit Service b0a153
		transfer_fd = -1;
Packit Service b0a153
		usbi_mutex_lock(&ctx->flying_transfers_lock);
Packit Service b0a153
		list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) {
Packit Service b0a153
			transfer_fd = priv->backend->get_transfer_fd(itransfer);
Packit Service b0a153
			if (transfer_fd == fds[i].fd) {
Packit Service b0a153
				found = true;
Packit Service b0a153
				break;
Packit Service b0a153
			}
Packit Service b0a153
		}
Packit Service b0a153
		usbi_mutex_unlock(&ctx->flying_transfers_lock);
Packit Service b0a153
Packit Service b0a153
		if (found) {
Packit Service b0a153
			priv->backend->get_overlapped_result(itransfer, &io_result, &io_size);
Packit Service b0a153
Packit Service b0a153
			usbi_remove_pollfd(ctx, transfer_fd);
Packit Service b0a153
Packit Service b0a153
			// let handle_callback free the event using the transfer wfd
Packit Service b0a153
			// If you don't use the transfer wfd, you run a risk of trying to free a
Packit Service b0a153
			// newly allocated wfd that took the place of the one from the transfer.
Packit Service b0a153
			windows_handle_callback(priv->backend, itransfer, io_result, io_size);
Packit Service b0a153
		} else {
Packit Service b0a153
			usbi_err(ctx, "could not find a matching transfer for fd %d", fds[i].fd);
Packit Service b0a153
			r = LIBUSB_ERROR_NOT_FOUND;
Packit Service b0a153
			break;
Packit Service b0a153
		}
Packit Service b0a153
	}
Packit Service b0a153
	usbi_mutex_unlock(&ctx->open_devs_lock);
Packit Service b0a153
Packit Service b0a153
	return r;
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
static int windows_clock_gettime(int clk_id, struct timespec *tp)
Packit Service b0a153
{
Packit Service b0a153
	struct timer_request request;
Packit Service b0a153
#if !defined(_MSC_VER) || (_MSC_VER < 1900)
Packit Service b0a153
	FILETIME filetime;
Packit Service b0a153
	ULARGE_INTEGER rtime;
Packit Service b0a153
#endif
Packit Service b0a153
	DWORD r;
Packit Service b0a153
Packit Service b0a153
	switch (clk_id) {
Packit Service b0a153
	case USBI_CLOCK_MONOTONIC:
Packit Service b0a153
		if (timer_thread) {
Packit Service b0a153
			request.tp = tp;
Packit Service b0a153
			request.event = CreateEvent(NULL, FALSE, FALSE, NULL);
Packit Service b0a153
			if (request.event == NULL)
Packit Service b0a153
				return LIBUSB_ERROR_NO_MEM;
Packit Service b0a153
Packit Service b0a153
			if (!pPostThreadMessageA(timer_thread_id, WM_TIMER_REQUEST, 0, (LPARAM)&request)) {
Packit Service b0a153
				usbi_err(NULL, "PostThreadMessage failed for timer thread: %s", windows_error_str(0));
Packit Service b0a153
				CloseHandle(request.event);
Packit Service b0a153
				return LIBUSB_ERROR_OTHER;
Packit Service b0a153
			}
Packit Service b0a153
Packit Service b0a153
			do {
Packit Service b0a153
				r = WaitForSingleObject(request.event, TIMER_REQUEST_RETRY_MS);
Packit Service b0a153
				if (r == WAIT_TIMEOUT)
Packit Service b0a153
					usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?");
Packit Service b0a153
				else if (r == WAIT_FAILED)
Packit Service b0a153
					usbi_err(NULL, "WaitForSingleObject failed: %s", windows_error_str(0));
Packit Service b0a153
			} while (r == WAIT_TIMEOUT);
Packit Service b0a153
			CloseHandle(request.event);
Packit Service b0a153
Packit Service b0a153
			if (r == WAIT_OBJECT_0)
Packit Service b0a153
				return LIBUSB_SUCCESS;
Packit Service b0a153
			else
Packit Service b0a153
				return LIBUSB_ERROR_OTHER;
Packit Service b0a153
		}
Packit Service b0a153
		// Fall through and return real-time if monotonic was not detected @ timer init
Packit Service b0a153
	case USBI_CLOCK_REALTIME:
Packit Service b0a153
#if defined(_MSC_VER) && (_MSC_VER >= 1900)
Packit Service b0a153
		timespec_get(tp, TIME_UTC);
Packit Service b0a153
#else
Packit Service b0a153
		// We follow http://msdn.microsoft.com/en-us/library/ms724928%28VS.85%29.aspx
Packit Service b0a153
		// with a predef epoch time to have an epoch that starts at 1970.01.01 00:00
Packit Service b0a153
		// Note however that our resolution is bounded by the Windows system time
Packit Service b0a153
		// functions and is at best of the order of 1 ms (or, usually, worse)
Packit Service b0a153
		GetSystemTimeAsFileTime(&filetime);
Packit Service b0a153
		rtime.LowPart = filetime.dwLowDateTime;
Packit Service b0a153
		rtime.HighPart = filetime.dwHighDateTime;
Packit Service b0a153
		rtime.QuadPart -= EPOCH_TIME;
Packit Service b0a153
		tp->tv_sec = (long)(rtime.QuadPart / 10000000);
Packit Service b0a153
		tp->tv_nsec = (long)((rtime.QuadPart % 10000000) * 100);
Packit Service b0a153
#endif
Packit Service b0a153
		return LIBUSB_SUCCESS;
Packit Service b0a153
	default:
Packit Service b0a153
		return LIBUSB_ERROR_INVALID_PARAM;
Packit Service b0a153
	}
Packit Service b0a153
}
Packit Service b0a153
Packit Service b0a153
// NB: MSVC6 does not support named initializers.
Packit Service b0a153
const struct usbi_os_backend usbi_backend = {
Packit Service b0a153
	"Windows",
Packit Service b0a153
	USBI_CAP_HAS_HID_ACCESS,
Packit Service b0a153
	windows_init,
Packit Service b0a153
	windows_exit,
Packit Service b0a153
	windows_set_option,
Packit Service b0a153
	windows_get_device_list,
Packit Service b0a153
	NULL,	/* hotplug_poll */
Packit Service b0a153
	NULL,	/* wrap_sys_device */
Packit Service b0a153
	windows_open,
Packit Service b0a153
	windows_close,
Packit Service b0a153
	windows_get_device_descriptor,
Packit Service b0a153
	windows_get_active_config_descriptor,
Packit Service b0a153
	windows_get_config_descriptor,
Packit Service b0a153
	windows_get_config_descriptor_by_value,
Packit Service b0a153
	windows_get_configuration,
Packit Service b0a153
	windows_set_configuration,
Packit Service b0a153
	windows_claim_interface,
Packit Service b0a153
	windows_release_interface,
Packit Service b0a153
	windows_set_interface_altsetting,
Packit Service b0a153
	windows_clear_halt,
Packit Service b0a153
	windows_reset_device,
Packit Service b0a153
	NULL,	/* alloc_streams */
Packit Service b0a153
	NULL,	/* free_streams */
Packit Service b0a153
	NULL,	/* dev_mem_alloc */
Packit Service b0a153
	NULL,	/* dev_mem_free */
Packit Service b0a153
	NULL,	/* kernel_driver_active */
Packit Service b0a153
	NULL,	/* detach_kernel_driver */
Packit Service b0a153
	NULL,	/* attach_kernel_driver */
Packit Service b0a153
	windows_destroy_device,
Packit Service b0a153
	windows_submit_transfer,
Packit Service b0a153
	windows_cancel_transfer,
Packit Service b0a153
	windows_clear_transfer_priv,
Packit Service b0a153
	windows_handle_events,
Packit Service b0a153
	NULL,	/* handle_transfer_completion */
Packit Service b0a153
	windows_clock_gettime,
Packit Service b0a153
	sizeof(struct windows_context_priv),
Packit Service b0a153
	sizeof(union windows_device_priv),
Packit Service b0a153
	sizeof(union windows_device_handle_priv),
Packit Service b0a153
	sizeof(union windows_transfer_priv),
Packit Service b0a153
};