WinCE: Add support for WinCE (sources)
diff --git a/examples/listdevs.c b/examples/listdevs.c
index 9f7e04e..8538bfa 100644
--- a/examples/listdevs.c
+++ b/examples/listdevs.c
@@ -18,7 +18,9 @@
  */
 
 #include <stdio.h>
+#if !defined(_WIN32_WCE)
 #include <sys/types.h>
+#endif
 
 #include "libusb.h"
 
diff --git a/examples/xusb.c b/examples/xusb.c
index 1117ace..707b58f 100644
--- a/examples/xusb.c
+++ b/examples/xusb.c
@@ -33,7 +33,7 @@
 #define msleep(msecs) usleep(1000*msecs)
 #endif
 
-#if !defined(_MSC_VER) || _MSC_VER<=1200
+#if !defined(_MSC_VER) || _MSC_VER<=1200 || defined(_WIN32_WCE)
 #define sscanf_s sscanf
 #endif
 
diff --git a/libusb/core.c b/libusb/core.c
index 77e21bf..5bface2 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -34,6 +34,10 @@
 #include <sys/time.h>
 #endif
 
+#if defined(OS_WINCE)
+#include "missing.h"	// getenv()
+#endif
+
 #include "libusbi.h"
 
 #if defined(OS_LINUX)
@@ -44,6 +48,8 @@
 const struct usbi_os_backend * const usbi_backend = &openbsd_backend;
 #elif defined(OS_WINDOWS)
 const struct usbi_os_backend * const usbi_backend = &windows_backend;
+#elif defined(OS_WINCE)
+const struct usbi_os_backend * const usbi_backend = &wince_backend;
 #else
 #error "Unsupported OS"
 #endif
@@ -1789,7 +1795,13 @@
 	UNUSED(tzp);
 
 	if(tp) {
+#if defined(OS_WINCE)
+		SYSTEMTIME st;
+		GetSystemTime(&st);
+		SystemTimeToFileTime(&st, &_now.ft);
+#else
 		GetSystemTimeAsFileTime (&_now.ft);
+#endif
 		tp->tv_usec=(long)((_now.ns100 / 10) % 1000000 );
 		tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000);
 	}
diff --git a/libusb/libusb-1.0.rc b/libusb/libusb-1.0.rc
index 86cb853..ae49757 100644
--- a/libusb/libusb-1.0.rc
+++ b/libusb/libusb-1.0.rc
@@ -5,7 +5,9 @@
  * The information can then be queried using standard APIs and can also be
  * viewed with utilities such as Windows Explorer.
  */
+#ifndef _WIN32_WCE
 #include "winresrc.h"
+#endif
 
 #include "version.h"
 #ifndef LIBUSB_VERSIONSTRING
diff --git a/libusb/libusb.h b/libusb/libusb.h
index da94c9b..c3b2f67 100644
--- a/libusb/libusb.h
+++ b/libusb/libusb.h
@@ -49,7 +49,9 @@
 #include <stdint.h>
 #endif
 
+#if !defined(_WIN32_WCE)
 #include <sys/types.h>
+#endif
 #include <time.h>
 #include <limits.h>
 
@@ -62,11 +64,15 @@
  * libusb_config_descriptor has an 'interface' member
  * As this can be problematic if you include windows.h after libusb.h
  * in your sources, we force windows.h to be included first. */
-#if defined(_WIN32) || defined(__CYGWIN__)
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
 #include <windows.h>
 #if defined(interface)
 #undef interface
 #endif
+#if defined(_WIN32_WCE)
+// Needed for "struct timeval" definition
+#include <winsock2.h>
+#endif
 #endif
 
 /** \def LIBUSB_CALL
@@ -101,7 +107,7 @@
  * return type, before the function name. See internal documentation for
  * API_EXPORTED.
  */
-#if defined(_WIN32) || defined(__CYGWIN__)
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
 #define LIBUSB_CALL WINAPI
 #else
 #define LIBUSB_CALL
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index 39e4c79..ac7f71c 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -195,7 +195,7 @@
 /* Internal abstraction for thread synchronization */
 #if defined(THREADS_POSIX)
 #include "os/threads_posix.h"
-#elif defined(OS_WINDOWS)
+#elif defined(OS_WINDOWS) || defined(OS_WINCE)
 #include <os/threads_windows.h>
 #endif
 
@@ -396,7 +396,7 @@
 #include <os/poll_windows.h>
 #endif
 
-#if defined(OS_WINDOWS) && !defined(__GCC__)
+#if (defined(OS_WINDOWS) || defined(OS_WINCE)) && !defined(__GCC__)
 #undef HAVE_GETTIMEOFDAY
 int usbi_gettimeofday(struct timeval *tp, void *tzp);
 #define LIBUSB_GETTIMEOFDAY_WIN32
@@ -905,5 +905,6 @@
 extern const struct usbi_os_backend darwin_backend;
 extern const struct usbi_os_backend openbsd_backend;
 extern const struct usbi_os_backend windows_backend;
+extern const struct usbi_os_backend wince_backend;
 
 #endif
diff --git a/libusb/os/wince_usb.c b/libusb/os/wince_usb.c
new file mode 100644
index 0000000..8f5bb92
--- /dev/null
+++ b/libusb/os/wince_usb.c
@@ -0,0 +1,1013 @@
+/*
+ * Windows CE backend for libusb 1.0
+ * Copyright (C) 2011-2012 RealVNC Ltd.
+ * Large portions taken from Windows backend, which is
+ * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com>
+ * With contributions from Michael Plante, Orin Eman et al.
+ * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
+ * Major code testing contribution by Xiaofan Chen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <libusbi.h>
+
+#include <stdint.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include "wince_usb.h"
+
+// Forward declares
+static int wince_clock_gettime(int clk_id, struct timespec *tp);
+unsigned __stdcall wince_clock_gettime_threaded(void* param);
+
+// Global variables
+uint64_t hires_frequency, hires_ticks_to_ps;
+int errno;
+const uint64_t epoch_time = UINT64_C(116444736000000000);       // 1970.01.01 00:00:000 in MS Filetime
+enum windows_version windows_version = WINDOWS_CE;
+static int concurrent_usage = -1;
+// Timer thread
+// NB: index 0 is for monotonic and 1 is for the thread exit event
+HANDLE timer_thread = NULL;
+HANDLE timer_mutex = NULL;
+struct timespec timer_tp;
+volatile LONG request_count[2] = {0, 1};	// last one must be > 0
+HANDLE timer_request[2] = { NULL, NULL };
+HANDLE timer_response = NULL;
+HANDLE driver_handle = INVALID_HANDLE_VALUE;
+
+/*
+ * Converts a windows error to human readable string
+ * uses retval as errorcode, or, if 0, use GetLastError()
+ */
+#if defined(ENABLE_LOGGING)
+static char* windows_error_str(uint32_t retval)
+{
+	static TCHAR wErr_string[ERR_BUFFER_SIZE];
+	static char err_string[ERR_BUFFER_SIZE];
+
+	DWORD size;
+	size_t i;
+	uint32_t error_code, format_error;
+
+	error_code = retval?retval:GetLastError();
+	
+	safe_stprintf(wErr_string, ERR_BUFFER_SIZE, _T("[%d] "), error_code);
+	
+	size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code,
+		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &wErr_string[safe_tcslen(wErr_string)],
+		ERR_BUFFER_SIZE - (DWORD)safe_tcslen(wErr_string), NULL);
+	if (size == 0) {
+		format_error = GetLastError();
+		if (format_error)
+			safe_stprintf(wErr_string, ERR_BUFFER_SIZE,
+				_T("Windows error code %u (FormatMessage error code %u)"), error_code, format_error);
+		else
+			safe_stprintf(wErr_string, ERR_BUFFER_SIZE, _T("Unknown error code %u"), error_code);
+	} else {
+		// Remove CR/LF terminators
+		for (i=safe_tcslen(wErr_string)-1; ((wErr_string[i]==0x0A) || (wErr_string[i]==0x0D)); i--) {
+			wErr_string[i] = 0;
+		}
+	}
+	if (WideCharToMultiByte(CP_ACP, 0, wErr_string, -1, err_string, ERR_BUFFER_SIZE, NULL, NULL) < 0)
+	{
+		strcpy(err_string, "Unable to convert error string");
+	}
+	return err_string;
+}
+#endif
+
+static struct wince_device_priv *_device_priv(struct libusb_device *dev)
+{
+        return (struct wince_device_priv *) dev->os_priv;
+}
+
+// ceusbkwrapper to libusb error code mapping
+static int translate_driver_error(int error) 
+{
+	switch (error) {
+		case ERROR_INVALID_PARAMETER:
+			return LIBUSB_ERROR_INVALID_PARAM;
+		case ERROR_CALL_NOT_IMPLEMENTED:
+		case ERROR_NOT_SUPPORTED:
+			return LIBUSB_ERROR_NOT_SUPPORTED;
+		case ERROR_NOT_ENOUGH_MEMORY:
+			return LIBUSB_ERROR_NO_MEM;
+		case ERROR_INVALID_HANDLE:
+			return LIBUSB_ERROR_NO_DEVICE;
+		case ERROR_BUSY:
+			return LIBUSB_ERROR_BUSY;
+
+		// Error codes that are either unexpected, or have 
+		// no suitable LIBUSB_ERROR equivilant.
+		case ERROR_CANCELLED:
+		case ERROR_INTERNAL_ERROR:
+		default:
+			return LIBUSB_ERROR_OTHER;
+	}
+}
+
+static int init_dllimports()
+{
+	DLL_LOAD(ceusbkwrapper.dll, UkwOpenDriver, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwGetDeviceList, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwReleaseDeviceList, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwGetDeviceAddress, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwGetDeviceDescriptor, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwGetConfigDescriptor, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwCloseDriver, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwCancelTransfer, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwIssueControlTransfer, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwClaimInterface, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwReleaseInterface, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwSetInterfaceAlternateSetting, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwClearHaltHost, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwClearHaltDevice, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwGetConfig, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwSetConfig, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwResetDevice, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwKernelDriverActive, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwAttachKernelDriver, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwDetachKernelDriver, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwIssueBulkTransfer, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwIsPipeHalted, TRUE);
+	return LIBUSB_SUCCESS;
+}
+
+static int init_device(struct libusb_device *dev, UKW_DEVICE drv_dev,
+					   unsigned char bus_addr, unsigned char dev_addr)
+{
+	struct wince_device_priv *priv = _device_priv(dev);
+	int r = LIBUSB_SUCCESS;
+
+	dev->bus_number = bus_addr;
+	dev->device_address = dev_addr;
+	priv->dev = drv_dev;
+
+	if (!UkwGetDeviceDescriptor(priv->dev, &(priv->desc))) {
+		r = translate_driver_error(GetLastError());
+	}
+	return r;
+}
+
+// Internal API functions
+static int wince_init(struct libusb_context *ctx)
+{
+	int i, r = LIBUSB_ERROR_OTHER;
+	HANDLE semaphore;
+	TCHAR sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID)
+
+	_stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)GetCurrentProcessId()&0xFFFFFFFF);
+	semaphore = CreateSemaphore(NULL, 1, 1, sem_name);
+	if (semaphore == NULL) {
+		usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0));
+		return LIBUSB_ERROR_NO_MEM;
+	}
+
+	// A successful wait brings our semaphore count to 0 (unsignaled)
+	// => any concurent wait stalls until the semaphore's release
+	if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
+		usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0));
+		CloseHandle(semaphore);
+		return LIBUSB_ERROR_NO_MEM;
+	}
+
+	// NB: concurrent usage supposes that init calls are equally balanced with
+	// exit calls. If init is called more than exit, we will not exit properly
+	if ( ++concurrent_usage == 0 ) {	// First init?
+		// Initialize pollable file descriptors
+		init_polling();
+
+		// Load DLL imports
+		if (init_dllimports() != LIBUSB_SUCCESS) {
+			usbi_err(ctx, "could not resolve DLL functions");
+			r = LIBUSB_ERROR_NOT_SUPPORTED;
+			goto init_exit;
+		}
+
+		// try to open a handle to the driver
+		driver_handle = UkwOpenDriver();
+		if (driver_handle == INVALID_HANDLE_VALUE) {
+			usbi_err(ctx, "could not connect to driver");
+			r = LIBUSB_ERROR_NOT_SUPPORTED;
+			goto init_exit;
+		}
+
+		// Windows CE doesn't have a way of specifying thread affinity, so this code
+		// just has  to hope QueryPerformanceCounter doesn't report different values when
+		// running on different cores.
+		r = LIBUSB_ERROR_NO_MEM;
+		for (i = 0; i < 2; i++) {
+			timer_request[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
+			if (timer_request[i] == NULL) {
+				usbi_err(ctx, "could not create timer request event %d - aborting", i);
+				goto init_exit;
+			}
+		}
+		timer_response = CreateSemaphore(NULL, 0, MAX_TIMER_SEMAPHORES, NULL);
+		if (timer_response == NULL) {
+			usbi_err(ctx, "could not create timer response semaphore - aborting");
+			goto init_exit;
+		}
+		timer_mutex = CreateMutex(NULL, FALSE, NULL);
+		if (timer_mutex == NULL) {
+			usbi_err(ctx, "could not create timer mutex - aborting");
+			goto init_exit;
+		}
+		timer_thread = CreateThread(NULL, 0, wince_clock_gettime_threaded, NULL, 0, NULL);
+		if (timer_thread == NULL) {
+			usbi_err(ctx, "Unable to create timer thread - aborting");
+			goto init_exit;
+		}
+	}
+	// At this stage, either we went through full init successfully, or didn't need to
+	r = LIBUSB_SUCCESS;
+
+init_exit: // Holds semaphore here.
+	if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed?
+		if (driver_handle != INVALID_HANDLE_VALUE) {
+			UkwCloseDriver(driver_handle);
+			driver_handle = INVALID_HANDLE_VALUE;
+		}
+		if (timer_thread) {
+			SetEvent(timer_request[1]); // actually the signal to quit the thread.
+			if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) {
+				usbi_warn(ctx, "could not wait for timer thread to quit");
+				TerminateThread(timer_thread, 1); // shouldn't happen, but we're destroying
+												  // all objects it might have held anyway.
+			}
+			CloseHandle(timer_thread);
+			timer_thread = NULL;
+		}
+		for (i = 0; i < 2; i++) {
+			if (timer_request[i]) {
+				CloseHandle(timer_request[i]);
+				timer_request[i] = NULL;
+			}
+		}
+		if (timer_response) {
+			CloseHandle(timer_response);
+			timer_response = NULL;
+		}
+		if (timer_mutex) {
+			CloseHandle(timer_mutex);
+			timer_mutex = NULL;
+		}
+	}
+
+	if (r != LIBUSB_SUCCESS)
+		--concurrent_usage; // Not expected to call libusb_exit if we failed.
+
+	ReleaseSemaphore(semaphore, 1, NULL);	// increase count back to 1
+	CloseHandle(semaphore);
+	return r;
+}
+
+static void wince_exit(void)
+{
+	int i;
+	HANDLE semaphore;
+	TCHAR sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID)
+
+	_stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)GetCurrentProcessId()&0xFFFFFFFF);
+	semaphore = CreateSemaphore(NULL, 1, 1, sem_name);
+	if (semaphore == NULL) {
+		return;
+	}
+
+	// A successful wait brings our semaphore count to 0 (unsignaled)
+	// => any concurent wait stalls until the semaphore release
+	if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
+		CloseHandle(semaphore);
+		return;
+	}
+
+	// Only works if exits and inits are balanced exactly
+	if (--concurrent_usage < 0) {	// Last exit
+		exit_polling();
+
+		if (timer_thread) {
+			SetEvent(timer_request[1]); // actually the signal to quit the thread.
+			if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) {
+				usbi_dbg("could not wait for timer thread to quit");
+				TerminateThread(timer_thread, 1);
+			}
+			CloseHandle(timer_thread);
+			timer_thread = NULL;
+		}
+		for (i = 0; i < 2; i++) {
+			if (timer_request[i]) {
+				CloseHandle(timer_request[i]);
+				timer_request[i] = NULL;
+			}
+		}
+		if (timer_response) {
+			CloseHandle(timer_response);
+			timer_response = NULL;
+		}
+		if (timer_mutex) {
+			CloseHandle(timer_mutex);
+			timer_mutex = NULL;
+		}
+		if (driver_handle != INVALID_HANDLE_VALUE) {
+			UkwCloseDriver(driver_handle);
+			driver_handle = INVALID_HANDLE_VALUE;
+		}
+	}
+
+	ReleaseSemaphore(semaphore, 1, NULL);	// increase count back to 1
+	CloseHandle(semaphore);
+}
+
+static int wince_get_device_list(
+	struct libusb_context *ctx,
+	struct discovered_devs **discdevs)
+{
+	UKW_DEVICE devices[MAX_DEVICE_COUNT];
+	struct discovered_devs * new_devices = *discdevs;
+	DWORD count = 0, i;
+	struct libusb_device *dev;
+	unsigned char bus_addr, dev_addr;
+	unsigned long session_id;
+	BOOL success, need_unref = FALSE;
+	DWORD release_list_offset = 0;
+	int r = LIBUSB_SUCCESS;
+
+	success = UkwGetDeviceList(driver_handle, devices, MAX_DEVICE_COUNT, &count);
+	if (!success) {
+		int libusbErr = translate_driver_error(GetLastError());
+		usbi_err(ctx, "could not get devices: %s", windows_error_str(0));
+		return libusbErr;
+	}
+	for(i = 0; i < count; ++i) {
+		release_list_offset = i;
+		success = UkwGetDeviceAddress(devices[i], &bus_addr, &dev_addr, &session_id);
+		if (!success) {
+			r = translate_driver_error(GetLastError());
+			usbi_err(ctx, "could not get device address for %d: %s", i, windows_error_str(0));
+			goto err_out;
+		}
+		dev = usbi_get_device_by_session_id(ctx, session_id);
+		if (dev) {
+			usbi_dbg("using existing device for %d/%d (session %ld)",
+					bus_addr, dev_addr, session_id);
+			// Release just this element in the device list (as we already hold a 
+			// reference to it).
+			UkwReleaseDeviceList(driver_handle, &devices[i], 1);
+			release_list_offset++;
+		} else {
+			usbi_dbg("allocating new device for %d/%d (session %ld)",
+					bus_addr, dev_addr, session_id);
+			dev = usbi_alloc_device(ctx, session_id);
+			if (!dev) {
+				r = LIBUSB_ERROR_NO_MEM;
+				goto err_out;
+			}
+			need_unref = TRUE;
+			r = init_device(dev, devices[i], bus_addr, dev_addr);
+			if (r < 0)
+				goto err_out;
+			r = usbi_sanitize_device(dev);
+			if (r < 0)
+				goto err_out;
+		}
+		new_devices = discovered_devs_append(new_devices, dev);
+		if (!discdevs) {
+			r = LIBUSB_ERROR_NO_MEM;
+			goto err_out;
+		}
+		need_unref = FALSE;
+	}
+	*discdevs = new_devices;
+	return r;
+err_out:
+	*discdevs = new_devices;
+	if (need_unref)
+		libusb_unref_device(dev);
+	// Release the remainder of the unprocessed device list.
+	// The devices added to new_devices already will still be passed up to libusb, 
+	// which can dispose of them at its leisure.
+	UkwReleaseDeviceList(driver_handle, &devices[release_list_offset], count - release_list_offset);
+	return r;
+}
+
+static int wince_open(struct libusb_device_handle *handle)
+{
+	// Nothing to do to open devices as a handle to it has
+	// been retrieved by wince_get_device_list
+	return LIBUSB_SUCCESS;
+}
+
+static void wince_close(struct libusb_device_handle *handle)
+{
+	// Nothing to do as wince_open does nothing.
+}
+
+static int wince_get_device_descriptor(
+   struct libusb_device *device,
+   unsigned char *buffer, int *host_endian)
+{
+	struct wince_device_priv *priv = _device_priv(device);
+
+	*host_endian = 1;
+	memcpy(buffer, &priv->desc, DEVICE_DESC_LENGTH);
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_get_active_config_descriptor(
+	struct libusb_device *device,
+	unsigned char *buffer, size_t len, int *host_endian)
+{
+	struct wince_device_priv *priv = _device_priv(device);
+	DWORD actualSize = len;
+	*host_endian = 1;
+	if (!UkwGetConfigDescriptor(priv->dev, UKW_ACTIVE_CONFIGURATION, buffer, len, &actualSize)) {
+		return translate_driver_error(GetLastError());
+	}
+	return actualSize;
+}
+
+static int wince_get_config_descriptor(
+	struct libusb_device *device,
+	uint8_t config_index,
+	unsigned char *buffer, size_t len, int *host_endian)
+{
+	struct wince_device_priv *priv = _device_priv(device);
+	DWORD actualSize = len;
+	*host_endian = 0;
+	if (!UkwGetConfigDescriptor(priv->dev, config_index, buffer, len, &actualSize)) {
+		return translate_driver_error(GetLastError());
+	}
+	return actualSize;
+}
+
+static int wince_get_configuration(
+   struct libusb_device_handle *handle,
+   int *config)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	UCHAR cv = 0;
+	if (!UkwGetConfig(priv->dev, &cv)) {
+		return translate_driver_error(GetLastError());
+	}
+	(*config) = cv;
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_set_configuration(
+	struct libusb_device_handle *handle,
+	int config)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	// Setting configuration 0 places the device in Address state.
+	// This should correspond to the "unconfigured state" required by
+	// libusb when the specified configuration is -1.
+	UCHAR cv = (config < 0) ? 0 : config;
+	if (!UkwSetConfig(priv->dev, cv)) {
+		return translate_driver_error(GetLastError());
+	}
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_claim_interface(
+	struct libusb_device_handle *handle,
+	int interface_number)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	if (!UkwClaimInterface(priv->dev, interface_number)) {
+		return translate_driver_error(GetLastError());
+	}
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_release_interface(
+	struct libusb_device_handle *handle,
+	int interface_number)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, 0)) {
+		return translate_driver_error(GetLastError());
+	}
+	if (!UkwReleaseInterface(priv->dev, interface_number)) {
+		return translate_driver_error(GetLastError());
+	}
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_set_interface_altsetting(
+	struct libusb_device_handle *handle,
+	int interface_number, int altsetting)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, altsetting)) {
+		return translate_driver_error(GetLastError());
+	}
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_clear_halt(
+	struct libusb_device_handle *handle,
+	unsigned char endpoint)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	if (!UkwClearHaltHost(priv->dev, endpoint)) {
+		return translate_driver_error(GetLastError());
+	}
+	if (!UkwClearHaltDevice(priv->dev, endpoint)) {
+		return translate_driver_error(GetLastError());
+	}
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_reset_device(
+	struct libusb_device_handle *handle)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	if (!UkwResetDevice(priv->dev)) {
+		return translate_driver_error(GetLastError());
+	}
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_kernel_driver_active(
+	struct libusb_device_handle *handle,
+	int interface_number)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	BOOL result = FALSE;
+	if (!UkwKernelDriverActive(priv->dev, interface_number, &result)) {
+		return translate_driver_error(GetLastError());
+	}
+	return result ? 1 : 0;
+}
+
+static int wince_detach_kernel_driver(
+	struct libusb_device_handle *handle,
+	int interface_number)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	if (!UkwDetachKernelDriver(priv->dev, interface_number)) {
+		return translate_driver_error(GetLastError());
+	}
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_attach_kernel_driver(
+	struct libusb_device_handle *handle,
+	int interface_number)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	if (!UkwAttachKernelDriver(priv->dev, interface_number)) {
+		return translate_driver_error(GetLastError());
+	}	
+	return LIBUSB_SUCCESS;
+}
+
+static void wince_destroy_device(
+	struct libusb_device *dev)
+{
+	struct wince_device_priv *priv = _device_priv(dev);
+	UkwReleaseDeviceList(driver_handle, &priv->dev, 1);
+}
+
+static void wince_clear_transfer_priv(
+	struct usbi_transfer *itransfer)
+{
+	struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
+	struct winfd wfd = fd_to_winfd(transfer_priv->pollable_fd.fd);
+	// No need to cancel transfer as it is either complete or abandoned
+	wfd.itransfer = NULL;
+	CloseHandle(wfd.handle);
+	usbi_free_fd(transfer_priv->pollable_fd.fd);
+}
+
+static int wince_cancel_transfer(
+	struct usbi_transfer *itransfer)
+{
+	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+	struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+	struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
+	
+	if (!UkwCancelTransfer(priv->dev, transfer_priv->pollable_fd.overlapped, UKW_TF_NO_WAIT)) {
+		return translate_driver_error(GetLastError());
+	}
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_submit_control_or_bulk_transfer(struct usbi_transfer *itransfer)
+{
+	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+	struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+	struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
+	struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+	BOOL direction_in, ret;
+	struct winfd wfd;
+	DWORD flags;
+	HANDLE eventHandle;
+	PUKW_CONTROL_HEADER setup = NULL;
+	const BOOL control_transfer = transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL;
+
+	transfer_priv->pollable_fd = INVALID_WINFD;
+	if (control_transfer) {
+		setup = (PUKW_CONTROL_HEADER) transfer->buffer;
+		direction_in = setup->bmRequestType & LIBUSB_ENDPOINT_IN;
+	} else {
+		direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN;
+	}
+	flags = direction_in ? UKW_TF_IN_TRANSFER : UKW_TF_OUT_TRANSFER;
+	flags |= UKW_TF_SHORT_TRANSFER_OK;
+
+	eventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
+	if (eventHandle == NULL) {
+		usbi_err(ctx, "Failed to create event for async transfer");
+		return LIBUSB_ERROR_NO_MEM;
+	}
+
+	wfd = usbi_create_fd(eventHandle, direction_in ? RW_READ : RW_WRITE, itransfer, &wince_cancel_transfer);
+	if (wfd.fd < 0) {
+		CloseHandle(eventHandle);
+		return LIBUSB_ERROR_NO_MEM;
+	}
+
+	transfer_priv->pollable_fd = wfd;
+	if (control_transfer) {
+		// Split out control setup header and data buffer
+		DWORD bufLen = transfer->length - sizeof(UKW_CONTROL_HEADER);
+		PVOID buf = (PVOID) &transfer->buffer[sizeof(UKW_CONTROL_HEADER)];
+
+		ret = UkwIssueControlTransfer(priv->dev, flags, setup, buf, bufLen, &transfer->actual_length, wfd.overlapped);
+	} else {
+		ret = UkwIssueBulkTransfer(priv->dev, flags, transfer->endpoint, transfer->buffer, 
+			transfer->length, &transfer->actual_length, wfd.overlapped);
+	}
+	if (!ret) {
+		int libusbErr = translate_driver_error(GetLastError());
+		usbi_err(ctx, "UkwIssue%sTransfer failed: error %d",
+			control_transfer ? "Control" : "Bulk", GetLastError());
+		wince_clear_transfer_priv(itransfer);
+		return libusbErr;
+	}
+	usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, direction_in ? POLLIN : POLLOUT);
+	itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
+
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_submit_iso_transfer(struct usbi_transfer *itransfer)
+{
+	return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+static int wince_submit_transfer(
+	struct usbi_transfer *itransfer)
+{
+	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+
+	switch (transfer->type) {
+	case LIBUSB_TRANSFER_TYPE_CONTROL:
+	case LIBUSB_TRANSFER_TYPE_BULK:
+	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+		return wince_submit_control_or_bulk_transfer(itransfer);
+	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+		return wince_submit_iso_transfer(itransfer);
+	default:
+		usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
+		return LIBUSB_ERROR_INVALID_PARAM;
+	}
+}
+
+static void wince_transfer_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
+{
+	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+	struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
+	struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+	int status;
+
+	usbi_dbg("handling I/O completion with errcode %d", io_result);
+
+	if (io_result == ERROR_NOT_SUPPORTED) {
+		/* The WinCE USB layer (and therefore the USB Kernel Wrapper Driver) will report
+		 * USB_ERROR_STALL/ERROR_NOT_SUPPORTED in situations where the endpoint isn't actually
+		 * stalled.
+		 *
+		 * One example of this is that some devices will occasionally fail to reply to an IN
+		 * token. The WinCE USB layer carries on with the transaction until it is completed
+		 * (or cancelled) but then completes it with USB_ERROR_STALL.
+		 *
+		 * This code therefore needs to confirm that there really is a stall error, but checking
+		 * the pipe status and requesting the endpoint status from the device.
+		 */
+		BOOL halted = FALSE;
+		usbi_dbg("checking I/O completion with errcode ERROR_NOT_SUPPORTED is really a stall");
+		if (UkwIsPipeHalted(priv->dev, transfer->endpoint, &halted)) {
+			/* The host side doesn't think the endpoint is halted, so check with the device if
+			 * it is stalled.
+			 *
+			 * So form a GET_STATUS control request. This is done synchronously,
+			 * which is a bit naughty, but this is a special corner case. */
+			WORD wStatus = 0;
+			DWORD written = 0;
+			UKW_CONTROL_HEADER ctrlHeader;
+			ctrlHeader.bmRequestType = LIBUSB_REQUEST_TYPE_STANDARD |
+				LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_ENDPOINT;
+			ctrlHeader.bRequest = LIBUSB_REQUEST_GET_STATUS;
+			ctrlHeader.wValue = 0;
+			ctrlHeader.wIndex = transfer->endpoint;
+			ctrlHeader.wLength = sizeof(wStatus);
+			if (UkwIssueControlTransfer(priv->dev,
+					UKW_TF_IN_TRANSFER | UKW_TF_SEND_TO_ENDPOINT,
+					&ctrlHeader, &wStatus, sizeof(wStatus), &written, NULL)) {
+				if (written == sizeof(wStatus) &&
+						(wStatus & STATUS_HALT_FLAG) == 0) {
+					if (!halted || UkwClearHaltHost(priv->dev, transfer->endpoint)) {
+						usbi_dbg("Endpoint doesn't appear to be stalled, overriding error with success");
+						io_result = ERROR_SUCCESS;
+					} else {
+						usbi_dbg("Endpoint does appear to be stalled, but the host is halted, changing error");
+						io_result = ERROR_IO_DEVICE;
+					}
+				}
+			}
+		}
+	}
+
+	switch(io_result) {
+	case ERROR_SUCCESS:
+		itransfer->transferred += io_size;
+		status = LIBUSB_TRANSFER_COMPLETED;
+		break;
+	case ERROR_CANCELLED:
+		usbi_dbg("detected transfer cancel");
+		status = LIBUSB_TRANSFER_CANCELLED;
+		break;
+	case ERROR_NOT_SUPPORTED:
+	case ERROR_GEN_FAILURE:
+		usbi_dbg("detected endpoint stall");
+		status = LIBUSB_TRANSFER_STALL;
+		break;
+	case ERROR_SEM_TIMEOUT:
+		usbi_dbg("detected semaphore timeout");
+		status = LIBUSB_TRANSFER_TIMED_OUT;
+		break;
+	case ERROR_OPERATION_ABORTED:
+		if (itransfer->flags & USBI_TRANSFER_TIMED_OUT) {
+			usbi_dbg("detected timeout");
+			status = LIBUSB_TRANSFER_TIMED_OUT;
+		} else {
+			usbi_dbg("detected operation aborted");
+			status = LIBUSB_TRANSFER_CANCELLED;
+		}
+		break;
+	default:
+		usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error: %s", windows_error_str(io_result));
+		status = LIBUSB_TRANSFER_ERROR;
+		break;
+	}
+	wince_clear_transfer_priv(itransfer);
+	if (status == LIBUSB_TRANSFER_CANCELLED) {
+		usbi_handle_transfer_cancellation(itransfer);
+	} else {
+		usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status);
+	}
+}
+
+static void wince_handle_callback (struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
+{
+	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+
+	switch (transfer->type) {
+	case LIBUSB_TRANSFER_TYPE_CONTROL:
+	case LIBUSB_TRANSFER_TYPE_BULK:
+	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+		wince_transfer_callback (itransfer, io_result, io_size);
+		break;
+	default:
+		usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
+	}
+}
+
+static int wince_handle_events(
+	struct libusb_context *ctx,
+	struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready)
+{
+	struct wince_transfer_priv* transfer_priv = NULL;
+	POLL_NFDS_TYPE i = 0;
+	BOOL found = FALSE;
+	struct usbi_transfer *transfer;
+	DWORD io_size, io_result;
+
+	usbi_mutex_lock(&ctx->open_devs_lock);
+	for (i = 0; i < nfds && num_ready > 0; i++) {
+
+		usbi_dbg("checking fd %d with revents = %04x", fds[i].fd, fds[i].revents);
+
+		if (!fds[i].revents) {
+			continue;
+		}
+
+		num_ready--;
+
+		// Because a Windows OVERLAPPED is used for poll emulation,
+		// a pollable fd is created and stored with each transfer
+		usbi_mutex_lock(&ctx->flying_transfers_lock);
+		list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
+			transfer_priv = usbi_transfer_get_os_priv(transfer);
+			if (transfer_priv->pollable_fd.fd == fds[i].fd) {
+				found = TRUE;
+				break;
+			}
+		}
+		usbi_mutex_unlock(&ctx->flying_transfers_lock);
+
+		if (found && HasOverlappedIoCompleted(transfer_priv->pollable_fd.overlapped)) {
+			io_result = (DWORD)transfer_priv->pollable_fd.overlapped->Internal;
+			io_size = (DWORD)transfer_priv->pollable_fd.overlapped->InternalHigh;
+			usbi_remove_pollfd(ctx, transfer_priv->pollable_fd.fd);
+			// let handle_callback free the event using the transfer wfd
+			// If you don't use the transfer wfd, you run a risk of trying to free a
+			// newly allocated wfd that took the place of the one from the transfer.
+			wince_handle_callback(transfer, io_result, io_size);
+		} else if (found) {
+			usbi_err(ctx, "matching transfer for fd %x has not completed", fds[i]);
+			return LIBUSB_ERROR_OTHER;
+		} else {
+			usbi_err(ctx, "could not find a matching transfer for fd %x", fds[i]);
+			return LIBUSB_ERROR_NOT_FOUND;
+		}
+	}
+
+	usbi_mutex_unlock(&ctx->open_devs_lock);
+	return LIBUSB_SUCCESS;
+}
+
+/*
+ * Monotonic and real time functions
+ */
+unsigned __stdcall wince_clock_gettime_threaded(void* param)
+{
+	LARGE_INTEGER hires_counter, li_frequency;
+	LONG nb_responses;
+	int timer_index;
+
+	// Init - find out if we have access to a monotonic (hires) timer
+	if (!QueryPerformanceFrequency(&li_frequency)) {
+		usbi_dbg("no hires timer available on this platform");
+		hires_frequency = 0;
+		hires_ticks_to_ps = UINT64_C(0);
+	} else {
+		hires_frequency = li_frequency.QuadPart;
+		// The hires frequency can go as high as 4 GHz, so we'll use a conversion
+		// to picoseconds to compute the tv_nsecs part in clock_gettime
+		hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency;
+		usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency);
+	}
+
+	// Main loop - wait for requests
+	while (1) {
+		timer_index = WaitForMultipleObjects(2, timer_request, FALSE, INFINITE) - WAIT_OBJECT_0;
+		if ( (timer_index != 0) && (timer_index != 1) ) {
+			usbi_dbg("failure to wait on requests: %s", windows_error_str(0));
+			continue;
+		}
+		if (request_count[timer_index] == 0) {
+			// Request already handled
+			ResetEvent(timer_request[timer_index]);
+			// There's still a possiblity that a thread sends a request between the
+			// time we test request_count[] == 0 and we reset the event, in which case
+			// the request would be ignored. The simple solution to that is to test
+			// request_count again and process requests if non zero.
+			if (request_count[timer_index] == 0)
+				continue;
+		}
+		switch (timer_index) {
+		case 0:
+			WaitForSingleObject(timer_mutex, INFINITE);
+			// Requests to this thread are for hires always
+			if (QueryPerformanceCounter(&hires_counter) != 0) {
+				timer_tp.tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
+				timer_tp.tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency)/1000) * hires_ticks_to_ps);
+			} else {
+				// Fallback to real-time if we can't get monotonic value
+				// Note that real-time clock does not wait on the mutex or this thread.
+				wince_clock_gettime(USBI_CLOCK_REALTIME, &timer_tp);
+			}
+			ReleaseMutex(timer_mutex);
+
+			nb_responses = InterlockedExchange((LONG*)&request_count[0], 0);
+			if ( (nb_responses)
+			  && (ReleaseSemaphore(timer_response, nb_responses, NULL) == 0) ) {
+				usbi_dbg("unable to release timer semaphore %d: %s", windows_error_str(0));
+			}
+			continue;
+		case 1: // time to quit
+			usbi_dbg("timer thread quitting");
+			return 0;
+		}
+	}
+	usbi_dbg("ERROR: broken timer thread");
+	return 1;
+}
+
+static int wince_clock_gettime(int clk_id, struct timespec *tp)
+{
+	FILETIME filetime;
+	ULARGE_INTEGER rtime;
+	DWORD r;
+	SYSTEMTIME st;
+	switch(clk_id) {
+	case USBI_CLOCK_MONOTONIC:
+		if (hires_frequency != 0) {
+			while (1) {
+				InterlockedIncrement((LONG*)&request_count[0]);
+				SetEvent(timer_request[0]);
+				r = WaitForSingleObject(timer_response, TIMER_REQUEST_RETRY_MS);
+				switch(r) {
+				case WAIT_OBJECT_0:
+					WaitForSingleObject(timer_mutex, INFINITE);
+					*tp = timer_tp;
+					ReleaseMutex(timer_mutex);
+					return LIBUSB_SUCCESS;
+				case WAIT_TIMEOUT:
+					usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?");
+					break; // Retry until successful
+				default:
+					usbi_dbg("WaitForSingleObject failed: %s", windows_error_str(0));
+					return LIBUSB_ERROR_OTHER;
+				}
+			}
+		}
+		// Fall through and return real-time if monotonic was not detected @ timer init
+	case USBI_CLOCK_REALTIME:
+		// We follow http://msdn.microsoft.com/en-us/library/ms724928%28VS.85%29.aspx
+		// with a predef epoch_time to have an epoch that starts at 1970.01.01 00:00
+		// Note however that our resolution is bounded by the Windows system time
+		// functions and is at best of the order of 1 ms (or, usually, worse)
+		GetSystemTime(&st);
+		SystemTimeToFileTime(&st, &filetime);
+		rtime.LowPart = filetime.dwLowDateTime;
+		rtime.HighPart = filetime.dwHighDateTime;
+		rtime.QuadPart -= epoch_time;
+		tp->tv_sec = (long)(rtime.QuadPart / 10000000);
+		tp->tv_nsec = (long)((rtime.QuadPart % 10000000)*100);
+		return LIBUSB_SUCCESS;
+	default:
+		return LIBUSB_ERROR_INVALID_PARAM;
+	}
+}
+
+const struct usbi_os_backend wince_backend = {
+        "Windows CE",
+        wince_init,
+        wince_exit,
+
+        wince_get_device_list,
+        wince_open,
+        wince_close,
+
+        wince_get_device_descriptor,
+        wince_get_active_config_descriptor,
+        wince_get_config_descriptor,
+
+        wince_get_configuration,
+        wince_set_configuration,
+        wince_claim_interface,
+        wince_release_interface,
+
+        wince_set_interface_altsetting,
+        wince_clear_halt,
+        wince_reset_device,
+
+        wince_kernel_driver_active,
+        wince_detach_kernel_driver,
+        wince_attach_kernel_driver,
+
+        wince_destroy_device,
+
+        wince_submit_transfer,
+        wince_cancel_transfer,
+        wince_clear_transfer_priv,
+
+        wince_handle_events,
+
+        wince_clock_gettime,
+        sizeof(struct wince_device_priv),
+        sizeof(struct wince_device_handle_priv),
+        sizeof(struct wince_transfer_priv),
+        0,
+};
diff --git a/libusb/os/wince_usb.h b/libusb/os/wince_usb.h
new file mode 100644
index 0000000..b125721
--- /dev/null
+++ b/libusb/os/wince_usb.h
@@ -0,0 +1,131 @@
+/*
+ * Windows CE backend for libusb 1.0
+ * Copyright (C) 2011-2012 RealVNC Ltd.
+ * Portions taken from Windows backend, which is
+ * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com>
+ * With contributions from Michael Plante, Orin Eman et al.
+ * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
+ * Major code testing contribution by Xiaofan Chen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#pragma once
+
+#include "windows_common.h"
+
+#include <windows.h>
+#include "poll_windows.h"
+
+#define MAX_DEVICE_COUNT            256
+
+// This is a modified dump of the types in the ceusbkwrapper.h library header
+// with functions transformed into extern pointers.
+//
+// This backend dynamically loads ceusbkwrapper.dll and doesn't include
+// ceusbkwrapper.h directly to simplify the build process. The kernel
+// side wrapper driver is built using the platform image build tools,
+// which makes it difficult to reference directly from the libusbx build
+// system.
+struct UKW_DEVICE_PRIV;
+typedef struct UKW_DEVICE_PRIV *UKW_DEVICE;
+typedef UKW_DEVICE *PUKW_DEVICE, *LPUKW_DEVICE;
+
+typedef struct {
+	UINT8 bLength;
+	UINT8 bDescriptorType;
+	UINT16 bcdUSB;
+	UINT8 bDeviceClass;
+	UINT8 bDeviceSubClass;
+	UINT8 bDeviceProtocol;
+	UINT8 bMaxPacketSize0;
+	UINT16 idVendor;
+	UINT16 idProduct;
+	UINT16 bcdDevice;
+	UINT8 iManufacturer;
+	UINT8 iProduct;
+	UINT8 iSerialNumber;
+	UINT8 bNumConfigurations;
+} UKW_DEVICE_DESCRIPTOR, *PUKW_DEVICE_DESCRIPTOR, *LPUKW_DEVICE_DESCRIPTOR;
+
+typedef struct {
+	UINT8 bmRequestType;
+	UINT8 bRequest;
+	UINT16 wValue;
+	UINT16 wIndex;
+	UINT16 wLength;
+} UKW_CONTROL_HEADER, *PUKW_CONTROL_HEADER, *LPUKW_CONTROL_HEADER;
+
+// Collection of flags which can be used when issuing transfer requests
+/* Indicates that the transfer direction is 'in' */
+#define UKW_TF_IN_TRANSFER        0x00000001
+/* Indicates that the transfer direction is 'out' */
+#define UKW_TF_OUT_TRANSFER       0x00000000
+/* Specifies that the transfer should complete as soon as possible,
+ * even if no OVERLAPPED structure has been provided. */
+#define UKW_TF_NO_WAIT            0x00000100
+/* Indicates that transfers shorter than the buffer are ok */
+#define UKW_TF_SHORT_TRANSFER_OK  0x00000200
+#define UKW_TF_SEND_TO_DEVICE     0x00010000
+#define UKW_TF_SEND_TO_INTERFACE  0x00020000
+#define UKW_TF_SEND_TO_ENDPOINT   0x00040000
+/* Don't block when waiting for memory allocations */
+#define UKW_TF_DONT_BLOCK_FOR_MEM 0x00080000
+
+/* Value to use when dealing with configuration values, such as UkwGetConfigDescriptor, 
+ * to specify the currently active configuration for the device. */
+#define UKW_ACTIVE_CONFIGURATION -1
+
+DLL_DECLARE(WINAPI, HANDLE, UkwOpenDriver, ());
+DLL_DECLARE(WINAPI, BOOL, UkwGetDeviceList, (HANDLE, LPUKW_DEVICE, DWORD, LPDWORD));
+DLL_DECLARE(WINAPI, void, UkwReleaseDeviceList, (HANDLE, LPUKW_DEVICE, DWORD));
+DLL_DECLARE(WINAPI, BOOL, UkwGetDeviceAddress, (UKW_DEVICE, unsigned char*, unsigned char*, unsigned long*));
+DLL_DECLARE(WINAPI, BOOL, UkwGetDeviceDescriptor, (UKW_DEVICE, LPUKW_DEVICE_DESCRIPTOR));
+DLL_DECLARE(WINAPI, BOOL, UkwGetConfigDescriptor, (UKW_DEVICE, DWORD, LPVOID, DWORD, LPDWORD));
+DLL_DECLARE(WINAPI, void, UkwCloseDriver, (HANDLE));
+DLL_DECLARE(WINAPI, BOOL, UkwCancelTransfer, (UKW_DEVICE, LPOVERLAPPED, DWORD));
+DLL_DECLARE(WINAPI, BOOL, UkwIssueControlTransfer, (UKW_DEVICE, DWORD, LPUKW_CONTROL_HEADER, LPVOID, DWORD, LPDWORD, LPOVERLAPPED));
+DLL_DECLARE(WINAPI, BOOL, UkwClaimInterface, (UKW_DEVICE, DWORD));
+DLL_DECLARE(WINAPI, BOOL, UkwReleaseInterface, (UKW_DEVICE, DWORD));
+DLL_DECLARE(WINAPI, BOOL, UkwSetInterfaceAlternateSetting, (UKW_DEVICE, DWORD, DWORD));
+DLL_DECLARE(WINAPI, BOOL, UkwClearHaltHost, (UKW_DEVICE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, UkwClearHaltDevice, (UKW_DEVICE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, UkwGetConfig, (UKW_DEVICE, PUCHAR));
+DLL_DECLARE(WINAPI, BOOL, UkwSetConfig, (UKW_DEVICE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, UkwResetDevice, (UKW_DEVICE));
+DLL_DECLARE(WINAPI, BOOL, UkwKernelDriverActive, (UKW_DEVICE, DWORD, PBOOL));
+DLL_DECLARE(WINAPI, BOOL, UkwAttachKernelDriver, (UKW_DEVICE, DWORD));
+DLL_DECLARE(WINAPI, BOOL, UkwDetachKernelDriver, (UKW_DEVICE, DWORD));
+DLL_DECLARE(WINAPI, BOOL, UkwIssueBulkTransfer, (UKW_DEVICE, DWORD, UCHAR, LPVOID, DWORD, LPDWORD, LPOVERLAPPED));
+DLL_DECLARE(WINAPI, BOOL, UkwIsPipeHalted, (UKW_DEVICE, UCHAR, LPBOOL));
+
+// Used to determine if an endpoint status really is halted on a failed transfer.
+#define STATUS_HALT_FLAG 0x1
+
+struct wince_device_priv {
+	UKW_DEVICE dev;
+	UKW_DEVICE_DESCRIPTOR desc;
+};
+
+struct wince_device_handle_priv {
+	// This member isn't used, but only exists to avoid an empty structure
+	// for private data for the device handle.
+	int reserved;
+};
+
+struct wince_transfer_priv {
+	struct winfd pollable_fd;
+	uint8_t interface_number;
+};
+
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index 40e8a76..b175dda 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 10595
+#define LIBUSB_NANO 10596
diff --git a/msvc/config.h b/msvc/config.h
index 730d091..eb05d3d 100644
--- a/msvc/config.h
+++ b/msvc/config.h
@@ -23,14 +23,22 @@
 /* Message logging */
 #define ENABLE_LOGGING 1
 
-/* Windows backend */
+/* Windows/WinCE backend */
+#if defined(_WIN32_WCE)
+#define OS_WINCE 1
+#else
 #define OS_WINDOWS 1
+#endif
 
 /* type of second poll() argument */
 #define POLL_NFDS_TYPE unsigned int
 
+#if !defined(_WIN32_WCE)
+
 /* Define to 1 if you have the <signal.h> header file. */
 #define HAVE_SIGNAL_H 1
 
 /* Define to 1 if you have the <sys/types.h> header file. */
 #define HAVE_SYS_TYPES_H 1
+
+#endif
\ No newline at end of file
diff --git a/msvc/errno.h b/msvc/errno.h
new file mode 100644
index 0000000..a1d4f64
--- /dev/null
+++ b/msvc/errno.h
@@ -0,0 +1,100 @@
+/* 
+ * errno.h
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is a part of the mingw-runtime package.
+ * No warranty is given; refer to the file DISCLAIMER within the package.
+ *
+ * Error numbers and access to error reporting.
+ *
+ */
+
+#ifndef _ERRNO_H_
+#define	_ERRNO_H_
+
+#include <crtdefs.h>
+
+/*
+ * Error numbers.
+ * TODO: Can't be sure of some of these assignments, I guessed from the
+ * names given by strerror and the defines in the Cygnus errno.h. A lot
+ * of the names from the Cygnus errno.h are not represented, and a few
+ * of the descriptions returned by strerror do not obviously match
+ * their error naming.
+ */
+#define EPERM		1	/* Operation not permitted */
+#define	ENOFILE		2	/* No such file or directory */
+#define	ENOENT		2
+#define	ESRCH		3	/* No such process */
+#define	EINTR		4	/* Interrupted function call */
+#define	EIO		5	/* Input/output error */
+#define	ENXIO		6	/* No such device or address */
+#define	E2BIG		7	/* Arg list too long */
+#define	ENOEXEC		8	/* Exec format error */
+#define	EBADF		9	/* Bad file descriptor */
+#define	ECHILD		10	/* No child processes */
+#define	EAGAIN		11	/* Resource temporarily unavailable */
+#define	ENOMEM		12	/* Not enough space */
+#define	EACCES		13	/* Permission denied */
+#define	EFAULT		14	/* Bad address */
+/* 15 - Unknown Error */
+#define	EBUSY		16	/* strerror reports "Resource device" */
+#define	EEXIST		17	/* File exists */
+#define	EXDEV		18	/* Improper link (cross-device link?) */
+#define	ENODEV		19	/* No such device */
+#define	ENOTDIR		20	/* Not a directory */
+#define	EISDIR		21	/* Is a directory */
+#define	EINVAL		22	/* Invalid argument */
+#define	ENFILE		23	/* Too many open files in system */
+#define	EMFILE		24	/* Too many open files */
+#define	ENOTTY		25	/* Inappropriate I/O control operation */
+/* 26 - Unknown Error */
+#define	EFBIG		27	/* File too large */
+#define	ENOSPC		28	/* No space left on device */
+#define	ESPIPE		29	/* Invalid seek (seek on a pipe?) */
+#define	EROFS		30	/* Read-only file system */
+#define	EMLINK		31	/* Too many links */
+#define	EPIPE		32	/* Broken pipe */
+#define	EDOM		33	/* Domain error (math functions) */
+#define	ERANGE		34	/* Result too large (possibly too small) */
+/* 35 - Unknown Error */
+#define	EDEADLOCK	36	/* Resource deadlock avoided (non-Cyg) */
+#define	EDEADLK		36
+/* 37 - Unknown Error */
+#define	ENAMETOOLONG	38	/* Filename too long (91 in Cyg?) */
+#define	ENOLCK		39	/* No locks available (46 in Cyg?) */
+#define	ENOSYS		40	/* Function not implemented (88 in Cyg?) */
+#define	ENOTEMPTY	41	/* Directory not empty (90 in Cyg?) */
+#define	EILSEQ		42	/* Illegal byte sequence */
+
+/*
+ * NOTE: ENAMETOOLONG and ENOTEMPTY conflict with definitions in the
+ *       sockets.h header provided with windows32api-0.1.2.
+ *       You should go and put an #if 0 ... #endif around the whole block
+ *       of errors (look at the comment above them).
+ */
+
+#ifndef	RC_INVOKED
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * Definitions of errno. For _doserrno, sys_nerr and * sys_errlist, see
+ * stdlib.h.
+ */
+#if defined(_UWIN) || defined(_WIN32_WCE)
+#undef errno
+extern int errno;
+#else
+_CRTIMP int* __cdecl _errno(void);
+#define	errno		(*_errno())
+#endif
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _ERRNO_H_ */
\ No newline at end of file
diff --git a/msvc/missing.c b/msvc/missing.c
new file mode 100644
index 0000000..85d9d6f
--- /dev/null
+++ b/msvc/missing.c
@@ -0,0 +1,80 @@
+/*
+ * Source file for missing WinCE functionality
+ * Copyright © 2012 RealVNC Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "missing.h"
+
+#include <config.h>
+#include <libusbi.h>
+
+#include <windows.h>
+
+// The registry path to store environment variables
+#define ENVIRONMENT_REG_PATH _T("Software\\libusb\\environment")
+
+/* Workaround getenv not being available on WinCE.
+ * Instead look in HKLM\Software\libusb\environment */
+char *getenv(const char *name)
+{
+	static char value[MAX_PATH];
+	TCHAR wValue[MAX_PATH];
+	WCHAR wName[MAX_PATH];
+	DWORD dwType, dwData;
+	HKEY hkey;
+	LONG rc;
+
+	if (!name)
+		return NULL;
+
+	if (MultiByteToWideChar(CP_UTF8, 0, name, -1, wName, MAX_PATH) <= 0) {
+		usbi_dbg("Failed to convert environment variable name to wide string");
+		return NULL;
+	}
+	wName[MAX_PATH - 1] = 0; // Be sure it's NUL terminated
+
+	rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ENVIRONMENT_REG_PATH, 0, KEY_QUERY_VALUE, &hkey);
+	if (rc != ERROR_SUCCESS) {
+		usbi_dbg("Failed to open registry key for getenv with error %d", rc);
+		return NULL;
+	}
+
+	// Attempt to read the key
+	dwData = sizeof(wValue);
+	rc = RegQueryValueEx(hkey, wName, NULL, &dwType,
+		(LPBYTE)&wValue, &dwData);
+	RegCloseKey(hkey);
+	if (rc != ERROR_SUCCESS) {
+		usbi_dbg("Failed to read registry key value for getenv with error %d", rc);
+		return NULL;
+	}
+	if (dwType != REG_SZ) {
+		usbi_dbg("Registry value was of type %d instead of REG_SZ", dwType);
+		return NULL;
+	}
+
+	// Success in reading the key, convert from WCHAR to char
+	if (WideCharToMultiByte(CP_UTF8, 0,
+			wValue, dwData / sizeof(*wValue),
+			value, MAX_PATH,
+			NULL, NULL) <= 0) {
+		usbi_dbg("Failed to convert environment variable value to narrow string");
+		return NULL;
+	}
+	value[MAX_PATH - 1] = 0; // Be sure it's NUL terminated
+	return value;
+}
diff --git a/msvc/missing.h b/msvc/missing.h
new file mode 100644
index 0000000..7846976
--- /dev/null
+++ b/msvc/missing.h
@@ -0,0 +1,29 @@
+/*
+ * Header file for missing WinCE functionality
+ * Copyright © 2012 RealVNC Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef MISSING_H
+#define MISSING_H
+
+/* Windows CE doesn't have any APIs to query environment variables.
+ *
+ * This contains a registry based implementation of getenv.
+ */
+char *getenv(const char *name);
+
+#endif
diff --git a/tests/stress.c b/tests/stress.c
index c4a92fa..26860a0 100644
--- a/tests/stress.c
+++ b/tests/stress.c
@@ -18,8 +18,10 @@
  */
 
 #include <stdio.h>
-#include <sys/types.h>
 #include <memory.h>
+#if !defined(_WIN32_WCE)
+#include <sys/types.h>
+#endif
 
 #include "libusb.h"
 
diff --git a/tests/testlib.c b/tests/testlib.c
index 9e45d31..3a91933 100644
--- a/tests/testlib.c
+++ b/tests/testlib.c
@@ -23,11 +23,17 @@
 #include <stdarg.h>
 #include <string.h>
 #include <errno.h>
+#if !defined(_WIN32_WCE)
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#endif
 
-#ifdef _WIN32
+#if defined(_WIN32_WCE)
+// No support for selective redirection of STDOUT on WinCE.
+#define DISABLE_STDOUT_REDIRECTION
+#define STDOUT_FILENO 1
+#elif defined(_WIN32)
 #include <io.h>
 #define dup _dup
 #define dup2 _dup2
@@ -72,6 +78,7 @@
 
 static void cleanup_test_output(libusbx_testlib_ctx * ctx)
 {
+#ifndef DISABLE_STDOUT_REDIRECTION
 	if (ctx->output_file != NULL) {
 		fclose(ctx->output_file);
 		ctx->output_file = NULL;
@@ -84,6 +91,7 @@
 		close(ctx->null_fd);
 		ctx->null_fd = INVALID_FD;
 	}
+#endif
 }
 
 /**
@@ -92,6 +100,11 @@
  */
 static int setup_test_output(libusbx_testlib_ctx * ctx)
 {
+#ifdef DISABLE_STDOUT_REDIRECTION
+    ctx->output_fd = STDOUT_FILENO;
+	ctx->output_file = stdout;
+	return 0;
+#else
 	/* Keep a copy of STDOUT for test output */
 	ctx->output_fd = dup(STDOUT_FILENO);
 	if (ctx->output_fd < 0) {
@@ -122,6 +135,7 @@
 		}
 	}
 	return 0;
+#endif
 }
 
 void libusbx_testlib_logf(libusbx_testlib_ctx * ctx,