Windows: Refactoring to consolidate and simplify common code

Both the UsbDk and WinUSB backends perform common steps when handling
transfers in order to interact with the poll abstraction, both during
submission and when processing transfer completion. With some
rearranging of shared structures, this can be yanked from the individual
backends and placed in the common area. This allows for several
functions to be removed outright from each backend.

The cancellation logic can also be simplified by attempting CancelIoEx()
at the highest level and delegating to the backend if there are
alternatives to try should CancelIoEx() fail.

After some analysis of how Windows processes asychronous (OVERLAPPED)
requests that the underlying driver completes synchronously, it is now
evident that such requests need not be handled in any special fashion.
Each function that called a driver function that was expected to
complete asynchronously had logic to handle the case of a synchronous
completion, so this has all been killed off. This significantly cleans
up these call sites as now they must only check for an error condition.

Finally, the initialization code for the WinUSB backend has been
reworked to load the WinUSB DLL independent of the libusbK DLL.
Previously when the libusbK DLL was present, all requests to devices
using WinUSB would first be sent through the libusbK DLL where
they would then be forwarded to the WinUSB DLL. This is slightly
inefficient but is also limiting when using Windows 8.1 or later because
support for isochronous transfers through WinUSB will be lost.

Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
diff --git a/libusb/os/poll_windows.c b/libusb/os/poll_windows.c
index f735245..490ee7f 100644
--- a/libusb/os/poll_windows.c
+++ b/libusb/os/poll_windows.c
@@ -392,8 +392,7 @@
 			if (fd == NULL) {
 				fds[n].revents = POLLNVAL;
 				nready++;
-			} else if (HasOverlappedIoCompleted(&fd->overlapped) &&
-					(WaitForSingleObject(fd->overlapped.hEvent, 0) == WAIT_OBJECT_0)) {
+			} else if (HasOverlappedIoCompleted(&fd->overlapped)) {
 				fds[n].revents = fds[n].events;
 				nready++;
 			} else {
diff --git a/libusb/os/poll_windows.h b/libusb/os/poll_windows.h
index b2c94f9..a38e1da 100644
--- a/libusb/os/poll_windows.h
+++ b/libusb/os/poll_windows.h
@@ -25,13 +25,6 @@
 #ifndef LIBUSB_POLL_WINDOWS_H
 #define LIBUSB_POLL_WINDOWS_H
 
-// Handle synchronous completion through the overlapped structure
-#if !defined(STATUS_REPARSE)	// reuse the REPARSE status code
-#define STATUS_REPARSE ((LONG)0x00000104L)
-#endif
-#define STATUS_COMPLETED_SYNCHRONOUSLY	STATUS_REPARSE
-#define HasOverlappedIoCompletedSync(lpOverlapped)	(((DWORD)(lpOverlapped)->Internal) == STATUS_COMPLETED_SYNCHRONOUSLY)
-
 #define DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2)
 
 #define POLLIN		0x0001	/* There is data to read */
diff --git a/libusb/os/windows_common.c b/libusb/os/windows_common.c
index a2c9beb..3a11c56 100644
--- a/libusb/os/windows_common.c
+++ b/libusb/os/windows_common.c
@@ -33,12 +33,14 @@
 
 #define EPOCH_TIME	UINT64_C(116444736000000000)	// 1970.01.01 00:00:000 in MS Filetime
 
+#define STATUS_SUCCESS	((ULONG_PTR)0UL)
+
 // Public
 enum windows_version windows_version = WINDOWS_UNDEFINED;
 
  // Global variables for init/exit
-static unsigned int init_count = 0;
-static bool usbdk_available = false;
+static unsigned int init_count;
+static bool usbdk_available;
 
 // Global variables for clock_gettime mechanism
 static uint64_t hires_ticks_to_ps;
@@ -114,7 +116,7 @@
 	char *str;
 } htab_entry;
 
-static htab_entry *htab_table = NULL;
+static htab_entry *htab_table;
 static usbi_mutex_t htab_mutex;
 static unsigned long htab_filled;
 
@@ -125,7 +127,7 @@
 static bool htab_create(struct libusb_context *ctx)
 {
 	if (htab_table != NULL) {
-		usbi_err(ctx, "hash table already allocated");
+		usbi_err(ctx, "program assertion falied - hash table already allocated");
 		return true;
 	}
 
@@ -173,7 +175,7 @@
 {
 	unsigned long hval, hval2;
 	unsigned long idx;
-	unsigned long r = 5381;
+	unsigned long r = 5381UL;
 	int c;
 	const char *sz = str;
 
@@ -204,7 +206,7 @@
 		usbi_dbg("hash collision ('%s' vs '%s')", str, htab_table[idx].str);
 
 		// Second hash function, as suggested in [Knuth]
-		hval2 = 1 + hval % (HTAB_SIZE - 2);
+		hval2 = 1UL + hval % (HTAB_SIZE - 2);
 
 		do {
 			// Because size is prime this guarantees to step through all available indexes
@@ -228,14 +230,14 @@
 	// If the table is full return an error
 	if (htab_filled >= HTAB_SIZE) {
 		usbi_err(NULL, "hash table is full (%lu entries)", HTAB_SIZE);
-		idx = 0;
+		idx = 0UL;
 		goto out_unlock;
 	}
 
 	htab_table[idx].str = _strdup(str);
 	if (htab_table[idx].str == NULL) {
 		usbi_err(NULL, "could not duplicate string for hash table");
-		idx = 0;
+		idx = 0UL;
 		goto out_unlock;
 	}
 
@@ -248,13 +250,33 @@
 	return idx;
 }
 
+enum libusb_transfer_status usbd_status_to_libusb_transfer_status(USBD_STATUS status)
+{
+	if (USBD_SUCCESS(status))
+		return LIBUSB_TRANSFER_COMPLETED;
+
+	switch (status) {
+	case USBD_STATUS_TIMEOUT:
+		return LIBUSB_TRANSFER_TIMED_OUT;
+	case USBD_STATUS_CANCELED:
+		return LIBUSB_TRANSFER_CANCELLED;
+	case USBD_STATUS_ENDPOINT_HALTED:
+		return LIBUSB_TRANSFER_STALL;
+	case USBD_STATUS_DEVICE_GONE:
+		return LIBUSB_TRANSFER_NO_DEVICE;
+	default:
+		usbi_dbg("USBD_STATUS 0x%08lx translated to LIBUSB_TRANSFER_ERROR", ULONG_CAST(status));
+		return LIBUSB_TRANSFER_ERROR;
+	}
+}
+
 /*
 * Make a transfer complete synchronously
 */
 void windows_force_sync_completion(OVERLAPPED *overlapped, ULONG size)
 {
-	overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
-	overlapped->InternalHigh = size;
+	overlapped->Internal = (ULONG_PTR)STATUS_SUCCESS;
+	overlapped->InternalHigh = (ULONG_PTR)size;
 	SetEvent(overlapped->hEvent);
 }
 
@@ -294,7 +316,7 @@
 	const char *arch, *w = NULL;
 	unsigned major, minor, version;
 	ULONGLONG major_equal, minor_equal;
-	BOOL ws;
+	bool ws;
 
 	windows_version = WINDOWS_UNDEFINED;
 
@@ -378,16 +400,17 @@
 }
 
 static void windows_transfer_callback(const struct windows_backend *backend,
-	struct usbi_transfer *itransfer, DWORD io_result, DWORD io_size)
+	struct usbi_transfer *itransfer, DWORD error, DWORD bytes_transferred)
 {
-	int status, istatus;
+	struct windows_transfer_priv *transfer_priv = get_transfer_priv(itransfer);
+	enum libusb_transfer_status status, istatus;
 
-	usbi_dbg("handling I/O completion with errcode %lu, size %lu",
-		ULONG_CAST(io_result), ULONG_CAST(io_size));
+	usbi_dbg("handling I/O completion with errcode %lu, length %lu",
+		ULONG_CAST(error), ULONG_CAST(bytes_transferred));
 
-	switch (io_result) {
+	switch (error) {
 	case NO_ERROR:
-		status = backend->copy_transfer_data(itransfer, (uint32_t)io_size);
+		status = backend->copy_transfer_data(itransfer, bytes_transferred);
 		break;
 	case ERROR_GEN_FAILURE:
 		usbi_dbg("detected endpoint stall");
@@ -398,9 +421,9 @@
 		status = LIBUSB_TRANSFER_TIMED_OUT;
 		break;
 	case ERROR_OPERATION_ABORTED:
-		istatus = backend->copy_transfer_data(itransfer, (uint32_t)io_size);
+		istatus = backend->copy_transfer_data(itransfer, bytes_transferred);
 		if (istatus != LIBUSB_TRANSFER_COMPLETED)
-			usbi_dbg("Failed to copy partial data in aborted operation: %d", istatus);
+			usbi_dbg("failed to copy partial data in aborted operation: %d", (int)istatus);
 
 		usbi_dbg("detected operation aborted");
 		status = LIBUSB_TRANSFER_CANCELLED;
@@ -412,57 +435,45 @@
 		break;
 	default:
 		usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error %lu: %s",
-			ULONG_CAST(io_result), windows_error_str(io_result));
+			ULONG_CAST(error), windows_error_str(error));
 		status = LIBUSB_TRANSFER_ERROR;
 		break;
 	}
-	backend->clear_transfer_priv(itransfer);	// Cancel polling
+
+	// Cancel polling
+	usbi_close(transfer_priv->pollable_fd.fd);
+	transfer_priv->pollable_fd = INVALID_WINFD;
+	transfer_priv->handle = NULL;
+
+	// Backend-specific cleanup
+	backend->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 windows_handle_callback(const struct windows_backend *backend,
-	struct usbi_transfer *itransfer, DWORD io_result, DWORD 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:
-		windows_transfer_callback(backend, itransfer, io_result, io_size);
-		break;
-	case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
-		usbi_warn(ITRANSFER_CTX(itransfer), "bulk stream transfers are not yet supported on this platform");
-		break;
-	default:
-		usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
-	}
+		usbi_handle_transfer_completion(itransfer, status);
 }
 
 static int windows_init(struct libusb_context *ctx)
 {
 	struct windows_context_priv *priv = _context_priv(ctx);
-	HANDLE semaphore;
-	char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
+	char mutex_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
+	HANDLE mutex;
 	int r = LIBUSB_ERROR_OTHER;
 	bool winusb_backend_init = false;
 
-	sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF));
-	semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name);
-	if (semaphore == NULL) {
-		usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0));
+	sprintf(mutex_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFFU));
+	mutex = CreateMutexA(NULL, FALSE, mutex_name);
+	if (mutex == NULL) {
+		usbi_err(ctx, "could not create mutex: %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);
+	// A successful wait gives this thread ownership of the mutex
+	// => any concurent wait stalls until the mutex is released
+	if (WaitForSingleObject(mutex, INFINITE) != WAIT_OBJECT_0) {
+		usbi_err(ctx, "failure to access mutex: %s", windows_error_str(0));
+		CloseHandle(mutex);
 		return LIBUSB_ERROR_NO_MEM;
 	}
 
@@ -511,26 +522,26 @@
 		--init_count;
 	}
 
-	ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
-	CloseHandle(semaphore);
+	ReleaseMutex(mutex);
+	CloseHandle(mutex);
 	return r;
 }
 
 static void windows_exit(struct libusb_context *ctx)
 {
-	HANDLE semaphore;
-	char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
-	UNUSED(ctx);
+	char mutex_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
+	HANDLE mutex;
 
-	sprintf(sem_name, "libusb_init%08lX", (GetCurrentProcessId() & 0xFFFFFFFFUL));
-	semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name);
-	if (semaphore == NULL)
+	sprintf(mutex_name, "libusb_init%08lX", (GetCurrentProcessId() & 0xFFFFFFFFU));
+	mutex = CreateMutexA(NULL, FALSE, mutex_name);
+	if (mutex == 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);
+	// A successful wait gives this thread ownership of the mutex
+	// => any concurent wait stalls until the mutex is released
+	if (WaitForSingleObject(mutex, INFINITE) != WAIT_OBJECT_0) {
+		usbi_err(ctx, "failed to access mutex: %s", windows_error_str(0));
+		CloseHandle(mutex);
 		return;
 	}
 
@@ -544,8 +555,8 @@
 		htab_destroy();
 	}
 
-	ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
-	CloseHandle(semaphore);
+	ReleaseMutex(mutex);
+	CloseHandle(mutex);
 }
 
 static int windows_set_option(struct libusb_context *ctx, enum libusb_option option, va_list ap)
@@ -567,7 +578,6 @@
 	default:
 		return LIBUSB_ERROR_NOT_SUPPORTED;
 	}
-
 }
 
 static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **discdevs)
@@ -671,29 +681,103 @@
 
 static int windows_submit_transfer(struct usbi_transfer *itransfer)
 {
-	struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer));
-	return priv->backend->submit_transfer(itransfer);
+	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+	struct libusb_context *ctx = TRANSFER_CTX(transfer);
+	struct windows_context_priv *priv = _context_priv(ctx);
+	struct windows_transfer_priv *transfer_priv = get_transfer_priv(itransfer);
+	short events;
+	int r;
+
+	switch (transfer->type) {
+	case LIBUSB_TRANSFER_TYPE_CONTROL:
+		events = (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) ? POLLIN : POLLOUT;
+		break;
+	case LIBUSB_TRANSFER_TYPE_BULK:
+	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+		events = IS_XFERIN(transfer) ? POLLIN : POLLOUT;
+		break;
+	case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
+		usbi_warn(ctx, "bulk stream transfers are not yet supported on this platform");
+		return LIBUSB_ERROR_NOT_SUPPORTED;
+	default:
+		usbi_err(ctx, "unknown endpoint type %d", transfer->type);
+		return LIBUSB_ERROR_INVALID_PARAM;
+	}
+
+	// Because a Windows OVERLAPPED is used for poll emulation,
+	// a pollable fd is created and stored with each transfer
+	transfer_priv->pollable_fd = usbi_create_fd();
+	if (transfer_priv->pollable_fd.fd < 0) {
+		usbi_err(ctx, "failed to create pollable fd");
+		return LIBUSB_ERROR_NO_MEM;
+	}
+
+	if (transfer_priv->handle != NULL) {
+		usbi_err(ctx, "program assertion failed - transfer HANDLE is not NULL");
+		transfer_priv->handle = NULL;
+	}
+
+	r = priv->backend->submit_transfer(itransfer);
+	if (r != LIBUSB_SUCCESS) {
+		// Always call the backend's clear_transfer_priv() function on failure
+		priv->backend->clear_transfer_priv(itransfer);
+		// Release the pollable fd since it won't be used
+		usbi_close(transfer_priv->pollable_fd.fd);
+		transfer_priv->pollable_fd = INVALID_WINFD;
+		transfer_priv->handle = NULL;
+		return r;
+	}
+
+	// The backend should set the HANDLE used for each submitted transfer
+	// by calling set_transfer_priv_handle()
+	if (transfer_priv->handle == NULL)
+		usbi_err(ctx, "program assertion failed - transfer HANDLE is NULL after transfer was submitted");
+
+	// We don't want to start monitoring the pollable fd before the transfer
+	// has been submitted, so start monitoring it now.  Note that if the
+	// usbi_add_pollfd() function fails, the user will never get notified
+	// that the transfer has completed.  We don't attempt any cleanup if this
+	// happens because the transfer is already in progress and could even have
+	// completed
+	if (usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, events))
+		usbi_err(ctx, "failed to add pollable fd %d for transfer %p",
+			transfer_priv->pollable_fd.fd, transfer);
+
+	return r;
 }
 
 static int windows_cancel_transfer(struct usbi_transfer *itransfer)
 {
 	struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer));
-	return priv->backend->cancel_transfer(itransfer);
+	struct windows_transfer_priv *transfer_priv = get_transfer_priv(itransfer);
+
+	// Try CancelIoEx() on the transfer
+	// If that fails, fall back to the backend's cancel_transfer()
+	// function if it is available
+	if (CancelIoEx(transfer_priv->handle, transfer_priv->pollable_fd.overlapped))
+		return LIBUSB_SUCCESS;
+	else if (GetLastError() == ERROR_NOT_FOUND)
+		return LIBUSB_ERROR_NOT_FOUND;
+
+	if (priv->backend->cancel_transfer)
+		return priv->backend->cancel_transfer(itransfer);
+
+	usbi_warn(ITRANSFER_CTX(itransfer), "cancellation not supported for this transfer's driver");
+	return LIBUSB_ERROR_NOT_SUPPORTED;
 }
 
 static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, usbi_nfds_t nfds, int num_ready)
 {
 	struct windows_context_priv *priv = _context_priv(ctx);
 	struct usbi_transfer *itransfer;
-	DWORD io_size, io_result;
+	struct windows_transfer_priv *transfer_priv;
+	DWORD result, bytes_transferred;
 	usbi_nfds_t i;
-	bool found;
-	int transfer_fd;
 	int r = LIBUSB_SUCCESS;
 
 	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)
@@ -701,34 +785,30 @@
 
 		num_ready--;
 
-		// Because a Windows OVERLAPPED is used for poll emulation,
-		// a pollable fd is created and stored with each transfer
-		found = false;
-		transfer_fd = -1;
+		transfer_priv = NULL;
 		usbi_mutex_lock(&ctx->flying_transfers_lock);
 		list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) {
-			transfer_fd = priv->backend->get_transfer_fd(itransfer);
-			if (transfer_fd == fds[i].fd) {
-				found = true;
+			transfer_priv = get_transfer_priv(itransfer);
+			if (transfer_priv->pollable_fd.fd == fds[i].fd)
 				break;
-			}
+			transfer_priv = NULL;
 		}
 		usbi_mutex_unlock(&ctx->flying_transfers_lock);
 
-		if (found) {
-			priv->backend->get_overlapped_result(itransfer, &io_result, &io_size);
-
-			usbi_remove_pollfd(ctx, transfer_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.
-			windows_handle_callback(priv->backend, itransfer, io_result, io_size);
-		} else {
+		if (transfer_priv == NULL) {
 			usbi_err(ctx, "could not find a matching transfer for fd %d", fds[i].fd);
 			r = LIBUSB_ERROR_NOT_FOUND;
 			break;
 		}
+
+		usbi_remove_pollfd(ctx, transfer_priv->pollable_fd.fd);
+
+		if (GetOverlappedResult(transfer_priv->handle, transfer_priv->pollable_fd.overlapped, &bytes_transferred, FALSE))
+			result = NO_ERROR;
+		else
+			result = GetLastError();
+
+		windows_transfer_callback(priv->backend, itransfer, result, bytes_transferred);
 	}
 	usbi_mutex_unlock(&ctx->open_devs_lock);
 
@@ -814,5 +894,5 @@
 	sizeof(struct windows_context_priv),
 	sizeof(union windows_device_priv),
 	sizeof(union windows_device_handle_priv),
-	sizeof(union windows_transfer_priv),
+	sizeof(struct windows_transfer_priv),
 };
diff --git a/libusb/os/windows_common.h b/libusb/os/windows_common.h
index 93ea23e..63d3183 100644
--- a/libusb/os/windows_common.h
+++ b/libusb/os/windows_common.h
@@ -68,13 +68,13 @@
 #define DLL_HANDLE_NAME(name) __dll_##name##_handle
 
 #define DLL_DECLARE_HANDLE(name)				\
-	static HMODULE DLL_HANDLE_NAME(name) = NULL
+	static HMODULE DLL_HANDLE_NAME(name)
 
 #define DLL_GET_HANDLE(name)					\
 	do {							\
 		DLL_HANDLE_NAME(name) = DLL_LOAD_LIBRARY(name);	\
 		if (!DLL_HANDLE_NAME(name))			\
-			return FALSE;				\
+			return false;				\
 	} while (0)
 
 #define DLL_FREE_HANDLE(name)					\
@@ -92,7 +92,7 @@
 
 #define DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefixname, name, args)	\
 	typedef ret (api * DLL_FUNC_NAME(name))args;			\
-	static DLL_FUNC_NAME(name) prefixname = NULL
+	static DLL_FUNC_NAME(name) prefixname
 
 #define DLL_DECLARE_FUNC(api, ret, name, args)				\
 	DLL_DECLARE_FUNC_PREFIXNAME(api, ret, name, name, args)
@@ -115,7 +115,7 @@
 		if (prefixname)						\
 			break;						\
 		if (ret_on_failure)					\
-			return FALSE;					\
+			return false;					\
 	} while (0)
 
 #define DLL_LOAD_FUNC(dll, name, ret_on_failure)			\
@@ -271,16 +271,13 @@
 
 struct usbdk_transfer_priv {
 	USB_DK_TRANSFER_REQUEST request;
-	struct winfd pollable_fd;
-	HANDLE system_handle;
 	PULONG64 IsochronousPacketsArray;
 	PUSB_DK_ISO_TRANSFER_RESULT IsochronousResultsArray;
 };
 
 struct winusb_transfer_priv {
-	struct winfd pollable_fd;
-	HANDLE handle;
 	uint8_t interface_number;
+
 	uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID
 	uint8_t *hid_dest;   // transfer buffer destination, required for HID
 	size_t hid_expected_size;
@@ -322,10 +319,7 @@
 	int (*submit_transfer)(struct usbi_transfer *itransfer);
 	int (*cancel_transfer)(struct usbi_transfer *itransfer);
 	void (*clear_transfer_priv)(struct usbi_transfer *itransfer);
-	int (*copy_transfer_data)(struct usbi_transfer *itransfer, uint32_t io_size);
-	int (*get_transfer_fd)(struct usbi_transfer *itransfer);
-	void (*get_overlapped_result)(struct usbi_transfer *itransfer,
-		DWORD *io_result, DWORD *io_size);
+	enum libusb_transfer_status (*copy_transfer_data)(struct usbi_transfer *itransfer, DWORD length);
 };
 
 struct windows_context_priv {
@@ -342,15 +336,49 @@
 	struct winusb_device_handle_priv winusb_priv;
 };
 
-union windows_transfer_priv {
-	struct usbdk_transfer_priv usbdk_priv;
-	struct winusb_transfer_priv winusb_priv;
+struct windows_transfer_priv {
+	struct winfd pollable_fd;
+	HANDLE handle;
+	union {
+		struct usbdk_transfer_priv usbdk_priv;
+		struct winusb_transfer_priv winusb_priv;
+	};
 };
 
+static inline struct windows_transfer_priv *get_transfer_priv(struct usbi_transfer *itransfer)
+{
+	return (struct windows_transfer_priv *)usbi_transfer_get_os_priv(itransfer);
+}
+
+static inline OVERLAPPED *get_transfer_priv_overlapped(struct usbi_transfer *itransfer)
+{
+	struct windows_transfer_priv *transfer_priv = get_transfer_priv(itransfer);
+	return transfer_priv->pollable_fd.overlapped;
+}
+
+static inline void set_transfer_priv_handle(struct usbi_transfer *itransfer, HANDLE handle)
+{
+	struct windows_transfer_priv *transfer_priv = get_transfer_priv(itransfer);
+	transfer_priv->handle = handle;
+}
+
+static inline struct usbdk_transfer_priv *get_usbdk_transfer_priv(struct usbi_transfer *itransfer)
+{
+	struct windows_transfer_priv *transfer_priv = get_transfer_priv(itransfer);
+	return &transfer_priv->usbdk_priv;
+}
+
+static inline struct winusb_transfer_priv *get_winusb_transfer_priv(struct usbi_transfer *itransfer)
+{
+	struct windows_transfer_priv *transfer_priv = get_transfer_priv(itransfer);
+	return &transfer_priv->winusb_priv;
+}
+
 extern const struct windows_backend usbdk_backend;
 extern const struct windows_backend winusb_backend;
 
 unsigned long htab_hash(const char *str);
+enum libusb_transfer_status usbd_status_to_libusb_transfer_status(USBD_STATUS status);
 void windows_force_sync_completion(OVERLAPPED *overlapped, ULONG size);
 
 #if defined(ENABLE_LOGGING)
diff --git a/libusb/os/windows_usbdk.c b/libusb/os/windows_usbdk.c
index bbec3d8..46935a6 100644
--- a/libusb/os/windows_usbdk.c
+++ b/libusb/os/windows_usbdk.c
@@ -48,11 +48,6 @@
 	return (struct usbdk_device_priv *)dev->os_priv;
 }
 
-static inline struct usbdk_transfer_priv *_usbdk_transfer_priv(struct usbi_transfer *itransfer)
-{
-	return (struct usbdk_transfer_priv *)usbi_transfer_get_os_priv(itransfer);
-}
-
 static struct {
 	HMODULE module;
 
@@ -423,7 +418,7 @@
 
 	priv->redirector_handle = usbdk_helper.StartRedirect(&priv->info.ID);
 	if (priv->redirector_handle == INVALID_HANDLE_VALUE) {
-		usbi_err(DEVICE_CTX(dev_handle->dev), "Redirector startup failed");
+		usbi_err(HANDLE_CTX(dev_handle), "Redirector startup failed");
 		return LIBUSB_ERROR_OTHER;
 	}
 
@@ -463,11 +458,10 @@
 
 static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
 {
-	struct libusb_context *ctx = HANDLE_CTX(dev_handle);
 	struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
 
 	if (!usbdk_helper.SetAltsetting(priv->redirector_handle, iface, altsetting)) {
-		usbi_err(ctx, "SetAltsetting failed: %s", windows_error_str(0));
+		usbi_err(HANDLE_CTX(dev_handle), "SetAltsetting failed: %s", windows_error_str(0));
 		return LIBUSB_ERROR_NO_DEVICE;
 	}
 
@@ -483,11 +477,10 @@
 
 static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
 {
-	struct libusb_context *ctx = HANDLE_CTX(dev_handle);
 	struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
 
 	if (!usbdk_helper.ResetPipe(priv->redirector_handle, endpoint)) {
-		usbi_err(ctx, "ResetPipe failed: %s", windows_error_str(0));
+		usbi_err(HANDLE_CTX(dev_handle), "ResetPipe failed: %s", windows_error_str(0));
 		return LIBUSB_ERROR_NO_DEVICE;
 	}
 
@@ -496,11 +489,10 @@
 
 static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
 {
-	struct libusb_context *ctx = HANDLE_CTX(dev_handle);
 	struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
 
 	if (!usbdk_helper.ResetDevice(priv->redirector_handle)) {
-		usbi_err(ctx, "ResetDevice failed: %s", windows_error_str(0));
+		usbi_err(HANDLE_CTX(dev_handle), "ResetDevice failed: %s", windows_error_str(0));
 		return LIBUSB_ERROR_NO_DEVICE;
 	}
 
@@ -517,13 +509,9 @@
 
 static void usbdk_clear_transfer_priv(struct usbi_transfer *itransfer)
 {
-	struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
+	struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
 
-	usbi_close(transfer_priv->pollable_fd.fd);
-	transfer_priv->pollable_fd = INVALID_WINFD;
-	transfer_priv->system_handle = NULL;
-
 	if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
 		safe_free(transfer_priv->IsochronousPacketsArray);
 		safe_free(transfer_priv->IsochronousResultsArray);
@@ -534,9 +522,8 @@
 {
 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
 	struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
-	struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
-	struct libusb_context *ctx = TRANSFER_CTX(transfer);
-	OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
+	struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
+	OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer);
 	TransferResult transResult;
 
 	transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
@@ -555,10 +542,12 @@
 	case TransferSuccessAsync:
 		break;
 	case TransferFailure:
-		usbi_err(ctx, "ControlTransfer failed: %s", windows_error_str(0));
+		usbi_err(TRANSFER_CTX(transfer), "ControlTransfer failed: %s", windows_error_str(0));
 		return LIBUSB_ERROR_IO;
 	}
 
+	set_transfer_priv_handle(itransfer, priv->system_handle);
+
 	return LIBUSB_SUCCESS;
 }
 
@@ -566,9 +555,8 @@
 {
 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
 	struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
-	struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
-	struct libusb_context *ctx = TRANSFER_CTX(transfer);
-	OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
+	struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
+	OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer);
 	TransferResult transferRes;
 
 	transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
@@ -582,9 +570,6 @@
 	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
 		transfer_priv->request.TransferType = InterruptTransferType;
 		break;
-	default:
-		usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer", transfer->type);
-		return LIBUSB_ERROR_INVALID_PARAM;
 	}
 
 	if (IS_XFERIN(transfer))
@@ -599,10 +584,12 @@
 	case TransferSuccessAsync:
 		break;
 	case TransferFailure:
-		usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
+		usbi_err(TRANSFER_CTX(transfer), "ReadPipe/WritePipe failed: %s", windows_error_str(0));
 		return LIBUSB_ERROR_IO;
 	}
 
+	set_transfer_priv_handle(itransfer, priv->system_handle);
+
 	return LIBUSB_SUCCESS;
 }
 
@@ -610,9 +597,8 @@
 {
 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
 	struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
-	struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
-	struct libusb_context *ctx = TRANSFER_CTX(transfer);
-	OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
+	struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
+	OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer);
 	TransferResult transferRes;
 	int i;
 
@@ -624,14 +610,14 @@
 	transfer_priv->IsochronousPacketsArray = malloc(transfer->num_iso_packets * sizeof(ULONG64));
 	transfer_priv->request.IsochronousPacketsArray = (PVOID64)transfer_priv->IsochronousPacketsArray;
 	if (!transfer_priv->IsochronousPacketsArray) {
-		usbi_err(ctx, "Allocation of IsochronousPacketsArray failed");
+		usbi_err(TRANSFER_CTX(transfer), "Allocation of IsochronousPacketsArray failed");
 		return LIBUSB_ERROR_NO_MEM;
 	}
 
 	transfer_priv->IsochronousResultsArray = malloc(transfer->num_iso_packets * sizeof(USB_DK_ISO_TRANSFER_RESULT));
 	transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)transfer_priv->IsochronousResultsArray;
 	if (!transfer_priv->IsochronousResultsArray) {
-		usbi_err(ctx, "Allocation of isochronousResultsArray failed");
+		usbi_err(TRANSFER_CTX(transfer), "Allocation of isochronousResultsArray failed");
 		return LIBUSB_ERROR_NO_MEM;
 	}
 
@@ -653,39 +639,7 @@
 		return LIBUSB_ERROR_IO;
 	}
 
-	return LIBUSB_SUCCESS;
-}
-
-static int usbdk_do_submit_transfer(struct usbi_transfer *itransfer,
-	short events, int (*transfer_fn)(struct usbi_transfer *))
-{
-	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-	struct libusb_context *ctx = TRANSFER_CTX(transfer);
-	struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
-	struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
-	struct winfd wfd;
-	int r;
-
-	wfd = usbi_create_fd();
-	if (wfd.fd < 0)
-		return LIBUSB_ERROR_NO_MEM;
-
-	r = usbi_add_pollfd(ctx, wfd.fd, events);
-	if (r) {
-		usbi_close(wfd.fd);
-		return r;
-	}
-
-	// Use transfer_priv to store data needed for async polling
-	transfer_priv->pollable_fd = wfd;
-	transfer_priv->system_handle = priv->system_handle;
-
-	r = transfer_fn(itransfer);
-	if (r != LIBUSB_SUCCESS) {
-		usbi_remove_pollfd(ctx, wfd.fd);
-		usbdk_clear_transfer_priv(itransfer);
-		return r;
-	}
+	set_transfer_priv_handle(itransfer, priv->system_handle);
 
 	return LIBUSB_SUCCESS;
 }
@@ -693,129 +647,55 @@
 static int usbdk_submit_transfer(struct usbi_transfer *itransfer)
 {
 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-	int (*transfer_fn)(struct usbi_transfer *);
-	short events;
 
 	switch (transfer->type) {
 	case LIBUSB_TRANSFER_TYPE_CONTROL:
-		events = (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) ? POLLIN : POLLOUT;
-		transfer_fn = usbdk_do_control_transfer;
-		break;
+		return usbdk_do_control_transfer(itransfer);
 	case LIBUSB_TRANSFER_TYPE_BULK:
 	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
 		if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
 			return LIBUSB_ERROR_NOT_SUPPORTED; //TODO: Check whether we can support this in UsbDk
-		events = IS_XFERIN(transfer) ? POLLIN : POLLOUT;
-		transfer_fn = usbdk_do_bulk_transfer;
-		break;
+		return usbdk_do_bulk_transfer(itransfer);
 	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
-		events = IS_XFERIN(transfer) ? POLLIN : POLLOUT;
-		transfer_fn = usbdk_do_iso_transfer;
-		break;
+		return usbdk_do_iso_transfer(itransfer);
 	default:
-		usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
-		return LIBUSB_ERROR_INVALID_PARAM;
+		// Should not get here since windows_submit_transfer() validates
+		// the transfer->type field
+		usbi_err(TRANSFER_CTX(transfer), "unsupported endpoint type %d", transfer->type);
+		return LIBUSB_ERROR_NOT_SUPPORTED;
 	}
-
-	return usbdk_do_submit_transfer(itransfer, events, transfer_fn);
 }
 
-static int usbdk_abort_transfers(struct usbi_transfer *itransfer)
+static enum libusb_transfer_status usbdk_copy_transfer_data(struct usbi_transfer *itransfer, DWORD length)
 {
 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-	struct libusb_context *ctx = TRANSFER_CTX(transfer);
-	struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
-	struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
-	struct winfd *pollable_fd = &transfer_priv->pollable_fd;
+	struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
 
-	// Use CancelIoEx to cancel just a single transfer
-	if (CancelIoEx(priv->system_handle, pollable_fd->overlapped))
-		return LIBUSB_SUCCESS;
+	UNUSED(length);
 
-	usbi_warn(ctx, "CancelIoEx failed: %s", windows_error_str(0));
-	return LIBUSB_ERROR_NOT_FOUND;
-}
+	if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
+		ULONG64 i;
 
-static int usbdk_cancel_transfer(struct usbi_transfer *itransfer)
-{
-	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+		for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) {
+			struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i];
 
-	switch (transfer->type) {
-	case LIBUSB_TRANSFER_TYPE_CONTROL:
-		// Control transfers cancelled by IoCancelXXX() API
-		// No special treatment needed
-		return LIBUSB_SUCCESS;
-	case LIBUSB_TRANSFER_TYPE_BULK:
-	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
-	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
-		return usbdk_abort_transfers(itransfer);
-	default:
-		usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
-		return LIBUSB_ERROR_INVALID_PARAM;
-	}
-}
-
-static int usbdk_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
-{
-	itransfer->transferred += io_size;
-	return LIBUSB_TRANSFER_COMPLETED;
-}
-
-static int usbdk_get_transfer_fd(struct usbi_transfer *itransfer)
-{
-	struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
-	return transfer_priv->pollable_fd.fd;
-}
-
-static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus)
-{
-	if (USBD_SUCCESS(UsbdStatus))
-		return NO_ERROR;
-
-	switch (UsbdStatus) {
-	case USBD_STATUS_TIMEOUT:
-		return ERROR_SEM_TIMEOUT;
-	case USBD_STATUS_CANCELED:
-		return ERROR_OPERATION_ABORTED;
-	default:
-		return ERROR_GEN_FAILURE;
-	}
-}
-
-static void usbdk_get_overlapped_result(struct usbi_transfer *itransfer, DWORD *io_result, DWORD *io_size)
-{
-	struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
-	struct winfd *pollable_fd = &transfer_priv->pollable_fd;
-
-	if (HasOverlappedIoCompletedSync(pollable_fd->overlapped) // Handle async requests that completed synchronously first
-			|| GetOverlappedResult(transfer_priv->system_handle, pollable_fd->overlapped, io_size, FALSE)) { // Regular async overlapped
-		struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-
-		if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
-			ULONG64 i;
-			for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) {
-				struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i];
-
-				switch (transfer_priv->IsochronousResultsArray[i].TransferResult) {
-				case STATUS_SUCCESS:
-				case STATUS_CANCELLED:
-				case STATUS_REQUEST_CANCELED:
-					lib_desc->status = LIBUSB_TRANSFER_COMPLETED; // == ERROR_SUCCESS
-					break;
-				default:
-					lib_desc->status = LIBUSB_TRANSFER_ERROR; // ERROR_UNKNOWN_EXCEPTION;
-					break;
-				}
-
-				lib_desc->actual_length = (unsigned int)transfer_priv->IsochronousResultsArray[i].ActualLength;
+			switch (transfer_priv->IsochronousResultsArray[i].TransferResult) {
+			case STATUS_SUCCESS:
+			case STATUS_CANCELLED:
+			case STATUS_REQUEST_CANCELED:
+				lib_desc->status = LIBUSB_TRANSFER_COMPLETED; // == ERROR_SUCCESS
+				break;
+			default:
+				lib_desc->status = LIBUSB_TRANSFER_ERROR; // ERROR_UNKNOWN_EXCEPTION;
+				break;
 			}
-		}
 
-		*io_size = (DWORD)transfer_priv->request.Result.GenResult.BytesTransferred;
-		*io_result = usbdk_translate_usbd_status((USBD_STATUS)transfer_priv->request.Result.GenResult.UsbdStatus);
-	} else {
-		*io_result = GetLastError();
+			lib_desc->actual_length = (unsigned int)transfer_priv->IsochronousResultsArray[i].ActualLength;
+		}
 	}
+
+	itransfer->transferred += (int)transfer_priv->request.Result.GenResult.BytesTransferred;
+	return usbd_status_to_libusb_transfer_status((USBD_STATUS)transfer_priv->request.Result.GenResult.UsbdStatus);
 }
 
 const struct windows_backend usbdk_backend = {
@@ -837,9 +717,7 @@
 	usbdk_reset_device,
 	usbdk_destroy_device,
 	usbdk_submit_transfer,
-	usbdk_cancel_transfer,
+	NULL,	/* cancel_transfer */
 	usbdk_clear_transfer_priv,
 	usbdk_copy_transfer_data,
-	usbdk_get_transfer_fd,
-	usbdk_get_overlapped_result,
 };
diff --git a/libusb/os/windows_winusb.c b/libusb/os/windows_winusb.c
index 7cb17be..ce4d3a1 100644
--- a/libusb/os/windows_winusb.c
+++ b/libusb/os/windows_winusb.c
@@ -42,13 +42,7 @@
 
 #define HANDLE_VALID(h) (((h) != NULL) && ((h) != INVALID_HANDLE_VALUE))
 
-// The 2 macros below are used in conjunction with safe loops.
-#define LOOP_CHECK(fcall)			\
-	{					\
-		r = fcall;			\
-		if (r != LIBUSB_SUCCESS)	\
-			continue;		\
-	}
+// The below macro is used in conjunction with safe loops.
 #define LOOP_BREAK(err)				\
 	{					\
 		r = err;			\
@@ -56,7 +50,7 @@
 	}
 
 // WinUSB-like API prototypes
-static int winusbx_init(struct libusb_context *ctx);
+static bool winusbx_init(struct libusb_context *ctx);
 static void winusbx_exit(void);
 static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle);
 static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle);
@@ -68,12 +62,11 @@
 static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer);
 static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer);
 static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
-static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer);
-static int winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer);
+static int winusbx_cancel_transfer(int sub_api, struct usbi_transfer *itransfer);
 static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
-static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size);
+static enum libusb_transfer_status winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length);
 // HID API prototypes
-static int hid_init(struct libusb_context *ctx);
+static bool hid_init(struct libusb_context *ctx);
 static void hid_exit(void);
 static int hid_open(int sub_api, struct libusb_device_handle *dev_handle);
 static void hid_close(int sub_api, struct libusb_device_handle *dev_handle);
@@ -83,9 +76,8 @@
 static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer);
 static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer);
 static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
-static int hid_abort_transfers(int sub_api, struct usbi_transfer *itransfer);
 static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
-static int hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size);
+static enum libusb_transfer_status hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length);
 // Composite API prototypes
 static int composite_open(int sub_api, struct libusb_device_handle *dev_handle);
 static void composite_close(int sub_api, struct libusb_device_handle *dev_handle);
@@ -96,28 +88,25 @@
 static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer);
 static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer);
 static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
-static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfer);
-static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer);
+static int composite_cancel_transfer(int sub_api, struct usbi_transfer *itransfer);
 static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
-static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size);
+static enum libusb_transfer_status composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length);
 
 static usbi_mutex_t autoclaim_lock;
 
 // API globals
-static HMODULE WinUSBX_handle = NULL;
 static struct winusb_interface WinUSBX[SUB_API_MAX];
 #define CHECK_WINUSBX_AVAILABLE(sub_api)		\
 	do {						\
 		if (sub_api == SUB_API_NOTSET)		\
 			sub_api = priv->sub_api;	\
-		if (!WinUSBX[sub_api].initialized)	\
+		if (WinUSBX[sub_api].hDll == NULL)	\
 			return LIBUSB_ERROR_ACCESS;	\
 	} while (0)
 
-static bool api_hid_available = false;
 #define CHECK_HID_AVAILABLE				\
 	do {						\
-		if (!api_hid_available)			\
+		if (DLL_HANDLE_NAME(hid) == NULL)	\
 			return LIBUSB_ERROR_ACCESS;	\
 	} while (0)
 
@@ -183,40 +172,40 @@
 /*
  * Cfgmgr32, AdvAPI32, OLE32 and SetupAPI DLL functions
  */
-static BOOL init_dlls(void)
+static bool init_dlls(void)
 {
 	DLL_GET_HANDLE(Cfgmgr32);
-	DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Parent, TRUE);
-	DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Child, TRUE);
+	DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Parent, true);
+	DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Child, true);
 
 	// Prefixed to avoid conflict with header files
 	DLL_GET_HANDLE(AdvAPI32);
-	DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExW, TRUE);
-	DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegCloseKey, TRUE);
+	DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExW, true);
+	DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegCloseKey, true);
 
 	DLL_GET_HANDLE(OLE32);
-	DLL_LOAD_FUNC_PREFIXED(OLE32, p, IIDFromString, TRUE);
+	DLL_LOAD_FUNC_PREFIXED(OLE32, p, IIDFromString, true);
 
 	DLL_GET_HANDLE(SetupAPI);
-	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetClassDevsA, TRUE);
-	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInfo, TRUE);
-	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInterfaces, TRUE);
-	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInstanceIdA, TRUE);
-	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInterfaceDetailA, TRUE);
-	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceRegistryPropertyA, TRUE);
-	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiDestroyDeviceInfoList, TRUE);
-	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDevRegKey, TRUE);
-	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDeviceInterfaceRegKey, TRUE);
+	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetClassDevsA, true);
+	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInfo, true);
+	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInterfaces, true);
+	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInstanceIdA, true);
+	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInterfaceDetailA, true);
+	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceRegistryPropertyA, true);
+	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiDestroyDeviceInfoList, true);
+	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDevRegKey, true);
+	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDeviceInterfaceRegKey, true);
 
-	return TRUE;
+	return true;
 }
 
 static void exit_dlls(void)
 {
-	DLL_FREE_HANDLE(Cfgmgr32);
-	DLL_FREE_HANDLE(AdvAPI32);
-	DLL_FREE_HANDLE(OLE32);
 	DLL_FREE_HANDLE(SetupAPI);
+	DLL_FREE_HANDLE(OLE32);
+	DLL_FREE_HANDLE(AdvAPI32);
+	DLL_FREE_HANDLE(Cfgmgr32);
 }
 
 /*
@@ -391,13 +380,13 @@
 			goto err_exit;
 		}
 	} else {
-		usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong.");
+		usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong");
 		goto err_exit;
 	}
 
-	dev_interface_details = calloc(1, size);
+	dev_interface_details = malloc(size);
 	if (dev_interface_details == NULL) {
-		usbi_err(ctx, "could not allocate interface data for index %u.", _index);
+		usbi_err(ctx, "could not allocate interface data for index %u", _index);
 		goto err_exit;
 	}
 
@@ -468,7 +457,8 @@
 {
 	const struct libusb_interface *intf;
 	const struct libusb_interface_descriptor *intf_desc;
-	int i, j, k;
+	uint8_t i, k;
+	int j;
 
 	for (i = 0; i < conf_desc->bNumInterfaces; i++) {
 		intf = &conf_desc->interface[i];
@@ -492,15 +482,14 @@
  */
 static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, int iface, int altsetting)
 {
-	int i, r;
 	struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
 	struct libusb_config_descriptor *conf_desc;
 	const struct libusb_interface_descriptor *if_desc;
-	struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+	int i, r;
 
 	r = libusb_get_active_config_descriptor(dev_handle->dev, &conf_desc);
 	if (r != LIBUSB_SUCCESS) {
-		usbi_warn(ctx, "could not read config descriptor: error %d", r);
+		usbi_warn(HANDLE_CTX(dev_handle), "could not read config descriptor: error %d", r);
 		return r;
 	}
 
@@ -541,10 +530,10 @@
 // return -1 if not found, driver match number otherwise
 static int get_sub_api(char *driver, int api)
 {
-	int i;
 	const char sep_str[2] = {LIST_SEPARATOR, 0};
 	char *tok, *tmp_str;
 	size_t len = strlen(driver);
+	int i;
 
 	if (len == 0)
 		return SUB_API_NOTSET;
@@ -573,7 +562,6 @@
  */
 static int auto_claim(struct libusb_transfer *transfer, int *interface_number, int api_type)
 {
-	struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
 	struct winusb_device_handle_priv *handle_priv = _device_handle_priv(
 		transfer->dev_handle);
 	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
@@ -596,13 +584,13 @@
 					&& (libusb_claim_interface(transfer->dev_handle, current_interface) == LIBUSB_SUCCESS)) {
 				usbi_dbg("auto-claimed interface %d for control request", current_interface);
 				if (handle_priv->autoclaim_count[current_interface] != 0)
-					usbi_warn(ctx, "program assertion failed - autoclaim_count was nonzero");
+					usbi_err(TRANSFER_CTX(transfer), "program assertion failed - autoclaim_count was nonzero");
 				handle_priv->autoclaim_count[current_interface]++;
 				break;
 			}
 		}
 		if (current_interface == USB_MAXINTERFACES) {
-			usbi_err(ctx, "could not auto-claim any interface");
+			usbi_err(TRANSFER_CTX(transfer), "could not auto-claim any interface");
 			r = LIBUSB_ERROR_NOT_FOUND;
 		}
 	} else {
@@ -619,7 +607,7 @@
 
 static void auto_release(struct usbi_transfer *itransfer)
 {
-	struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+	struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
 	libusb_device_handle *dev_handle = transfer->dev_handle;
 	struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
@@ -647,9 +635,6 @@
 {
 	int i;
 
-	// We need a lock for proper auto-release
-	usbi_mutex_init(&autoclaim_lock);
-
 	// Load DLL imports
 	if (!init_dlls()) {
 		usbi_err(ctx, "could not resolve DLL functions");
@@ -658,11 +643,14 @@
 
 	// Initialize the low level APIs (we don't care about errors at this stage)
 	for (i = 0; i < USB_API_MAX; i++) {
-		if (usb_api_backend[i].init && usb_api_backend[i].init(ctx))
+		if (usb_api_backend[i].init && !usb_api_backend[i].init(ctx))
 			usbi_warn(ctx, "error initializing %s backend",
 				usb_api_backend[i].designation);
 	}
 
+	// We need a lock for proper auto-release
+	usbi_mutex_init(&autoclaim_lock);
+
 	return LIBUSB_SUCCESS;
 }
 
@@ -675,13 +663,14 @@
 
 	UNUSED(ctx);
 
+	usbi_mutex_destroy(&autoclaim_lock);
+
 	for (i = 0; i < USB_API_MAX; i++) {
 		if (usb_api_backend[i].exit)
 			usb_api_backend[i].exit();
 	}
 
 	exit_dlls();
-	usbi_mutex_destroy(&autoclaim_lock);
 }
 
 /*
@@ -701,6 +690,8 @@
 	if (dev->num_configurations == 0)
 		return;
 
+	assert(sizeof(USB_DESCRIPTOR_REQUEST) == USB_DESCRIPTOR_REQUEST_SIZE);
+
 	priv->config_descriptor = calloc(dev->num_configurations, sizeof(PUSB_CONFIGURATION_DESCRIPTOR));
 	if (priv->config_descriptor == NULL) {
 		usbi_err(ctx, "could not allocate configuration descriptor array for '%s'", priv->dev_id);
@@ -714,7 +705,7 @@
 			break;
 
 		size = sizeof(cd_buf_short);
-		memset(&cd_buf_short, 0, size);
+		memset(&cd_buf_short.desc, 0, sizeof(cd_buf_short.desc));
 
 		cd_buf_short.req.ConnectionIndex = (ULONG)dev->port_number;
 		cd_buf_short.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
@@ -758,7 +749,7 @@
 			continue;
 		}
 
-		cd_data = (PUSB_CONFIGURATION_DESCRIPTOR)((UCHAR *)cd_buf_actual + sizeof(USB_DESCRIPTOR_REQUEST));
+		cd_data = (PUSB_CONFIGURATION_DESCRIPTOR)((UCHAR *)cd_buf_actual + USB_DESCRIPTOR_REQUEST_SIZE);
 
 		if ((size != ret_size) || (cd_data->wTotalLength != cd_buf_short.desc.wTotalLength)) {
 			usbi_err(ctx, "unexpected configuration descriptor %u size (actual) for '%s'", i, priv->dev_id);
@@ -774,12 +765,8 @@
 			i, cd_data->bConfigurationValue, cd_data->wTotalLength);
 
 		// Cache the descriptor
-		priv->config_descriptor[i] = malloc(cd_data->wTotalLength);
-		if (priv->config_descriptor[i] != NULL) {
-			memcpy(priv->config_descriptor[i], cd_data, cd_data->wTotalLength);
-		} else {
-			usbi_err(ctx, "could not allocate configuration descriptor %u buffer for '%s'", i, priv->dev_id);
-		}
+		priv->config_descriptor[i] = cd_data;
+		cd_buf_actual = NULL;
 	}
 }
 
@@ -853,7 +840,6 @@
 			return LIBUSB_ERROR_ACCESS;
 		}
 
-		memset(&conn_info, 0, sizeof(conn_info));
 		conn_info.ConnectionIndex = (ULONG)port_number;
 		// coverity[tainted_data_argument]
 		ginfotimeout = 20;
@@ -873,31 +859,28 @@
 			}
 
 			memcpy(&priv->dev_descriptor, &(conn_info.DeviceDescriptor), sizeof(USB_DEVICE_DESCRIPTOR));
-			dev->num_configurations = priv->dev_descriptor.bNumConfigurations;
+			dev->num_configurations = conn_info.DeviceDescriptor.bNumConfigurations;
 			priv->active_config = conn_info.CurrentConfigurationValue;
 			if (priv->active_config == 0) {
-				usbi_dbg("0x%x:0x%x found %u configurations (active conf: %u) \n",
+				usbi_dbg("0x%x:0x%x found %u configurations (not configured)",
 					priv->dev_descriptor.idVendor,
 					priv->dev_descriptor.idProduct,
-					dev->num_configurations,
-					priv->active_config);
+					dev->num_configurations);
+				SleepEx(50, TRUE);
 			}
-			if (priv->active_config == 0)
-				Sleep(50);
 		} while (priv->active_config == 0 && --ginfotimeout >= 0);
 
 		if (priv->active_config == 0) {
-			usbi_dbg("after try 0x%x:0x%x found %u configurations (active conf: %u) \n",
+			usbi_info(ctx, "0x%x:0x%x found %u configurations but device isn't configured, "
+				"forcing current configuration to 1",
 				priv->dev_descriptor.idVendor,
 				priv->dev_descriptor.idProduct,
-				dev->num_configurations,
-				priv->active_config);
-			usbi_dbg("Force this device active config to 1 in libusb! \nNOTICE: Should not reach this place!!!!!! \n");
+				dev->num_configurations);
 			priv->active_config = 1;
+		} else {
+			usbi_dbg("found %u configurations (current config: %u)", dev->num_configurations, priv->active_config);
 		}
 
-		usbi_dbg("found %u configurations (active conf: %u)", dev->num_configurations, priv->active_config);
-
 		// Cache as many config descriptors as we can
 		cache_config_descriptors(dev, hub_handle);
 
@@ -964,7 +947,7 @@
 	session_id = (unsigned long)child_devinst;
 	dev = usbi_get_device_by_session_id(ctx, session_id);
 	if (dev == NULL) {
-		usbi_warn(ctx, "program assertion failed - HCD '%s' child not found", dev_id);
+		usbi_err(ctx, "program assertion failed - HCD '%s' child not found", dev_id);
 		return LIBUSB_SUCCESS;
 	}
 
@@ -1093,20 +1076,20 @@
 static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *dev,
 	char *dev_interface_path)
 {
-	int i;
 	struct winusb_device_priv *priv = _device_priv(dev);
+	uint8_t i;
 
 	if (priv->hid == NULL) {
-		usbi_err(ctx, "program assertion failed: parent is not HID");
+		usbi_err(ctx, "program assertion failed - parent is not HID");
 		return LIBUSB_ERROR_NO_DEVICE;
 	} else if (priv->hid->nb_interfaces == USB_MAXINTERFACES) {
-		usbi_err(ctx, "program assertion failed: max USB interfaces reached for HID device");
+		usbi_err(ctx, "program assertion failed - max USB interfaces reached for HID device");
 		return LIBUSB_ERROR_NO_DEVICE;
 	}
 
 	for (i = 0; i < priv->hid->nb_interfaces; i++) {
 		if ((priv->usb_interface[i].path != NULL) && strcmp(priv->usb_interface[i].path, dev_interface_path) == 0) {
-			usbi_dbg("interface[%d] already set to %s", i, dev_interface_path);
+			usbi_dbg("interface[%u] already set to %s", i, dev_interface_path);
 			return LIBUSB_ERROR_ACCESS;
 		}
 	}
@@ -1182,7 +1165,7 @@
 	guid_list[DEV_PASS] = &GUID_DEVINTERFACE_USB_DEVICE;
 	guid_list[HCD_PASS] = &GUID_DEVINTERFACE_USB_HOST_CONTROLLER;
 	guid_list[GEN_PASS] = NULL;
-	if (api_hid_available) {
+	if (HidD_GetHidGuid != NULL) {
 		HidD_GetHidGuid(&hid_guid);
 		guid_list[HID_PASS] = &hid_guid;
 	} else {
@@ -1228,7 +1211,7 @@
 				break;
 
 			if ((pass == HCD_PASS) && (i == UINT8_MAX)) {
-				usbi_warn(ctx, "program assertion failed - found more than %u buses, skipping the rest.", UINT8_MAX);
+				usbi_warn(ctx, "program assertion failed - found more than %u buses, skipping the rest", UINT8_MAX);
 				break;
 			}
 
@@ -1741,14 +1724,11 @@
 
 static void winusb_clear_transfer_priv(struct usbi_transfer *itransfer)
 {
-	struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+	struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
 	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
 	int sub_api = priv->sub_api;
 
-	usbi_close(transfer_priv->pollable_fd.fd);
-	transfer_priv->pollable_fd = INVALID_WINFD;
-	transfer_priv->handle = NULL;
 	safe_free(transfer_priv->hid_buffer);
 
 	if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS && sub_api == SUB_API_WINUSB) {
@@ -1756,7 +1736,7 @@
 			if (WinUSBX[sub_api].UnregisterIsochBuffer(transfer_priv->isoch_buffer_handle)) {
 				transfer_priv->isoch_buffer_handle = NULL;
 			} else {
-				usbi_dbg("Couldn't unregister isoch buffer!");
+				usbi_warn(TRANSFER_CTX(transfer), "failed to unregister WinUSB isoch buffer: %s", windows_error_str(0));
 			}
 		}
 	}
@@ -1767,64 +1747,28 @@
 	auto_release(itransfer);
 }
 
-static int do_submit_transfer(struct usbi_transfer *itransfer, short events,
-	int (*transfer_fn)(int, struct usbi_transfer *))
-{
-	struct libusb_context *ctx = ITRANSFER_CTX(itransfer);
-	struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
-	struct winfd wfd;
-	int r;
-
-	wfd = usbi_create_fd();
-	if (wfd.fd < 0)
-		return LIBUSB_ERROR_NO_MEM;
-
-	r = usbi_add_pollfd(ctx, wfd.fd, events);
-	if (r) {
-		usbi_close(wfd.fd);
-		return r;
-	}
-
-	// Use transfer_priv to store data needed for async polling
-	transfer_priv->pollable_fd = wfd;
-
-	r = transfer_fn(SUB_API_NOTSET, itransfer);
-
-	if ((r != LIBUSB_SUCCESS) && (r != LIBUSB_ERROR_OVERFLOW)) {
-		usbi_remove_pollfd(ctx, wfd.fd);
-		usbi_close(wfd.fd);
-		transfer_priv->pollable_fd = INVALID_WINFD;
-	}
-
-	return r;
-}
-
 static int winusb_submit_transfer(struct usbi_transfer *itransfer)
 {
 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
 	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
 	int (*transfer_fn)(int, struct usbi_transfer *);
-	short events;
 
 	switch (transfer->type) {
 	case LIBUSB_TRANSFER_TYPE_CONTROL:
-		events = (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) ? POLLIN : POLLOUT;
 		transfer_fn = priv->apib->submit_control_transfer;
 		break;
 	case LIBUSB_TRANSFER_TYPE_BULK:
 	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
 		if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
 			return LIBUSB_ERROR_NOT_SUPPORTED;
-		events = IS_XFERIN(transfer) ? POLLIN : POLLOUT;
 		transfer_fn = priv->apib->submit_bulk_transfer;
 		break;
 	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
-		events = IS_XFERIN(transfer) ? POLLIN : POLLOUT;
 		transfer_fn = priv->apib->submit_iso_transfer;
 		break;
-	case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
-		return LIBUSB_ERROR_NOT_SUPPORTED;
 	default:
+		// Should not get here since windows_submit_transfer() validates
+		// the transfer->type field
 		usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
 		return LIBUSB_ERROR_INVALID_PARAM;
 	}
@@ -1836,76 +1780,30 @@
 		return LIBUSB_ERROR_NOT_SUPPORTED;
 	}
 
-	return do_submit_transfer(itransfer, events, transfer_fn);
-}
-
-static int windows_abort_control(struct usbi_transfer *itransfer)
-{
-	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
-
-	CHECK_SUPPORTED_API(priv->apib, abort_control);
-
-	return priv->apib->abort_control(SUB_API_NOTSET, itransfer);
-}
-
-static int windows_abort_transfers(struct usbi_transfer *itransfer)
-{
-	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
-
-	CHECK_SUPPORTED_API(priv->apib, abort_transfers);
-
-	return priv->apib->abort_transfers(SUB_API_NOTSET, itransfer);
+	return transfer_fn(SUB_API_NOTSET, itransfer);
 }
 
 static int winusb_cancel_transfer(struct usbi_transfer *itransfer)
 {
 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
 
-	switch (transfer->type) {
-	case LIBUSB_TRANSFER_TYPE_CONTROL:
-		return windows_abort_control(itransfer);
-	case LIBUSB_TRANSFER_TYPE_BULK:
-	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
-	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
-		return windows_abort_transfers(itransfer);
-	case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
-		return LIBUSB_ERROR_NOT_SUPPORTED;
-	default:
-		usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
-		return LIBUSB_ERROR_INVALID_PARAM;
-	}
+	CHECK_SUPPORTED_API(priv->apib, cancel_transfer);
+
+	return priv->apib->cancel_transfer(SUB_API_NOTSET, itransfer);
 }
 
-static int winusb_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
+static enum libusb_transfer_status winusb_copy_transfer_data(struct usbi_transfer *itransfer, DWORD length)
 {
 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
 	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
-	return priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, io_size);
-}
 
-static int winusb_get_transfer_fd(struct usbi_transfer *itransfer)
-{
-	struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
-	return transfer_priv->pollable_fd.fd;
-}
-
-static void winusb_get_overlapped_result(struct usbi_transfer *itransfer,
-	DWORD *io_result, DWORD *io_size)
-{
-	struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
-	struct winfd *pollable_fd = &transfer_priv->pollable_fd;
-
-	if (HasOverlappedIoCompletedSync(pollable_fd->overlapped)) {
-		*io_result = NO_ERROR;
-		*io_size = (DWORD)pollable_fd->overlapped->InternalHigh;
-	} else if (GetOverlappedResult(transfer_priv->handle, pollable_fd->overlapped, io_size, FALSE)) {
-		// Regular async overlapped
-		*io_result = NO_ERROR;
-	} else {
-		*io_result = GetLastError();
+	if (priv->apib->copy_transfer_data == NULL) {
+		usbi_err(TRANSFER_CTX(transfer), "program assertion failed - no function to copy transfer data");
+		return LIBUSB_TRANSFER_ERROR;
 	}
+
+	return priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, length);
 }
 
 // NB: MSVC6 does not support named initializers.
@@ -1931,8 +1829,6 @@
 	winusb_cancel_transfer,
 	winusb_clear_transfer_priv,
 	winusb_copy_transfer_data,
-	winusb_get_transfer_fd,
-	winusb_get_overlapped_result,
 };
 
 /*
@@ -1971,8 +1867,7 @@
 		composite_submit_bulk_transfer,
 		composite_submit_iso_transfer,
 		composite_submit_control_transfer,
-		composite_abort_control,
-		composite_abort_transfers,
+		composite_cancel_transfer,
 		composite_copy_transfer_data,
 	},
 	{
@@ -1993,8 +1888,7 @@
 		winusbx_submit_bulk_transfer,
 		winusbx_submit_iso_transfer,
 		winusbx_submit_control_transfer,
-		winusbx_abort_control,
-		winusbx_abort_transfers,
+		winusbx_cancel_transfer,
 		winusbx_copy_transfer_data,
 	},
 	{
@@ -2015,8 +1909,7 @@
 		hid_submit_bulk_transfer,
 		NULL,	/* submit_iso_transfer */
 		hid_submit_control_transfer,
-		hid_abort_transfers,
-		hid_abort_transfers,
+		NULL,	/* cancel_transfer */
 		hid_copy_transfer_data,
 	},
 };
@@ -2025,105 +1918,159 @@
 /*
  * WinUSB-like (WinUSB, libusb0/libusbK through libusbk DLL) API functions
  */
-#define WinUSBX_Set(fn)										\
+#define WinUSB_Set(h, fn, required)										\
 	do {											\
-		if (native_winusb)								\
-			WinUSBX[i].fn = (WinUsb_##fn##_t)GetProcAddress(h, "WinUsb_" #fn);	\
-		else										\
-			pLibK_GetProcAddress((PVOID *)&WinUSBX[i].fn, i, KUSB_FNID_##fn);	\
+		WinUSBX[SUB_API_WINUSB].fn = (WinUsb_##fn##_t)GetProcAddress(h, "WinUsb_" #fn);	\
+		if (required && (WinUSBX[SUB_API_WINUSB].fn == NULL)) {				\
+			usbi_err(ctx, "GetProcAddress() failed for WinUsb_%s", #fn);		\
+			goto cleanup_winusb;							\
+		}										\
 	} while (0)
 
-#define NativeWinUSBOnly_Set(fn)								\
+#define libusbK_Set(sub_api, fn, required)								\
 	do {											\
-		if (native_winusb)								\
-			WinUSBX[i].fn = (WinUsb_##fn##_t)GetProcAddress(h, "WinUsb_" #fn);	\
-		else                                                                            \
-			WinUSBX[i].fn = NULL;                                                   \
+		pLibK_GetProcAddress((PVOID *)&WinUSBX[sub_api].fn, sub_api, KUSB_FNID_##fn);	\
+		if (required && (WinUSBX[sub_api].fn == NULL)) {				\
+			usbi_err(ctx, "LibK_GetProcAddress() failed for LibK_%s", #fn);		\
+			goto cleanup_libusbk;							\
+		}										\
 	} while (0)
 
-static int winusbx_init(struct libusb_context *ctx)
+static bool winusbx_init(struct libusb_context *ctx)
 {
-	HMODULE h;
-	bool native_winusb;
-	int i;
-	KLIB_VERSION LibK_Version;
-	LibK_GetProcAddress_t pLibK_GetProcAddress = NULL;
-	LibK_GetVersion_t pLibK_GetVersion;
+	HMODULE hWinUSB, hlibusbK;
 
-	h = LoadLibraryA("libusbK");
+	hWinUSB = LoadLibraryA("WinUSB");
+	if (hWinUSB != NULL) {
+		WinUSB_Set(hWinUSB, AbortPipe, true);
+		WinUSB_Set(hWinUSB, ControlTransfer, true);
+		WinUSB_Set(hWinUSB, FlushPipe, true);
+		WinUSB_Set(hWinUSB, Free, true);
+		WinUSB_Set(hWinUSB, GetAssociatedInterface, true);
+		WinUSB_Set(hWinUSB, Initialize, true);
+		WinUSB_Set(hWinUSB, ReadPipe, true);
+		WinUSB_Set(hWinUSB, ResetPipe, true);
+		WinUSB_Set(hWinUSB, SetCurrentAlternateSetting, true);
+		WinUSB_Set(hWinUSB, SetPipePolicy, true);
+		WinUSB_Set(hWinUSB, WritePipe, true);
 
-	if (h == NULL) {
-		usbi_info(ctx, "libusbK DLL is not available, will use native WinUSB");
-		h = LoadLibraryA("WinUSB");
+		// Check for isochronous transfers support (available starting with Windows 8.1)
+		WinUSB_Set(hWinUSB, ReadIsochPipeAsap, false);
+		if (WinUSBX[SUB_API_WINUSB].ReadIsochPipeAsap != NULL) {
+			WinUSB_Set(hWinUSB, QueryPipeEx, true);
+			WinUSB_Set(hWinUSB, RegisterIsochBuffer, true);
+			WinUSB_Set(hWinUSB, UnregisterIsochBuffer, true);
+			WinUSB_Set(hWinUSB, WriteIsochPipeAsap, true);
+		}
 
-		if (h == NULL) {
-			usbi_warn(ctx, "WinUSB DLL is not available either, "
-				"you will not be able to access devices outside of enumeration");
-			return LIBUSB_ERROR_NOT_FOUND;
+		WinUSBX[SUB_API_WINUSB].hDll = hWinUSB;
+
+		usbi_info(ctx, "WinUSB DLL available (%s isoch support)",
+			(WinUSBX[SUB_API_WINUSB].ReadIsochPipeAsap != NULL) ? "with" : "without");
+
+cleanup_winusb:
+		if (WinUSBX[SUB_API_WINUSB].hDll == NULL) {
+			usbi_err(ctx, "failed to initialize WinUSB");
+			memset(&WinUSBX[SUB_API_WINUSB], 0, sizeof(WinUSBX[SUB_API_WINUSB]));
+			FreeLibrary(hWinUSB);
+			hWinUSB = NULL;
 		}
 	} else {
-		usbi_dbg("using libusbK DLL for universal access");
-		pLibK_GetVersion = (LibK_GetVersion_t)GetProcAddress(h, "LibK_GetVersion");
+		usbi_info(ctx, "WinUSB DLL is not available");
+	}
+
+	hlibusbK = LoadLibraryA("libusbK");
+	if (hlibusbK != NULL) {
+		LibK_GetVersion_t pLibK_GetVersion;
+		LibK_GetProcAddress_t pLibK_GetProcAddress;
+		int sub_api = 0;
+
+		pLibK_GetVersion = (LibK_GetVersion_t)GetProcAddress(hlibusbK, "LibK_GetVersion");
 		if (pLibK_GetVersion != NULL) {
+			KLIB_VERSION LibK_Version;
+
 			pLibK_GetVersion(&LibK_Version);
-			usbi_dbg("libusbK version: %d.%d.%d.%d", LibK_Version.Major, LibK_Version.Minor,
+			usbi_dbg("libusbK DLL found, version: %d.%d.%d.%d", LibK_Version.Major, LibK_Version.Minor,
 				LibK_Version.Micro, LibK_Version.Nano);
+		} else {
+			usbi_dbg("libusbK DLL found, version unknown");
 		}
-		pLibK_GetProcAddress = (LibK_GetProcAddress_t)GetProcAddress(h, "LibK_GetProcAddress");
+
+		pLibK_GetProcAddress = (LibK_GetProcAddress_t)GetProcAddress(hlibusbK, "LibK_GetProcAddress");
 		if (pLibK_GetProcAddress == NULL) {
 			usbi_err(ctx, "LibK_GetProcAddress() not found in libusbK DLL");
-			FreeLibrary(h);
-			return LIBUSB_ERROR_NOT_FOUND;
+			goto cleanup_libusbk;
 		}
+
+		// NB: The below for loop works because the sub_api value for WinUSB
+		// is a higher value than that of libusbK and libusb0
+		for (; sub_api < SUB_API_WINUSB; sub_api++) {
+			libusbK_Set(sub_api, AbortPipe, true);
+			libusbK_Set(sub_api, ControlTransfer, true);
+			libusbK_Set(sub_api, FlushPipe, true);
+			libusbK_Set(sub_api, Free, true);
+			libusbK_Set(sub_api, GetAssociatedInterface, true);
+			libusbK_Set(sub_api, Initialize, true);
+			libusbK_Set(sub_api, ReadPipe, true);
+			libusbK_Set(sub_api, ResetPipe, true);
+			libusbK_Set(sub_api, SetCurrentAlternateSetting, true);
+			libusbK_Set(sub_api, SetPipePolicy, true);
+			libusbK_Set(sub_api, WritePipe, true);
+
+			// Optional isochronous support
+			libusbK_Set(sub_api, IsoReadPipe, false);
+			if (WinUSBX[sub_api].IsoReadPipe != NULL)
+				libusbK_Set(sub_api, IsoWritePipe, true);
+
+			// Optional device reset support
+			libusbK_Set(sub_api, ResetDevice, false);
+
+			WinUSBX[sub_api].hDll = hlibusbK;
+		}
+
+cleanup_libusbk:
+		if (sub_api < SUB_API_WINUSB) {
+			usbi_err(ctx, "failed to initialize libusbK");
+			while (sub_api >= 0) {
+				memset(&WinUSBX[sub_api], 0, sizeof(WinUSBX[sub_api]));
+				sub_api--;
+			}
+			FreeLibrary(hlibusbK);
+			hlibusbK = NULL;
+		}
+	} else {
+		usbi_info(ctx, "libusbK DLL is not available");
 	}
 
-	native_winusb = (pLibK_GetProcAddress == NULL);
-	for (i = 0; i < SUB_API_MAX; i++) {
-		WinUSBX_Set(AbortPipe);
-		WinUSBX_Set(ControlTransfer);
-		WinUSBX_Set(FlushPipe);
-		WinUSBX_Set(Free);
-		WinUSBX_Set(GetAssociatedInterface);
-		WinUSBX_Set(Initialize);
-		WinUSBX_Set(ReadPipe);
-		if (!native_winusb)
-			WinUSBX_Set(ResetDevice);
-		WinUSBX_Set(ResetPipe);
-		WinUSBX_Set(SetCurrentAlternateSetting);
-		WinUSBX_Set(SetPipePolicy);
-		WinUSBX_Set(WritePipe);
-		WinUSBX_Set(IsoReadPipe);
-		WinUSBX_Set(IsoWritePipe);
-		NativeWinUSBOnly_Set(RegisterIsochBuffer);
-		NativeWinUSBOnly_Set(UnregisterIsochBuffer);
-		NativeWinUSBOnly_Set(WriteIsochPipeAsap);
-		NativeWinUSBOnly_Set(ReadIsochPipeAsap);
-		NativeWinUSBOnly_Set(QueryPipeEx);
-
-		if (WinUSBX[i].Initialize != NULL) {
-			WinUSBX[i].initialized = true;
-			// Assume driver supports CancelIoEx()
-			WinUSBX[i].CancelIoEx_supported = true;
-			usbi_dbg("initalized sub API %s", winusbx_driver_names[i]);
-		} else {
-			usbi_warn(ctx, "Failed to initalize sub API %s", winusbx_driver_names[i]);
-			WinUSBX[i].initialized = false;
-		}
+	if ((hWinUSB == NULL) && (hlibusbK == NULL)) {
+		usbi_warn(ctx, "neither WinUSB nor libusbK DLLs were found, "
+			"you will not be able to access devices outside of enumeration");
+		return false;
 	}
 
-	WinUSBX_handle = h;
-	return LIBUSB_SUCCESS;
+	return true;
 }
 
 static void winusbx_exit(void)
 {
-	if (WinUSBX_handle != NULL) {
-		FreeLibrary(WinUSBX_handle);
-		WinUSBX_handle = NULL;
+	bool loaded = false;
+	HMODULE hDll;
 
-		/* Reset the WinUSBX API structures */
-		memset(&WinUSBX, 0, sizeof(WinUSBX));
+	hDll = WinUSBX[SUB_API_LIBUSBK].hDll;
+	if (hDll != NULL) {
+		FreeLibrary(hDll);
+		loaded = true;
 	}
+
+	hDll = WinUSBX[SUB_API_WINUSB].hDll;
+	if (hDll != NULL) {
+		FreeLibrary(hDll);
+		loaded = true;
+	}
+
+	// Reset the WinUSBX API structures if something was loaded
+	if (loaded)
+		memset(&WinUSBX, 0, sizeof(WinUSBX));
 }
 
 // NB: open and close must ensure that they only handle interface of
@@ -2131,7 +2078,6 @@
 // composite_open(), with interfaces belonging to different APIs
 static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle)
 {
-	struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
 	struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
 	struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
 	HANDLE file_handle;
@@ -2144,9 +2090,9 @@
 		if ((priv->usb_interface[i].path != NULL)
 				&& (priv->usb_interface[i].apib->id == USB_API_WINUSBX)) {
 			file_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
-				NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
+				NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
 			if (file_handle == INVALID_HANDLE_VALUE) {
-				usbi_err(ctx, "could not open device %s (interface %d): %s", priv->usb_interface[i].path, i, windows_error_str(0));
+				usbi_err(HANDLE_CTX(dev_handle), "could not open device %s (interface %d): %s", priv->usb_interface[i].path, i, windows_error_str(0));
 				switch (GetLastError()) {
 				case ERROR_FILE_NOT_FOUND: // The device was disconnected
 					return LIBUSB_ERROR_NO_DEVICE;
@@ -2173,7 +2119,7 @@
 	if (sub_api == SUB_API_NOTSET)
 		sub_api = priv->sub_api;
 
-	if (!WinUSBX[sub_api].initialized)
+	if (WinUSBX[sub_api].hDll == NULL)
 		return;
 
 	if (priv->apib->id == USB_API_COMPOSITE) {
@@ -2220,7 +2166,7 @@
 
 	CHECK_WINUSBX_AVAILABLE(sub_api);
 
-	// With handle and enpoints set (in parent), we can setup the default pipe properties
+	// With handle and endpoints set (in parent), we can setup the default pipe properties
 	// see http://download.microsoft.com/download/D/1/D/D1DD7745-426B-4CC3-A269-ABBBE427C0EF/DVC-T705_DDC08.pptx
 	for (i = -1; i < priv->usb_interface[iface].nb_endpoints; i++) {
 		endpoint_address = (i == -1) ? 0 : priv->usb_interface[iface].endpoint[i];
@@ -2263,7 +2209,7 @@
 
 static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface)
 {
-	struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+	struct libusb_context *ctx = HANDLE_CTX(dev_handle);
 	struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
 	struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
 	bool is_using_usbccgp = (priv->apib->id == USB_API_COMPOSITE);
@@ -2313,7 +2259,7 @@
 
 					if (strncmp(dev_path_no_guid, priv->usb_interface[iface].path, strlen(dev_path_no_guid)) == 0) {
 						file_handle = CreateFileA(filter_path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
-							NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
+							NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
 						if (file_handle != INVALID_HANDLE_VALUE) {
 							if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) {
 								// Replace the existing file handle with the working one
@@ -2467,12 +2413,11 @@
 static int winusbx_submit_control_transfer(int sub_api, 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 winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
-	struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+	struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
 	struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
 	PWINUSB_SETUP_PACKET setup = (PWINUSB_SETUP_PACKET)transfer->buffer;
-	ULONG size, transferred;
+	ULONG size;
 	HANDLE winusb_handle;
 	OVERLAPPED *overlapped;
 	int current_interface;
@@ -2497,26 +2442,25 @@
 
 	usbi_dbg("will use interface %d", current_interface);
 
-	transfer_priv->handle = winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
-	overlapped = transfer_priv->pollable_fd.overlapped;
+	winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
+	set_transfer_priv_handle(itransfer, handle_priv->interface_handle[current_interface].dev_handle);
+	overlapped = get_transfer_priv_overlapped(itransfer);
 
 	// Sending of set configuration control requests from WinUSB creates issues, except when using libusb0.sys
 	if (sub_api != SUB_API_LIBUSB0
 			&& (LIBUSB_REQ_TYPE(setup->RequestType) == LIBUSB_REQUEST_TYPE_STANDARD)
 			&& (setup->Request == LIBUSB_REQUEST_SET_CONFIGURATION)) {
 		if (setup->Value != priv->active_config) {
-			usbi_warn(ctx, "cannot set configuration other than the default one");
+			usbi_warn(TRANSFER_CTX(transfer), "cannot set configuration other than the default one");
 			return LIBUSB_ERROR_INVALID_PARAM;
 		}
 		windows_force_sync_completion(overlapped, 0);
 	} else {
-		if (!WinUSBX[sub_api].ControlTransfer(winusb_handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, &transferred, overlapped)) {
+		if (!WinUSBX[sub_api].ControlTransfer(winusb_handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, overlapped)) {
 			if (GetLastError() != ERROR_IO_PENDING) {
-				usbi_warn(ctx, "ControlTransfer failed: %s", windows_error_str(0));
+				usbi_warn(TRANSFER_CTX(transfer), "ControlTransfer failed: %s", windows_error_str(0));
 				return LIBUSB_ERROR_IO;
 			}
-		} else {
-			windows_force_sync_completion(overlapped, transferred);
 		}
 	}
 
@@ -2527,7 +2471,6 @@
 
 static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting)
 {
-	struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
 	struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
 	struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
 	HANDLE winusb_handle;
@@ -2539,37 +2482,18 @@
 
 	winusb_handle = handle_priv->interface_handle[iface].api_handle;
 	if (!HANDLE_VALID(winusb_handle)) {
-		usbi_err(ctx, "interface must be claimed first");
+		usbi_err(HANDLE_CTX(dev_handle), "interface must be claimed first");
 		return LIBUSB_ERROR_NOT_FOUND;
 	}
 
 	if (!WinUSBX[sub_api].SetCurrentAlternateSetting(winusb_handle, (UCHAR)altsetting)) {
-		usbi_err(ctx, "SetCurrentAlternateSetting failed: %s", windows_error_str(0));
+		usbi_err(HANDLE_CTX(dev_handle), "SetCurrentAlternateSetting failed: %s", windows_error_str(0));
 		return LIBUSB_ERROR_IO;
 	}
 
 	return LIBUSB_SUCCESS;
 }
 
-static enum libusb_transfer_status usbd_status_to_libusb_transfer_status(USBD_STATUS status)
-{
-	if (USBD_SUCCESS(status))
-		return LIBUSB_TRANSFER_COMPLETED;
-
-	switch (status) {
-	case USBD_STATUS_TIMEOUT:
-		return LIBUSB_TRANSFER_TIMED_OUT;
-	case USBD_STATUS_CANCELED:
-		return LIBUSB_TRANSFER_CANCELLED;
-	case USBD_STATUS_ENDPOINT_HALTED:
-		return LIBUSB_TRANSFER_STALL;
-	case USBD_STATUS_DEVICE_GONE:
-		return LIBUSB_TRANSFER_NO_DEVICE;
-	default:
-		usbi_dbg("USBD_STATUS 0x%08lx translated to LIBUSB_TRANSFER_ERROR", ULONG_CAST(status));
-		return LIBUSB_TRANSFER_ERROR;
-	}
-}
 
 static void WINAPI winusbx_native_iso_transfer_continue_stream_callback(struct libusb_transfer *transfer)
 {
@@ -2578,27 +2502,24 @@
 	// The role of this callback is to fallback to ContinueStream = FALSE if the transfer
 	// did not succeed.
 
-	struct winusb_transfer_priv *transfer_priv = (struct winusb_transfer_priv *)
-		usbi_transfer_get_os_priv(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer));
-	BOOL fallback = (transfer->status != LIBUSB_TRANSFER_COMPLETED);
+	struct winusb_transfer_priv *transfer_priv =
+		get_winusb_transfer_priv(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer));
+	bool fallback = (transfer->status != LIBUSB_TRANSFER_COMPLETED);
 	int idx;
 
 	// Restore the user callback
 	transfer->callback = transfer_priv->iso_user_callback;
 
-	for (idx = 0; idx < transfer->num_iso_packets && !fallback; ++idx) {
-		if (transfer->iso_packet_desc[idx].status != LIBUSB_TRANSFER_COMPLETED) {
-			fallback = TRUE;
-		}
+	for (idx = 0; idx < transfer->num_iso_packets && !fallback; idx++) {
+		if (transfer->iso_packet_desc[idx].status != LIBUSB_TRANSFER_COMPLETED)
+			fallback = true;
 	}
 
 	if (!fallback) {
 		// If the transfer was successful, we restore the user callback and call it.
-		if (transfer->callback) {
+		if (transfer->callback)
 			transfer->callback(transfer);
-		}
-	}
-	else {
+	} else {
 		// If the transfer wasn't successful we reschedule the transfer while forcing it
 		// not to continue the stream. This might results in a 5-ms delay.
 		transfer_priv->iso_break_stream = TRUE;
@@ -2608,27 +2529,27 @@
 static int winusbx_submit_iso_transfer(int sub_api, 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 winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+	struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
 	struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
 	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
 	HANDLE winusb_handle;
 	OVERLAPPED *overlapped;
-	bool ret;
+	BOOL ret;
 	int current_interface;
 
 	CHECK_WINUSBX_AVAILABLE(sub_api);
 
 	current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
 	if (current_interface < 0) {
-		usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
+		usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer");
 		return LIBUSB_ERROR_NOT_FOUND;
-	} else {
-		usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
 	}
 
-	transfer_priv->handle = winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
-	overlapped = transfer_priv->pollable_fd.overlapped;
+	usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
+
+	winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
+	set_transfer_priv_handle(itransfer, handle_priv->interface_handle[current_interface].dev_handle);
+	overlapped = get_transfer_priv_overlapped(itransfer);
 
 	if ((sub_api == SUB_API_LIBUSBK) || (sub_api == SUB_API_LIBUSB0)) {
 		int i;
@@ -2636,6 +2557,11 @@
 		size_t iso_ctx_size;
 		PKISO_CONTEXT iso_context;
 
+		if (WinUSBX[sub_api].IsoReadPipe == NULL) {
+			usbi_warn(TRANSFER_CTX(transfer), "libusbK DLL does not support isoch transfers");
+			return LIBUSB_ERROR_NOT_SUPPORTED;
+		}
+
 		iso_ctx_size = sizeof(KISO_CONTEXT) + (transfer->num_iso_packets * sizeof(KISO_PACKET));
 		transfer_priv->iso_context = iso_context = calloc(1, iso_ctx_size);
 		if (transfer_priv->iso_context == NULL)
@@ -2660,42 +2586,29 @@
 			ret = WinUSBX[sub_api].IsoWritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, overlapped, iso_context);
 		}
 
-		if (!ret) {
-			if (GetLastError() != ERROR_IO_PENDING) {
-				usbi_err(ctx, "IsoReadPipe/IsoWritePipe failed: %s", windows_error_str(0));
-				return LIBUSB_ERROR_IO;
-			}
-		} else {
-			windows_force_sync_completion(overlapped, (ULONG)transfer->length);
+		if (!ret && GetLastError() != ERROR_IO_PENDING) {
+			usbi_err(TRANSFER_CTX(transfer), "IsoReadPipe/IsoWritePipe failed: %s", windows_error_str(0));
+			return LIBUSB_ERROR_IO;
 		}
 
 		transfer_priv->interface_number = (uint8_t)current_interface;
 
 		return LIBUSB_SUCCESS;
-	}
-	else if (sub_api == SUB_API_WINUSB) {
+	} else if (sub_api == SUB_API_WINUSB) {
 		WINUSB_PIPE_INFORMATION_EX pipe_info_ex = { 0 };
 		WINUSB_ISOCH_BUFFER_HANDLE buffer_handle;
 		ULONG iso_transfer_size_multiple;
 		int out_transfer_length = 0;
 		int idx;
 
-#		define WINUSBX_CHECK_API_SUPPORTED(API)       \
-		if (WinUSBX[sub_api].API == NULL)             \
-		{                                             \
-			usbi_dbg(#API " isn't available");        \
-			return LIBUSB_ERROR_NOT_SUPPORTED;        \
+		// Depending on the version of Microsoft WinUSB, isochronous transfers may not be supported.
+		if (WinUSBX[sub_api].ReadIsochPipeAsap == NULL) {
+			usbi_warn(TRANSFER_CTX(transfer), "WinUSB DLL does not support isoch transfers");
+			return LIBUSB_ERROR_NOT_SUPPORTED;
 		}
 
-		// Depending on the version of Microsoft WinUSB, isochronous transfers may not be supported.
-		WINUSBX_CHECK_API_SUPPORTED(RegisterIsochBuffer);
-		WINUSBX_CHECK_API_SUPPORTED(ReadIsochPipeAsap);
-		WINUSBX_CHECK_API_SUPPORTED(WriteIsochPipeAsap);
-		WINUSBX_CHECK_API_SUPPORTED(UnregisterIsochBuffer);
-		WINUSBX_CHECK_API_SUPPORTED(QueryPipeEx);
-
 		if (sizeof(struct libusb_iso_packet_descriptor) != sizeof(USBD_ISO_PACKET_DESCRIPTOR)) {
-			usbi_dbg("The size of Microsoft WinUsb and libusb isochronous packet descriptor doesn't match.");
+			usbi_err(TRANSFER_CTX(transfer), "size of WinUsb and libusb isoch packet descriptors don't match");
 			return LIBUSB_ERROR_NOT_SUPPORTED;
 		}
 
@@ -2703,18 +2616,17 @@
 		for (idx = 0; idx < priv->usb_interface[current_interface].nb_endpoints; ++idx) {
 			ret = WinUSBX[sub_api].QueryPipeEx(winusb_handle, (UINT8)priv->usb_interface[current_interface].current_altsetting, (UCHAR)idx, &pipe_info_ex);
 			if (!ret) {
-				usbi_dbg("Couldn't query interface settings for USB pipe with index %d. Error: %s", idx, windows_error_str(0));
+				usbi_err(TRANSFER_CTX(transfer), "couldn't query interface settings for USB pipe with index %d. Error: %s", idx, windows_error_str(0));
 				return LIBUSB_ERROR_NOT_FOUND;
 			}
 
-			if (pipe_info_ex.PipeId == transfer->endpoint && pipe_info_ex.PipeType == UsbdPipeTypeIsochronous) {
+			if (pipe_info_ex.PipeId == transfer->endpoint && pipe_info_ex.PipeType == UsbdPipeTypeIsochronous)
 				break;
-			}
 		}
 
 		// Make sure we found the index.
-		if (idx >= priv->usb_interface[current_interface].nb_endpoints) {
-			usbi_dbg("Couldn't find the isochronous endpoint %02x.", transfer->endpoint);
+		if (idx == priv->usb_interface[current_interface].nb_endpoints) {
+			usbi_err(TRANSFER_CTX(transfer), "couldn't find isoch endpoint 0x%02x", transfer->endpoint);
 			return LIBUSB_ERROR_NOT_FOUND;
 		}
 
@@ -2722,27 +2634,25 @@
 			int interval = pipe_info_ex.Interval;
 
 			// For high-speed and SuperSpeed device, the interval is 2**(bInterval-1).
-			if (libusb_get_device_speed(libusb_get_device(transfer->dev_handle)) >= LIBUSB_SPEED_HIGH) {
+			if (transfer->dev_handle->dev->speed >= LIBUSB_SPEED_HIGH)
 				interval = (1 << (pipe_info_ex.Interval - 1));
-			}
 
-			// WinUSB only supports isochronous transfers spanning a full USB frames. Later, we might be smarter about this
+			// WinUSB only supports isoch transfers spanning a full USB frames. Later, we might be smarter about this
 			// and allocate a temporary buffer. However, this is harder than it seems as its destruction would depend on overlapped
 			// IO...
 			iso_transfer_size_multiple = (pipe_info_ex.MaximumBytesPerInterval * 8) / interval;
 			if (transfer->length % iso_transfer_size_multiple != 0) {
-				usbi_dbg("The length of isochronous buffer must be a multiple of the MaximumBytesPerInterval * 8 / Interval");
+				usbi_err(TRANSFER_CTX(transfer), "length of isoch buffer must be a multiple of the MaximumBytesPerInterval * 8 / Interval");
 				return LIBUSB_ERROR_INVALID_PARAM;
 			}
-		}
-		else {
-			// If this is an OUT transfer, we make sure the isochronous packets are contiguous as this isn't supported otherwise.
-			BOOL size_should_be_zero = FALSE;
-			out_transfer_length = 0;
+		} else {
+			// If this is an OUT transfer, we make sure the isoch packets are contiguous as this isn't supported otherwise.
+			bool size_should_be_zero = false;
+
 			for (idx = 0; idx < transfer->num_iso_packets; ++idx) {
 				if ((size_should_be_zero && transfer->iso_packet_desc[idx].length != 0) ||
 					(transfer->iso_packet_desc[idx].length != pipe_info_ex.MaximumBytesPerInterval && idx + 1 < transfer->num_iso_packets && transfer->iso_packet_desc[idx + 1].length > 0)) {
-					usbi_dbg("Isochronous packets for OUT transfer with Microsoft WinUSB must be contiguous in memory.");
+					usbi_err(TRANSFER_CTX(transfer), "isoch packets for OUT transfer with WinUSB must be contiguous in memory");
 					return LIBUSB_ERROR_INVALID_PARAM;
 				}
 
@@ -2755,15 +2665,15 @@
 			if (WinUSBX[sub_api].UnregisterIsochBuffer(transfer_priv->isoch_buffer_handle)) {
 				transfer_priv->isoch_buffer_handle = NULL;
 			} else {
-				usbi_dbg("Couldn't unregister the Microsoft WinUSB isochronous buffer: %s", windows_error_str(0));
+				usbi_err(TRANSFER_CTX(transfer), "failed to unregister WinUSB isoch buffer: %s", windows_error_str(0));
 				return LIBUSB_ERROR_OTHER;
 			}
 		}
 
-		// Register the isochronous buffer to the operating system.
+		// Register the isoch buffer to the operating system.
 		ret = WinUSBX[sub_api].RegisterIsochBuffer(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, &buffer_handle);
 		if (!ret) {
-			usbi_dbg("Microsoft WinUSB refused to allocate an isochronous buffer.");
+			usbi_err(TRANSFER_CTX(transfer), "failed to register WinUSB isoch buffer: %s", windows_error_str(0));
 			return LIBUSB_ERROR_NO_MEM;
 		}
 
@@ -2780,36 +2690,22 @@
 		}
 
 		// Initiate the transfers.
-		if (IS_XFERIN(transfer)) {
+		if (IS_XFERIN(transfer))
 			ret = WinUSBX[sub_api].ReadIsochPipeAsap(buffer_handle, 0, transfer->length, !transfer_priv->iso_break_stream, transfer->num_iso_packets, (PUSBD_ISO_PACKET_DESCRIPTOR)transfer->iso_packet_desc, overlapped);
-		}
-		else {
+		else
 			ret = WinUSBX[sub_api].WriteIsochPipeAsap(buffer_handle, 0, out_transfer_length, !transfer_priv->iso_break_stream, overlapped);
+
+		if (!ret && GetLastError() != ERROR_IO_PENDING) {
+			usbi_err(TRANSFER_CTX(transfer), "ReadIsochPipeAsap/WriteIsochPipeAsap failed: %s", windows_error_str(0));
+			if (!WinUSBX[sub_api].UnregisterIsochBuffer(buffer_handle))
+				usbi_warn(TRANSFER_CTX(transfer), "failed to unregister WinUSB isoch buffer: %s", windows_error_str(0));
+			return LIBUSB_ERROR_IO;
 		}
 
 		// Restore the ContinueStream parameter to TRUE.
 		transfer_priv->iso_break_stream = FALSE;
 
-		if (!ret) {
-			if (GetLastError() == ERROR_IO_PENDING) {
-				transfer_priv->isoch_buffer_handle = buffer_handle;
-			} else {
-				usbi_err(ctx, "ReadIsochPipeAsap/WriteIsochPipeAsap failed: %s", windows_error_str(0));
-				if (WinUSBX[sub_api].UnregisterIsochBuffer(buffer_handle)) {
-					transfer_priv->isoch_buffer_handle = NULL;
-					return LIBUSB_ERROR_IO;
-				} else {
-					usbi_dbg("Couldn't unregister the Microsoft WinUSB isochronous buffer: %s", windows_error_str(0));
-					return LIBUSB_ERROR_OTHER;
-				}
-			}
-		} else {
-			windows_force_sync_completion(overlapped, (ULONG)transfer->length);
-			if (!WinUSBX[sub_api].UnregisterIsochBuffer(buffer_handle)) {
-				usbi_dbg("Couldn't unregister the Microsoft WinUSB isochronous buffer: %s", windows_error_str(0));
-				return LIBUSB_ERROR_OTHER;
-			}
-		}
+		transfer_priv->isoch_buffer_handle = buffer_handle;
 
 		transfer_priv->interface_number = (uint8_t)current_interface;
 
@@ -2823,27 +2719,27 @@
 static int winusbx_submit_bulk_transfer(int sub_api, 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 winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+	struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
 	struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
 	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
 	HANDLE winusb_handle;
 	OVERLAPPED *overlapped;
-	bool ret;
+	BOOL ret;
 	int current_interface;
 
 	CHECK_WINUSBX_AVAILABLE(sub_api);
 
 	current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
 	if (current_interface < 0) {
-		usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
+		usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer");
 		return LIBUSB_ERROR_NOT_FOUND;
 	}
 
 	usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
 
-	transfer_priv->handle = winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
-	overlapped = transfer_priv->pollable_fd.overlapped;
+	winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
+	set_transfer_priv_handle(itransfer, handle_priv->interface_handle[current_interface].dev_handle);
+	overlapped = get_transfer_priv_overlapped(itransfer);
 
 	if (IS_XFERIN(transfer)) {
 		usbi_dbg("reading %d bytes", transfer->length);
@@ -2853,13 +2749,9 @@
 		ret = WinUSBX[sub_api].WritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, overlapped);
 	}
 
-	if (!ret) {
-		if (GetLastError() != ERROR_IO_PENDING) {
-			usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
-			return LIBUSB_ERROR_IO;
-		}
-	} else {
-		windows_force_sync_completion(overlapped, (ULONG)transfer->length);
+	if (!ret && GetLastError() != ERROR_IO_PENDING) {
+		usbi_err(TRANSFER_CTX(transfer), "ReadPipe/WritePipe failed: %s", windows_error_str(0));
+		return LIBUSB_ERROR_IO;
 	}
 
 	transfer_priv->interface_number = (uint8_t)current_interface;
@@ -2869,7 +2761,6 @@
 
 static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint)
 {
-	struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
 	struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
 	struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
 	HANDLE winusb_handle;
@@ -2879,7 +2770,7 @@
 
 	current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
 	if (current_interface < 0) {
-		usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear");
+		usbi_err(HANDLE_CTX(dev_handle), "unable to match endpoint to an open interface - cannot clear");
 		return LIBUSB_ERROR_NOT_FOUND;
 	}
 
@@ -2887,62 +2778,29 @@
 	winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
 
 	if (!WinUSBX[sub_api].ResetPipe(winusb_handle, endpoint)) {
-		usbi_err(ctx, "ResetPipe failed: %s", windows_error_str(0));
+		usbi_err(HANDLE_CTX(dev_handle), "ResetPipe failed: %s", windows_error_str(0));
 		return LIBUSB_ERROR_NO_DEVICE;
 	}
 
 	return LIBUSB_SUCCESS;
 }
 
-/*
- * from http://www.winvistatips.com/winusb-bugchecks-t335323.html (confirmed
- * through testing as well):
- * "You can not call WinUsb_AbortPipe on control pipe. You can possibly cancel
- * the control transfer using CancelIo"
- */
-static int winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer)
-{
-	UNUSED(sub_api);
-	UNUSED(itransfer);
-	// Cancelling of the I/O is done in the parent
-	return LIBUSB_SUCCESS;
-}
-
-static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer)
+static int winusbx_cancel_transfer(int sub_api, 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 winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
-	struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+	struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
 	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+	int current_interface = transfer_priv->interface_number;
 	HANDLE handle;
-	int current_interface;
 
 	CHECK_WINUSBX_AVAILABLE(sub_api);
 
-	current_interface = transfer_priv->interface_number;
-	if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) {
-		usbi_err(ctx, "program assertion failed: invalid interface_number");
-		return LIBUSB_ERROR_NOT_FOUND;
-	}
 	usbi_dbg("will use interface %d", current_interface);
 
-	if (WinUSBX[sub_api].CancelIoEx_supported) {
-		// Try to use CancelIoEx if available to cancel just a single transfer
-		handle = handle_priv->interface_handle[current_interface].dev_handle;
-		if (CancelIoEx(handle, transfer_priv->pollable_fd.overlapped))
-			return LIBUSB_SUCCESS;
-		else if (GetLastError() == ERROR_NOT_FOUND)
-			return LIBUSB_ERROR_NOT_FOUND;
-
-		// Not every driver implements the necessary functionality for CancelIoEx
-		usbi_warn(ctx, "CancelIoEx not supported for sub API %s", winusbx_driver_names[sub_api]);
-		WinUSBX[sub_api].CancelIoEx_supported = false;
-	}
-
 	handle = handle_priv->interface_handle[current_interface].api_handle;
 	if (!WinUSBX[sub_api].AbortPipe(handle, transfer->endpoint)) {
-		usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0));
+		usbi_err(TRANSFER_CTX(transfer), "AbortPipe failed: %s", windows_error_str(0));
 		return LIBUSB_ERROR_NO_DEVICE;
 	}
 
@@ -2960,7 +2818,6 @@
 // TODO: (post hotplug): see if we can force eject the device and redetect it (reuse hotplug?)
 static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
 {
-	struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
 	struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
 	struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
 	HANDLE winusb_handle;
@@ -2975,24 +2832,24 @@
 			for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) {
 				usbi_dbg("resetting ep %02X", priv->usb_interface[i].endpoint[j]);
 				if (!WinUSBX[sub_api].AbortPipe(winusb_handle, priv->usb_interface[i].endpoint[j]))
-					usbi_err(ctx, "AbortPipe (pipe address %02X) failed: %s",
+					usbi_err(HANDLE_CTX(dev_handle), "AbortPipe (pipe address %02X) failed: %s",
 						priv->usb_interface[i].endpoint[j], windows_error_str(0));
 
 				// FlushPipe seems to fail on OUT pipes
 				if (IS_EPIN(priv->usb_interface[i].endpoint[j])
 						&& (!WinUSBX[sub_api].FlushPipe(winusb_handle, priv->usb_interface[i].endpoint[j])))
-					usbi_err(ctx, "FlushPipe (pipe address %02X) failed: %s",
+					usbi_err(HANDLE_CTX(dev_handle), "FlushPipe (pipe address %02X) failed: %s",
 						priv->usb_interface[i].endpoint[j], windows_error_str(0));
 
 				if (!WinUSBX[sub_api].ResetPipe(winusb_handle, priv->usb_interface[i].endpoint[j]))
-					usbi_err(ctx, "ResetPipe (pipe address %02X) failed: %s",
+					usbi_err(HANDLE_CTX(dev_handle), "ResetPipe (pipe address %02X) failed: %s",
 						priv->usb_interface[i].endpoint[j], windows_error_str(0));
 			}
 		}
 	}
 
 	// libusbK & libusb0 have the ability to issue an actual device reset
-	if (WinUSBX[sub_api].ResetDevice != NULL) {
+	if ((sub_api != SUB_API_WINUSB) && (WinUSBX[sub_api].ResetDevice != NULL)) {
 		winusb_handle = handle_priv->interface_handle[0].api_handle;
 		if (HANDLE_VALID(winusb_handle))
 			WinUSBX[sub_api].ResetDevice(winusb_handle);
@@ -3001,21 +2858,17 @@
 	return LIBUSB_SUCCESS;
 }
 
-static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size)
+static enum libusb_transfer_status winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length)
 {
 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-	struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
-	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
-	PKISO_CONTEXT iso_context;
+	struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
 	int i;
 
 	if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
-		CHECK_WINUSBX_AVAILABLE(sub_api);
-
 		// for isochronous, need to copy the individual iso packet actual_lengths and statuses
 		if ((sub_api == SUB_API_LIBUSBK) || (sub_api == SUB_API_LIBUSB0)) {
 			// iso only supported on libusbk-based backends for now
-			iso_context = transfer_priv->iso_context;
+			PKISO_CONTEXT iso_context = transfer_priv->iso_context;
 			for (i = 0; i < transfer->num_iso_packets; i++) {
 				transfer->iso_packet_desc[i].actual_length = iso_context->IsoPackets[i].actual_length;
 				// TODO translate USDB_STATUS codes http://msdn.microsoft.com/en-us/library/ff539136(VS.85).aspx to libusb_transfer_status
@@ -3026,31 +2879,28 @@
 				/* Convert isochronous packet descriptor between Windows and libusb representation.
 				 * Both representation are guaranteed to have the same length in bytes.*/
 				PUSBD_ISO_PACKET_DESCRIPTOR usbd_iso_packet_desc = (PUSBD_ISO_PACKET_DESCRIPTOR)transfer->iso_packet_desc;
-				for (i = 0; i < transfer->num_iso_packets; ++i)
-				{
-					int length = (i < transfer->num_iso_packets - 1) ? (usbd_iso_packet_desc[i + 1].Offset - usbd_iso_packet_desc[i].Offset) : usbd_iso_packet_desc[i].Length;
-					int actual_length = usbd_iso_packet_desc[i].Length;
+				for (i = 0; i < transfer->num_iso_packets; i++) {
+					unsigned int packet_length = (i < transfer->num_iso_packets - 1) ? (usbd_iso_packet_desc[i + 1].Offset - usbd_iso_packet_desc[i].Offset) : usbd_iso_packet_desc[i].Length;
+					unsigned int actual_length = usbd_iso_packet_desc[i].Length;
 					USBD_STATUS status = usbd_iso_packet_desc[i].Status;
 
-					transfer->iso_packet_desc[i].length = length;
+					transfer->iso_packet_desc[i].length = packet_length;
 					transfer->iso_packet_desc[i].actual_length = actual_length;
 					transfer->iso_packet_desc[i].status = usbd_status_to_libusb_transfer_status(status);
 				}
-			}
-			else {
-				for (i = 0; i < transfer->num_iso_packets; ++i)
-				{
+			} else {
+				for (i = 0; i < transfer->num_iso_packets; i++) {
 					transfer->iso_packet_desc[i].status = LIBUSB_TRANSFER_COMPLETED;
 				}
 			}
 		} else {
 			// This should only occur if backend is not set correctly or other backend isoc is partially implemented
 			PRINT_UNSUPPORTED_API(copy_transfer_data);
-			return LIBUSB_ERROR_NOT_SUPPORTED;
+			return LIBUSB_TRANSFER_ERROR;
 		}
 	}
 
-	itransfer->transferred += io_size;
+	itransfer->transferred += (int)length;
 	return LIBUSB_TRANSFER_COMPLETED;
 }
 
@@ -3072,7 +2922,7 @@
 	return i;
 }
 
-static int _hid_get_device_descriptor(struct hid_device_priv *dev, void *data, size_t *size)
+static int _hid_get_device_descriptor(struct hid_device_priv *hid_priv, void *data, size_t *size)
 {
 	struct libusb_device_descriptor d;
 
@@ -3083,12 +2933,12 @@
 	d.bDeviceSubClass = 0;
 	d.bDeviceProtocol = 0;
 	d.bMaxPacketSize0 = 64; /* fix this! */
-	d.idVendor = (uint16_t)dev->vid;
-	d.idProduct = (uint16_t)dev->pid;
+	d.idVendor = (uint16_t)hid_priv->vid;
+	d.idProduct = (uint16_t)hid_priv->pid;
 	d.bcdDevice = 0x0100;
-	d.iManufacturer = dev->string_index[0];
-	d.iProduct = dev->string_index[1];
-	d.iSerialNumber = dev->string_index[2];
+	d.iManufacturer = hid_priv->string_index[0];
+	d.iProduct = hid_priv->string_index[1];
+	d.iSerialNumber = hid_priv->string_index[2];
 	d.bNumConfigurations = 1;
 
 	if (*size > LIBUSB_DT_DEVICE_SIZE)
@@ -3098,7 +2948,7 @@
 	return LIBUSB_COMPLETED;
 }
 
-static int _hid_get_config_descriptor(struct hid_device_priv *dev, void *data, size_t *size)
+static int _hid_get_config_descriptor(struct hid_device_priv *hid_priv, void *data, size_t *size)
 {
 	char num_endpoints = 0;
 	size_t config_total_len = 0;
@@ -3109,9 +2959,9 @@
 	struct libusb_endpoint_descriptor *ed;
 	size_t tmp_size;
 
-	if (dev->input_report_size)
+	if (hid_priv->input_report_size)
 		num_endpoints++;
-	if (dev->output_report_size)
+	if (hid_priv->output_report_size)
 		num_endpoints++;
 
 	config_total_len = LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE
@@ -3145,24 +2995,24 @@
 	id->iInterface = 0;
 
 	tmp_size = LIBUSB_DT_HID_SIZE;
-	_hid_get_hid_descriptor(dev, hd, &tmp_size);
+	_hid_get_hid_descriptor(hid_priv, hd, &tmp_size);
 
-	if (dev->input_report_size) {
+	if (hid_priv->input_report_size) {
 		ed->bLength = LIBUSB_DT_ENDPOINT_SIZE;
 		ed->bDescriptorType = LIBUSB_DT_ENDPOINT;
 		ed->bEndpointAddress = HID_IN_EP;
 		ed->bmAttributes = 3;
-		ed->wMaxPacketSize = dev->input_report_size - 1;
+		ed->wMaxPacketSize = hid_priv->input_report_size - 1;
 		ed->bInterval = 10;
 		ed = (struct libusb_endpoint_descriptor *)((char *)ed + LIBUSB_DT_ENDPOINT_SIZE);
 	}
 
-	if (dev->output_report_size) {
+	if (hid_priv->output_report_size) {
 		ed->bLength = LIBUSB_DT_ENDPOINT_SIZE;
 		ed->bDescriptorType = LIBUSB_DT_ENDPOINT;
 		ed->bEndpointAddress = HID_OUT_EP;
 		ed->bmAttributes = 3;
-		ed->wMaxPacketSize = dev->output_report_size - 1;
+		ed->wMaxPacketSize = hid_priv->output_report_size - 1;
 		ed->bInterval = 10;
 	}
 
@@ -3173,7 +3023,7 @@
 	return LIBUSB_COMPLETED;
 }
 
-static int _hid_get_string_descriptor(struct hid_device_priv *dev, int _index,
+static int _hid_get_string_descriptor(struct hid_device_priv *hid_priv, int _index,
 	void *data, size_t *size, HANDLE hid_handle)
 {
 	void *tmp = NULL;
@@ -3184,17 +3034,14 @@
 	/* language ID, EN-US */
 	char string_langid[] = {0x09, 0x04};
 
-	if ((*size < 2) || (*size > 255))
-		return LIBUSB_ERROR_OVERFLOW;
-
 	if (_index == 0) {
 		tmp = string_langid;
 		tmp_size = sizeof(string_langid) + 2;
 	} else {
 		for (i = 0; i < 3; i++) {
-			if (_index == (dev->string_index[i])) {
-				tmp = dev->string[i];
-				tmp_size = (_hid_wcslen(dev->string[i]) + 1) * sizeof(WCHAR);
+			if (_index == (hid_priv->string_index[i])) {
+				tmp = hid_priv->string[i];
+				tmp_size = (_hid_wcslen(hid_priv->string[i]) + 1) * sizeof(WCHAR);
 				break;
 			}
 		}
@@ -3221,13 +3068,13 @@
 	return LIBUSB_COMPLETED;
 }
 
-static int _hid_get_hid_descriptor(struct hid_device_priv *dev, void *data, size_t *size)
+static int _hid_get_hid_descriptor(struct hid_device_priv *hid_priv, void *data, size_t *size)
 {
 	struct libusb_hid_descriptor d;
 	uint8_t tmp[MAX_HID_DESCRIPTOR_SIZE];
 	size_t report_len = MAX_HID_DESCRIPTOR_SIZE;
 
-	_hid_get_report_descriptor(dev, tmp, &report_len);
+	_hid_get_report_descriptor(hid_priv, tmp, &report_len);
 
 	d.bLength = LIBUSB_DT_HID_SIZE;
 	d.bDescriptorType = LIBUSB_DT_HID;
@@ -3244,19 +3091,19 @@
 	return LIBUSB_COMPLETED;
 }
 
-static int _hid_get_report_descriptor(struct hid_device_priv *dev, void *data, size_t *size)
+static int _hid_get_report_descriptor(struct hid_device_priv *hid_priv, void *data, size_t *size)
 {
 	uint8_t d[MAX_HID_DESCRIPTOR_SIZE];
 	size_t i = 0;
 
 	/* usage page */
-	d[i++] = 0x06; d[i++] = dev->usagePage & 0xFF; d[i++] = dev->usagePage >> 8;
+	d[i++] = 0x06; d[i++] = hid_priv->usagePage & 0xFF; d[i++] = hid_priv->usagePage >> 8;
 	/* usage */
-	d[i++] = 0x09; d[i++] = (uint8_t)dev->usage;
+	d[i++] = 0x09; d[i++] = (uint8_t)hid_priv->usage;
 	/* start collection (application) */
 	d[i++] = 0xA1; d[i++] = 0x01;
 	/* input report */
-	if (dev->input_report_size) {
+	if (hid_priv->input_report_size) {
 		/* usage (vendor defined) */
 		d[i++] = 0x09; d[i++] = 0x01;
 		/* logical minimum (0) */
@@ -3266,12 +3113,12 @@
 		/* report size (8 bits) */
 		d[i++] = 0x75; d[i++] = 0x08;
 		/* report count */
-		d[i++] = 0x95; d[i++] = (uint8_t)dev->input_report_size - 1;
+		d[i++] = 0x95; d[i++] = (uint8_t)hid_priv->input_report_size - 1;
 		/* input (data, variable, absolute) */
 		d[i++] = 0x81; d[i++] = 0x00;
 	}
 	/* output report */
-	if (dev->output_report_size) {
+	if (hid_priv->output_report_size) {
 		/* usage (vendor defined) */
 		d[i++] = 0x09; d[i++] = 0x02;
 		/* logical minimum (0) */
@@ -3281,12 +3128,12 @@
 		/* report size (8 bits) */
 		d[i++] = 0x75; d[i++] = 0x08;
 		/* report count */
-		d[i++] = 0x95; d[i++] = (uint8_t)dev->output_report_size - 1;
+		d[i++] = 0x95; d[i++] = (uint8_t)hid_priv->output_report_size - 1;
 		/* output (data, variable, absolute) */
 		d[i++] = 0x91; d[i++] = 0x00;
 	}
 	/* feature report */
-	if (dev->feature_report_size) {
+	if (hid_priv->feature_report_size) {
 		/* usage (vendor defined) */
 		d[i++] = 0x09; d[i++] = 0x03;
 		/* logical minimum (0) */
@@ -3296,7 +3143,7 @@
 		/* report size (8 bits) */
 		d[i++] = 0x75; d[i++] = 0x08;
 		/* report count */
-		d[i++] = 0x95; d[i++] = (uint8_t)dev->feature_report_size - 1;
+		d[i++] = 0x95; d[i++] = (uint8_t)hid_priv->feature_report_size - 1;
 		/* feature (data, variable, absolute) */
 		d[i++] = 0xb2; d[i++] = 0x02; d[i++] = 0x01;
 	}
@@ -3311,32 +3158,33 @@
 	return LIBUSB_COMPLETED;
 }
 
-static int _hid_get_descriptor(struct hid_device_priv *dev, HANDLE hid_handle, int recipient,
+static int _hid_get_descriptor(struct libusb_device *dev, HANDLE hid_handle, int recipient,
 	int type, int _index, void *data, size_t *size)
 {
+	struct winusb_device_priv *priv = _device_priv(dev);
 	UNUSED(recipient);
 
 	switch (type) {
 	case LIBUSB_DT_DEVICE:
 		usbi_dbg("LIBUSB_DT_DEVICE");
-		return _hid_get_device_descriptor(dev, data, size);
+		return _hid_get_device_descriptor(priv->hid, data, size);
 	case LIBUSB_DT_CONFIG:
 		usbi_dbg("LIBUSB_DT_CONFIG");
 		if (!_index)
-			return _hid_get_config_descriptor(dev, data, size);
+			return _hid_get_config_descriptor(priv->hid, data, size);
 		return LIBUSB_ERROR_INVALID_PARAM;
 	case LIBUSB_DT_STRING:
 		usbi_dbg("LIBUSB_DT_STRING");
-		return _hid_get_string_descriptor(dev, _index, data, size, hid_handle);
+		return _hid_get_string_descriptor(priv->hid, _index, data, size, hid_handle);
 	case LIBUSB_DT_HID:
 		usbi_dbg("LIBUSB_DT_HID");
 		if (!_index)
-			return _hid_get_hid_descriptor(dev, data, size);
+			return _hid_get_hid_descriptor(priv->hid, data, size);
 		return LIBUSB_ERROR_INVALID_PARAM;
 	case LIBUSB_DT_REPORT:
 		usbi_dbg("LIBUSB_DT_REPORT");
 		if (!_index)
-			return _hid_get_report_descriptor(dev, data, size);
+			return _hid_get_report_descriptor(priv->hid, data, size);
 		return LIBUSB_ERROR_INVALID_PARAM;
 	case LIBUSB_DT_PHYSICAL:
 		usbi_dbg("LIBUSB_DT_PHYSICAL");
@@ -3345,24 +3193,21 @@
 		return LIBUSB_ERROR_OTHER;
 	}
 
-	usbi_dbg("unsupported");
+	usbi_warn(DEVICE_CTX(dev), "unsupported");
 	return LIBUSB_ERROR_NOT_SUPPORTED;
 }
 
-static int _hid_get_report(struct hid_device_priv *dev, HANDLE hid_handle, int id, void *data,
-	struct winusb_transfer_priv *tp, size_t *size, OVERLAPPED *overlapped, int report_type)
+static int _hid_get_report(struct libusb_device *dev, HANDLE hid_handle, int id, void *data,
+	struct winusb_transfer_priv *tp, size_t size, OVERLAPPED *overlapped, int report_type)
 {
+	DWORD ioctl_code, expected_size = (DWORD)size;
 	uint8_t *buf;
-	DWORD ioctl_code, read_size, expected_size = (DWORD)*size;
-	int r = LIBUSB_SUCCESS;
-
-	UNUSED(dev);
 
 	if (tp->hid_buffer != NULL)
-		usbi_dbg("program assertion failed: hid_buffer is not NULL");
+		usbi_err(DEVICE_CTX(dev), "program assertion failed - hid_buffer is not NULL");
 
-	if ((*size == 0) || (*size > MAX_HID_REPORT_SIZE)) {
-		usbi_dbg("invalid size (%"PRIuPTR")", (uintptr_t)*size);
+	if ((size == 0) || (size > MAX_HID_REPORT_SIZE)) {
+		usbi_warn(DEVICE_CTX(dev), "invalid size (%"PRIuPTR")", (uintptr_t)size);
 		return LIBUSB_ERROR_INVALID_PARAM;
 	}
 
@@ -3374,7 +3219,7 @@
 		ioctl_code = IOCTL_HID_GET_FEATURE;
 		break;
 	default:
-		usbi_dbg("unknown HID report type %d", report_type);
+		usbi_warn(DEVICE_CTX(dev), "unknown HID report type %d", report_type);
 		return LIBUSB_ERROR_INVALID_PARAM;
 	}
 
@@ -3386,64 +3231,37 @@
 	buf[0] = (uint8_t)id; // Must be set always
 	usbi_dbg("report ID: 0x%02X", buf[0]);
 
-	tp->hid_expected_size = expected_size;
-	read_size = expected_size;
-
 	// NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0)
 	if (!DeviceIoControl(hid_handle, ioctl_code, buf, expected_size + 1,
-		buf, expected_size + 1, &read_size, overlapped)) {
+		buf, expected_size + 1, NULL, overlapped)) {
 		if (GetLastError() != ERROR_IO_PENDING) {
-			usbi_dbg("Failed to Read HID Report: %s", windows_error_str(0));
+			usbi_err(DEVICE_CTX(dev), "failed to read HID Report: %s", windows_error_str(0));
 			free(buf);
 			return LIBUSB_ERROR_IO;
 		}
-		// Asynchronous wait
-		tp->hid_buffer = buf;
-		tp->hid_dest = data; // copy dest, as not necessarily the start of the transfer buffer
-		return LIBUSB_SUCCESS;
 	}
 
-	// Transfer completed synchronously => copy and discard extra buffer
-	if (read_size == 0) {
-		usbi_warn(NULL, "program assertion failed - read completed synchronously, but no data was read");
-		*size = 0;
-	} else {
-		if (buf[0] != id)
-			usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id);
+	// Asynchronous wait
+	tp->hid_buffer = buf;
+	tp->hid_dest = data; // copy dest, as not necessarily the start of the transfer buffer
+	tp->hid_expected_size = expected_size;
 
-		if ((size_t)read_size > expected_size) {
-			r = LIBUSB_ERROR_OVERFLOW;
-			usbi_dbg("OVERFLOW!");
-		} else {
-			r = LIBUSB_COMPLETED;
-		}
-
-		*size = MIN((size_t)read_size, *size);
-		if (id == 0)
-			memcpy(data, buf + 1, *size); // Discard report ID
-		else
-			memcpy(data, buf, *size);
-	}
-
-	free(buf);
-	return r;
+	return LIBUSB_SUCCESS;
 }
 
-static int _hid_set_report(struct hid_device_priv *dev, HANDLE hid_handle, int id, void *data,
-	struct winusb_transfer_priv *tp, size_t *size, OVERLAPPED *overlapped, int report_type)
+static int _hid_set_report(struct libusb_device *dev, HANDLE hid_handle, int id, void *data,
+	struct winusb_transfer_priv *tp, size_t size, OVERLAPPED *overlapped, int report_type)
 {
-	uint8_t *buf = NULL;
-	DWORD ioctl_code, write_size = (DWORD)*size;
+	DWORD ioctl_code, write_size = (DWORD)size;
 	// If an id is reported, we must allow MAX_HID_REPORT_SIZE + 1
 	size_t max_report_size = MAX_HID_REPORT_SIZE + (id ? 1 : 0);
-
-	UNUSED(dev);
+	uint8_t *buf;
 
 	if (tp->hid_buffer != NULL)
-		usbi_dbg("program assertion failed: hid_buffer is not NULL");
+		usbi_err(DEVICE_CTX(dev), "program assertion failed - hid_buffer is not NULL");
 
-	if ((*size == 0) || (*size > max_report_size)) {
-		usbi_dbg("invalid size (%"PRIuPTR")", (uintptr_t)*size);
+	if ((size == 0) || (size > max_report_size)) {
+		usbi_warn(DEVICE_CTX(dev), "invalid size (%"PRIuPTR")", (uintptr_t)size);
 		return LIBUSB_ERROR_INVALID_PARAM;
 	}
 
@@ -3455,7 +3273,7 @@
 		ioctl_code = IOCTL_HID_SET_FEATURE;
 		break;
 	default:
-		usbi_dbg("unknown HID report type %d", report_type);
+		usbi_warn(DEVICE_CTX(dev), "unknown HID report type %d", report_type);
 		return LIBUSB_ERROR_INVALID_PARAM;
 	}
 
@@ -3471,40 +3289,33 @@
 
 	if (id == 0) {
 		buf[0] = 0;
-		memcpy(buf + 1, data, *size);
+		memcpy(buf + 1, data, size);
 	} else {
 		// This seems like a waste, but if we don't duplicate the
 		// data, we'll get issues when freeing hid_buffer
-		memcpy(buf, data, *size);
+		memcpy(buf, data, size);
 		if (buf[0] != id)
-			usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id);
+			usbi_warn(DEVICE_CTX(dev), "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id);
 	}
 
 	// NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0)
 	if (!DeviceIoControl(hid_handle, ioctl_code, buf, write_size,
-		buf, write_size, &write_size, overlapped)) {
+		buf, write_size, NULL, overlapped)) {
 		if (GetLastError() != ERROR_IO_PENDING) {
-			usbi_dbg("Failed to Write HID Output Report: %s", windows_error_str(0));
+			usbi_err(DEVICE_CTX(dev), "failed to write HID Output Report: %s", windows_error_str(0));
 			free(buf);
 			return LIBUSB_ERROR_IO;
 		}
-		tp->hid_buffer = buf;
-		tp->hid_dest = NULL;
-		return LIBUSB_SUCCESS;
 	}
 
-	// Transfer completed synchronously
-	*size = write_size;
-	if (write_size == 0)
-		usbi_dbg("program assertion failed - write completed synchronously, but no data was written");
-
-	free(buf);
-	return LIBUSB_COMPLETED;
+	tp->hid_buffer = buf;
+	tp->hid_dest = NULL;
+	return LIBUSB_SUCCESS;
 }
 
-static int _hid_class_request(struct hid_device_priv *dev, HANDLE hid_handle, int request_type,
+static int _hid_class_request(struct libusb_device *dev, HANDLE hid_handle, int request_type,
 	int request, int value, int _index, void *data, struct winusb_transfer_priv *tp,
-	size_t *size, OVERLAPPED *overlapped)
+	size_t size, OVERLAPPED *overlapped)
 {
 	int report_type = (value >> 8) & 0xFF;
 	int report_id = value & 0xFF;
@@ -3524,32 +3335,30 @@
 	return LIBUSB_ERROR_INVALID_PARAM;
 }
 
-
 /*
  * HID API functions
  */
-static int hid_init(struct libusb_context *ctx)
+static bool hid_init(struct libusb_context *ctx)
 {
 	UNUSED(ctx);
 
 	DLL_GET_HANDLE(hid);
 
-	DLL_LOAD_FUNC(hid, HidD_GetAttributes, TRUE);
-	DLL_LOAD_FUNC(hid, HidD_GetHidGuid, TRUE);
-	DLL_LOAD_FUNC(hid, HidD_GetPreparsedData, TRUE);
-	DLL_LOAD_FUNC(hid, HidD_FreePreparsedData, TRUE);
-	DLL_LOAD_FUNC(hid, HidD_GetManufacturerString, TRUE);
-	DLL_LOAD_FUNC(hid, HidD_GetProductString, TRUE);
-	DLL_LOAD_FUNC(hid, HidD_GetSerialNumberString, TRUE);
-	DLL_LOAD_FUNC(hid, HidD_GetIndexedString, TRUE);
-	DLL_LOAD_FUNC(hid, HidP_GetCaps, TRUE);
-	DLL_LOAD_FUNC(hid, HidD_SetNumInputBuffers, TRUE);
-	DLL_LOAD_FUNC(hid, HidD_GetPhysicalDescriptor, TRUE);
-	DLL_LOAD_FUNC(hid, HidD_FlushQueue, TRUE);
-	DLL_LOAD_FUNC(hid, HidP_GetValueCaps, TRUE);
+	DLL_LOAD_FUNC(hid, HidD_GetAttributes, true);
+	DLL_LOAD_FUNC(hid, HidD_GetHidGuid, true);
+	DLL_LOAD_FUNC(hid, HidD_GetPreparsedData, true);
+	DLL_LOAD_FUNC(hid, HidD_FreePreparsedData, true);
+	DLL_LOAD_FUNC(hid, HidD_GetManufacturerString, true);
+	DLL_LOAD_FUNC(hid, HidD_GetProductString, true);
+	DLL_LOAD_FUNC(hid, HidD_GetSerialNumberString, true);
+	DLL_LOAD_FUNC(hid, HidD_GetIndexedString, true);
+	DLL_LOAD_FUNC(hid, HidP_GetCaps, true);
+	DLL_LOAD_FUNC(hid, HidD_SetNumInputBuffers, true);
+	DLL_LOAD_FUNC(hid, HidD_GetPhysicalDescriptor, true);
+	DLL_LOAD_FUNC(hid, HidD_FlushQueue, true);
+	DLL_LOAD_FUNC(hid, HidP_GetValueCaps, true);
 
-	api_hid_available = true;
-	return LIBUSB_SUCCESS;
+	return true;
 }
 
 static void hid_exit(void)
@@ -3562,7 +3371,6 @@
 // composite_open(), with interfaces belonging to different APIs
 static int hid_open(int sub_api, struct libusb_device_handle *dev_handle)
 {
-	struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
 	struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
 	struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
 	HIDD_ATTRIBUTES hid_attributes;
@@ -3582,7 +3390,7 @@
 	CHECK_HID_AVAILABLE;
 
 	if (priv->hid == NULL) {
-		usbi_err(ctx, "program assertion failed - private HID structure is unitialized");
+		usbi_err(HANDLE_CTX(dev_handle), "program assertion failed - private HID structure is unitialized");
 		return LIBUSB_ERROR_NOT_FOUND;
 	}
 
@@ -3590,7 +3398,7 @@
 		if ((priv->usb_interface[i].path != NULL)
 				&& (priv->usb_interface[i].apib->id == USB_API_HID)) {
 			hid_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
-				NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
+				NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
 			/*
 			 * http://www.lvr.com/hidfaq.htm: Why do I receive "Access denied" when attempting to access my HID?
 			 * "Windows 2000 and later have exclusive read/write access to HIDs that are configured as a system
@@ -3599,11 +3407,11 @@
 			 * HidD_GetFeature (if the device supports Feature reports)."
 			 */
 			if (hid_handle == INVALID_HANDLE_VALUE) {
-				usbi_warn(ctx, "could not open HID device in R/W mode (keyboard or mouse?) - trying without");
+				usbi_warn(HANDLE_CTX(dev_handle), "could not open HID device in R/W mode (keyboard or mouse?) - trying without");
 				hid_handle = CreateFileA(priv->usb_interface[i].path, 0, FILE_SHARE_WRITE | FILE_SHARE_READ,
-					NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
+					NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
 				if (hid_handle == INVALID_HANDLE_VALUE) {
-					usbi_err(ctx, "could not open device %s (interface %d): %s", priv->path, i, windows_error_str(0));
+					usbi_err(HANDLE_CTX(dev_handle), "could not open device %s (interface %d): %s", priv->path, i, windows_error_str(0));
 					switch (GetLastError()) {
 					case ERROR_FILE_NOT_FOUND: // The device was disconnected
 						return LIBUSB_ERROR_NO_DEVICE;
@@ -3622,7 +3430,7 @@
 	hid_attributes.Size = sizeof(hid_attributes);
 	do {
 		if (!HidD_GetAttributes(hid_handle, &hid_attributes)) {
-			usbi_err(ctx, "could not gain access to HID top collection (HidD_GetAttributes)");
+			usbi_err(HANDLE_CTX(dev_handle), "could not gain access to HID top collection (HidD_GetAttributes)");
 			break;
 		}
 
@@ -3635,11 +3443,11 @@
 
 		// Get the maximum input and output report size
 		if (!HidD_GetPreparsedData(hid_handle, &preparsed_data) || !preparsed_data) {
-			usbi_err(ctx, "could not read HID preparsed data (HidD_GetPreparsedData)");
+			usbi_err(HANDLE_CTX(dev_handle), "could not read HID preparsed data (HidD_GetPreparsedData)");
 			break;
 		}
 		if (HidP_GetCaps(preparsed_data, &capabilities) != HIDP_STATUS_SUCCESS) {
-			usbi_err(ctx, "could not parse HID capabilities (HidP_GetCaps)");
+			usbi_err(HANDLE_CTX(dev_handle), "could not parse HID capabilities (HidP_GetCaps)");
 			break;
 		}
 
@@ -3666,12 +3474,12 @@
 					}
 					if (nb_ids[1] != 0) {
 						if (nb_ids[0] != 0)
-							usbi_warn(ctx, "program assertion failed: zero and nonzero report IDs used for %s",
+							usbi_warn(HANDLE_CTX(dev_handle), "program assertion failed - zero and nonzero report IDs used for %s",
 								type[j]);
 						priv->hid->uses_report_ids[j] = true;
 					}
 				} else {
-					usbi_warn(ctx, "  could not process %s report IDs", type[j]);
+					usbi_warn(HANDLE_CTX(dev_handle), "  could not process %s report IDs", type[j]);
 				}
 				free(value_caps);
 			}
@@ -3720,7 +3528,8 @@
 	int i;
 
 	UNUSED(sub_api);
-	if (!api_hid_available)
+
+	if (DLL_HANDLE_NAME(hid) == NULL)
 		return;
 
 	for (i = 0; i < USB_MAXINTERFACES; i++) {
@@ -3777,8 +3586,6 @@
 
 static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting)
 {
-	struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
-
 	UNUSED(sub_api);
 	UNUSED(iface);
 
@@ -3788,7 +3595,7 @@
 		return LIBUSB_ERROR_INVALID_PARAM;
 
 	if (altsetting != 0) {
-		usbi_err(ctx, "set interface altsetting not supported for altsetting >0");
+		usbi_err(HANDLE_CTX(dev_handle), "set interface altsetting not supported for altsetting >0");
 		return LIBUSB_ERROR_NOT_SUPPORTED;
 	}
 
@@ -3798,10 +3605,10 @@
 static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer)
 {
 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-	struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
-	struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
+	struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
+	struct libusb_device_handle *dev_handle = transfer->dev_handle;
+	struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
 	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
-	struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
 	WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer;
 	HANDLE hid_handle;
 	OVERLAPPED *overlapped;
@@ -3819,7 +3626,7 @@
 	if (size > MAX_CTRL_BUFFER_LENGTH)
 		return LIBUSB_ERROR_INVALID_PARAM;
 
-	current_interface = get_valid_interface(transfer->dev_handle, USB_API_HID);
+	current_interface = get_valid_interface(dev_handle, USB_API_HID);
 	if (current_interface < 0) {
 		if (auto_claim(transfer, &current_interface, USB_API_HID) != LIBUSB_SUCCESS)
 			return LIBUSB_ERROR_NOT_FOUND;
@@ -3828,17 +3635,18 @@
 	usbi_dbg("will use interface %d", current_interface);
 
 	hid_handle = handle_priv->interface_handle[current_interface].api_handle;
-	overlapped = transfer_priv->pollable_fd.overlapped;
+	set_transfer_priv_handle(itransfer, hid_handle);
+	overlapped = get_transfer_priv_overlapped(itransfer);
 
 	switch (LIBUSB_REQ_TYPE(setup->RequestType)) {
 	case LIBUSB_REQUEST_TYPE_STANDARD:
 		switch (setup->Request) {
 		case LIBUSB_REQUEST_GET_DESCRIPTOR:
-			r = _hid_get_descriptor(priv->hid, hid_handle, LIBUSB_REQ_RECIPIENT(setup->RequestType),
+			r = _hid_get_descriptor(dev_handle->dev, hid_handle, LIBUSB_REQ_RECIPIENT(setup->RequestType),
 				(setup->Value >> 8) & 0xFF, setup->Value & 0xFF, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, &size);
 			break;
 		case LIBUSB_REQUEST_GET_CONFIGURATION:
-			r = winusb_get_configuration(transfer->dev_handle, &config);
+			r = winusb_get_configuration(dev_handle, &config);
 			if (r == LIBUSB_SUCCESS) {
 				size = 1;
 				((uint8_t *)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = (uint8_t)config;
@@ -3849,7 +3657,7 @@
 			if (setup->Value == priv->active_config) {
 				r = LIBUSB_COMPLETED;
 			} else {
-				usbi_warn(ctx, "cannot set configuration other than the default one");
+				usbi_warn(TRANSFER_CTX(transfer), "cannot set configuration other than the default one");
 				r = LIBUSB_ERROR_NOT_SUPPORTED;
 			}
 			break;
@@ -3859,22 +3667,22 @@
 			r = LIBUSB_COMPLETED;
 			break;
 		case LIBUSB_REQUEST_SET_INTERFACE:
-			r = hid_set_interface_altsetting(0, transfer->dev_handle, setup->Index, setup->Value);
+			r = hid_set_interface_altsetting(0, dev_handle, setup->Index, setup->Value);
 			if (r == LIBUSB_SUCCESS)
 				r = LIBUSB_COMPLETED;
 			break;
 		default:
-			usbi_warn(ctx, "unsupported HID control request");
+			usbi_warn(TRANSFER_CTX(transfer), "unsupported HID control request");
 			return LIBUSB_ERROR_NOT_SUPPORTED;
 		}
 		break;
 	case LIBUSB_REQUEST_TYPE_CLASS:
-		r = _hid_class_request(priv->hid, hid_handle, setup->RequestType, setup->Request, setup->Value,
+		r = _hid_class_request(dev_handle->dev, hid_handle, setup->RequestType, setup->Request, setup->Value,
 			setup->Index, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, transfer_priv,
-			&size, overlapped);
+			size, overlapped);
 		break;
 	default:
-		usbi_warn(ctx, "unsupported HID control request");
+		usbi_warn(TRANSFER_CTX(transfer), "unsupported HID control request");
 		return LIBUSB_ERROR_NOT_SUPPORTED;
 	}
 
@@ -3895,16 +3703,14 @@
 static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer)
 {
 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-	struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
-	struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+	struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
 	struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
 	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
 	HANDLE hid_handle;
 	OVERLAPPED *overlapped;
-	bool direction_in, ret;
+	bool direction_in;
+	BOOL ret;
 	int current_interface, length;
-	DWORD size;
-	int r = LIBUSB_SUCCESS;
 
 	UNUSED(sub_api);
 	CHECK_HID_AVAILABLE;
@@ -3914,14 +3720,15 @@
 
 	current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
 	if (current_interface < 0) {
-		usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
+		usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer");
 		return LIBUSB_ERROR_NOT_FOUND;
 	}
 
 	usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
 
-	transfer_priv->handle = hid_handle = handle_priv->interface_handle[current_interface].api_handle;
-	overlapped = transfer_priv->pollable_fd.overlapped;
+	hid_handle = handle_priv->interface_handle[current_interface].api_handle;
+	set_transfer_priv_handle(itransfer, hid_handle);
+	overlapped = get_transfer_priv_overlapped(itransfer);
 	direction_in = IS_XFERIN(transfer);
 
 	// If report IDs are not in use, an extra prefix byte must be added
@@ -3941,7 +3748,7 @@
 	if (direction_in) {
 		transfer_priv->hid_dest = transfer->buffer;
 		usbi_dbg("reading %d bytes (report ID: 0x00)", length);
-		ret = ReadFile(hid_handle, transfer_priv->hid_buffer, length + 1, &size, overlapped);
+		ret = ReadFile(hid_handle, transfer_priv->hid_buffer, length + 1, NULL, overlapped);
 	} else {
 		if (!priv->hid->uses_report_ids[1])
 			memcpy(transfer_priv->hid_buffer + 1, transfer->buffer, transfer->length);
@@ -3950,64 +3757,18 @@
 			memcpy(transfer_priv->hid_buffer, transfer->buffer, transfer->length);
 
 		usbi_dbg("writing %d bytes (report ID: 0x%02X)", length, transfer_priv->hid_buffer[0]);
-		ret = WriteFile(hid_handle, transfer_priv->hid_buffer, length, &size, overlapped);
+		ret = WriteFile(hid_handle, transfer_priv->hid_buffer, length, NULL, overlapped);
 	}
 
-	if (!ret) {
-		if (GetLastError() != ERROR_IO_PENDING) {
-			usbi_err(ctx, "HID transfer failed: %s", windows_error_str(0));
-			safe_free(transfer_priv->hid_buffer);
-			return LIBUSB_ERROR_IO;
-		}
-	} else {
-		// Only write operations that completed synchronously need to free up
-		// hid_buffer. For reads, copy_transfer_data() handles that process.
-		if (!direction_in)
-			safe_free(transfer_priv->hid_buffer);
-
-		if (size == 0) {
-			usbi_err(ctx, "program assertion failed - no data was transferred");
-			size = 1;
-		}
-		if (size > (size_t)length) {
-			usbi_err(ctx, "OVERFLOW!");
-			r = LIBUSB_ERROR_OVERFLOW;
-		}
-		windows_force_sync_completion(overlapped, (ULONG)size);
+	if (!ret && GetLastError() != ERROR_IO_PENDING) {
+		usbi_err(TRANSFER_CTX(transfer), "HID transfer failed: %s", windows_error_str(0));
+		safe_free(transfer_priv->hid_buffer);
+		return LIBUSB_ERROR_IO;
 	}
 
 	transfer_priv->interface_number = (uint8_t)current_interface;
 
-	return r;
-}
-
-static int hid_abort_transfers(int sub_api, struct usbi_transfer *itransfer)
-{
-	struct libusb_context *ctx = ITRANSFER_CTX(itransfer);
-	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-	struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
-	struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
-	HANDLE hid_handle;
-	int current_interface;
-
-	UNUSED(sub_api);
-	CHECK_HID_AVAILABLE;
-
-	current_interface = transfer_priv->interface_number;
-	if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) {
-		usbi_err(ctx, "program assertion failed: invalid interface_number");
-		return LIBUSB_ERROR_NOT_FOUND;
-	}
-	usbi_dbg("will use interface %d", current_interface);
-
-	hid_handle = handle_priv->interface_handle[current_interface].api_handle;
-
-	// Use CancelIoEx to cancel just a single transfer
-	if (CancelIoEx(hid_handle, transfer_priv->pollable_fd.overlapped))
-			return LIBUSB_SUCCESS;
-
-	usbi_warn(ctx, "CancelIoEx failed: %s", windows_error_str(0));
-	return LIBUSB_ERROR_NOT_FOUND;
+	return LIBUSB_SUCCESS;
 }
 
 static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
@@ -4031,7 +3792,6 @@
 
 static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint)
 {
-	struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
 	struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
 	struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
 	HANDLE hid_handle;
@@ -4042,7 +3802,7 @@
 
 	current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
 	if (current_interface < 0) {
-		usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear");
+		usbi_err(HANDLE_CTX(dev_handle), "unable to match endpoint to an open interface - cannot clear");
 		return LIBUSB_ERROR_NOT_FOUND;
 	}
 
@@ -4052,7 +3812,7 @@
 	// No endpoint selection with Microsoft's implementation, so we try to flush the
 	// whole interface. Should be OK for most case scenarios
 	if (!HidD_FlushQueue(hid_handle)) {
-		usbi_err(ctx, "Flushing of HID queue failed: %s", windows_error_str(0));
+		usbi_err(HANDLE_CTX(dev_handle), "Flushing of HID queue failed: %s", windows_error_str(0));
 		// Device was probably disconnected
 		return LIBUSB_ERROR_NO_DEVICE;
 	}
@@ -4061,33 +3821,31 @@
 }
 
 // This extra function is only needed for HID
-static int hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size)
+static enum libusb_transfer_status hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length)
 {
 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-	struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
-	struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
-	int r = LIBUSB_TRANSFER_COMPLETED;
-	uint32_t corrected_size = io_size;
+	struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
+	enum libusb_transfer_status r = LIBUSB_TRANSFER_COMPLETED;
 
 	UNUSED(sub_api);
 
 	if (transfer_priv->hid_buffer != NULL) {
 		// If we have a valid hid_buffer, it means the transfer was async
 		if (transfer_priv->hid_dest != NULL) { // Data readout
-			if (corrected_size > 0) {
+			if (length > 0) {
 				// First, check for overflow
-				if (corrected_size > transfer_priv->hid_expected_size) {
-					usbi_err(ctx, "OVERFLOW!");
-					corrected_size = (uint32_t)transfer_priv->hid_expected_size;
+				if ((size_t)length > transfer_priv->hid_expected_size) {
+					usbi_err(TRANSFER_CTX(transfer), "OVERFLOW!");
+					length = (DWORD)transfer_priv->hid_expected_size;
 					r = LIBUSB_TRANSFER_OVERFLOW;
 				}
 
 				if (transfer_priv->hid_buffer[0] == 0) {
 					// Discard the 1 byte report ID prefix
-					corrected_size--;
-					memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer + 1, corrected_size);
+					length--;
+					memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer + 1, length);
 				} else {
-					memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer, corrected_size);
+					memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer, length);
 				}
 			}
 			transfer_priv->hid_dest = NULL;
@@ -4096,7 +3854,7 @@
 		safe_free(transfer_priv->hid_buffer);
 	}
 
-	itransfer->transferred += corrected_size;
+	itransfer->transferred += (int)length;
 	return r;
 }
 
@@ -4107,13 +3865,15 @@
 static int composite_open(int sub_api, struct libusb_device_handle *dev_handle)
 {
 	struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
-	int r = LIBUSB_ERROR_NOT_FOUND;
-	uint8_t i;
+	int i, r = LIBUSB_ERROR_NOT_FOUND;
 	// SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID
-	bool available[SUB_API_MAX + 1] = { 0 };
+	bool available[SUB_API_MAX + 1];
 
 	UNUSED(sub_api);
 
+	for (i = 0; i < SUB_API_MAX + 1; i++)
+		available[i] = false;
+
 	for (i = 0; i < USB_MAXINTERFACES; i++) {
 		switch (priv->usb_interface[i].apib->id) {
 		case USB_API_WINUSBX:
@@ -4154,12 +3914,15 @@
 static void composite_close(int sub_api, struct libusb_device_handle *dev_handle)
 {
 	struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
-	uint8_t i;
+	int i;
 	// SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID
-	bool available[SUB_API_MAX + 1] = { 0 };
+	bool available[SUB_API_MAX + 1];
 
 	UNUSED(sub_api);
 
+	for (i = 0; i < SUB_API_MAX + 1; i++)
+		available[i] = false;
+
 	for (i = 0; i < USB_MAXINTERFACES; i++) {
 		switch (priv->usb_interface[i].apib->id) {
 		case USB_API_WINUSBX:
@@ -4219,7 +3982,6 @@
 static int composite_submit_control_transfer(int sub_api, 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 winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
 	struct libusb_config_descriptor *conf_desc;
 	WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer;
@@ -4278,13 +4040,13 @@
 		}
 	}
 
-	usbi_err(ctx, "no libusb supported interfaces to complete request");
+	usbi_err(TRANSFER_CTX(transfer), "no libusb supported interfaces to complete request");
 	return LIBUSB_ERROR_NOT_FOUND;
 }
 
-static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) {
+static int composite_submit_bulk_transfer(int sub_api, 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 winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
 	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
 	int current_interface;
@@ -4293,7 +4055,7 @@
 
 	current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
 	if (current_interface < 0) {
-		usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
+		usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer");
 		return LIBUSB_ERROR_NOT_FOUND;
 	}
 
@@ -4303,9 +4065,9 @@
 		submit_bulk_transfer(priv->usb_interface[current_interface].sub_api, itransfer);
 }
 
-static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer) {
+static int composite_submit_iso_transfer(int sub_api, 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 winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
 	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
 	int current_interface;
@@ -4314,7 +4076,7 @@
 
 	current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
 	if (current_interface < 0) {
-		usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
+		usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer");
 		return LIBUSB_ERROR_NOT_FOUND;
 	}
 
@@ -4326,7 +4088,6 @@
 
 static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint)
 {
-	struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
 	struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
 	struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
 	int current_interface;
@@ -4335,7 +4096,7 @@
 
 	current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
 	if (current_interface < 0) {
-		usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear");
+		usbi_err(HANDLE_CTX(dev_handle), "unable to match endpoint to an open interface - cannot clear");
 		return LIBUSB_ERROR_NOT_FOUND;
 	}
 
@@ -4345,51 +4106,30 @@
 		clear_halt(priv->usb_interface[current_interface].sub_api, dev_handle, endpoint);
 }
 
-static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer)
+static int composite_cancel_transfer(int sub_api, struct usbi_transfer *itransfer)
 {
 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-	struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+	struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
 	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
 	int current_interface = transfer_priv->interface_number;
 
 	UNUSED(sub_api);
 
 	if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) {
-		usbi_err(TRANSFER_CTX(transfer), "program assertion failed: invalid interface_number");
+		usbi_err(TRANSFER_CTX(transfer), "program assertion failed - invalid interface_number");
 		return LIBUSB_ERROR_NOT_FOUND;
 	}
 
-	CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, abort_control);
+	CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, cancel_transfer);
 
 	return priv->usb_interface[current_interface].apib->
-		abort_control(priv->usb_interface[current_interface].sub_api, itransfer);
-}
-
-static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfer)
-{
-	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-	struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
-	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
-	int current_interface = transfer_priv->interface_number;
-
-	UNUSED(sub_api);
-
-	if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) {
-		usbi_err(TRANSFER_CTX(transfer), "program assertion failed: invalid interface_number");
-		return LIBUSB_ERROR_NOT_FOUND;
-	}
-
-	CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, abort_transfers);
-
-	return priv->usb_interface[current_interface].apib->
-		abort_transfers(priv->usb_interface[current_interface].sub_api, itransfer);
+		cancel_transfer(priv->usb_interface[current_interface].sub_api, itransfer);
 }
 
 static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
 {
 	struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
-	int r;
-	uint8_t i;
+	int i, r;
 	bool available[SUB_API_MAX];
 
 	UNUSED(sub_api);
@@ -4414,16 +4154,19 @@
 	return LIBUSB_SUCCESS;
 }
 
-static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size)
+static enum libusb_transfer_status composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length)
 {
 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-	struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+	struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
 	struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
 	int current_interface = transfer_priv->interface_number;
 
 	UNUSED(sub_api);
-	CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, copy_transfer_data);
+	if (priv->usb_interface[current_interface].apib->copy_transfer_data == NULL) {
+		usbi_err(TRANSFER_CTX(transfer), "program assertion failed - no function to copy transfer data");
+		return LIBUSB_TRANSFER_ERROR;
+	}
 
 	return priv->usb_interface[current_interface].apib->
-		copy_transfer_data(priv->usb_interface[current_interface].sub_api, itransfer, io_size);
+		copy_transfer_data(priv->usb_interface[current_interface].sub_api, itransfer, length);
 }
diff --git a/libusb/os/windows_winusb.h b/libusb/os/windows_winusb.h
index 6ac39c3..57d4b7f 100644
--- a/libusb/os/windows_winusb.h
+++ b/libusb/os/windows_winusb.h
@@ -69,6 +69,8 @@
 const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = {0xF9F3FF14, 0xAE21, 0x48A0, {0x8A, 0x25, 0x80, 0x11, 0xA7, 0xA9, 0x31, 0xD9}};
 #endif
 
+// The following define MUST be == sizeof(USB_DESCRIPTOR_REQUEST)
+#define USB_DESCRIPTOR_REQUEST_SIZE	12U
 
 /*
  * Multiple USB API backend support
@@ -93,7 +95,7 @@
 	const char * const designation;
 	const char * const * const driver_name_list; // Driver name, without .sys, e.g. "usbccgp"
 	const uint8_t nb_driver_names;
-	int (*init)(struct libusb_context *ctx);
+	bool (*init)(struct libusb_context *ctx);
 	void (*exit)(void);
 	int (*open)(int sub_api, struct libusb_device_handle *dev_handle);
 	void (*close)(int sub_api, struct libusb_device_handle *dev_handle);
@@ -106,9 +108,8 @@
 	int (*submit_bulk_transfer)(int sub_api, struct usbi_transfer *itransfer);
 	int (*submit_iso_transfer)(int sub_api, struct usbi_transfer *itransfer);
 	int (*submit_control_transfer)(int sub_api, struct usbi_transfer *itransfer);
-	int (*abort_control)(int sub_api, struct usbi_transfer *itransfer);
-	int (*abort_transfers)(int sub_api, struct usbi_transfer *itransfer);
-	int (*copy_transfer_data)(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size);
+	int (*cancel_transfer)(int sub_api, struct usbi_transfer *itransfer);
+	enum libusb_transfer_status (*copy_transfer_data)(int sub_api, struct usbi_transfer *itransfer, DWORD length);
 };
 
 extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX];
@@ -226,8 +227,11 @@
 	free(p->dev_id);
 	free(p->path);
 	if ((dev->num_configurations > 0) && (p->config_descriptor != NULL)) {
-		for (i = 0; i < dev->num_configurations; i++)
-			free(p->config_descriptor[i]);
+		for (i = 0; i < dev->num_configurations; i++) {
+			if (p->config_descriptor[i] == NULL)
+				continue;
+			free((UCHAR *)p->config_descriptor[i] - USB_DESCRIPTOR_REQUEST_SIZE);
+		}
 	}
 	free(p->config_descriptor);
 	free(p->hid);
@@ -422,6 +426,12 @@
 /* libusbK */
 #define ISO_ALWAYS_START_ASAP	0x21
 
+typedef struct _USBD_ISO_PACKET_DESCRIPTOR {
+	ULONG Offset;
+	ULONG Length;
+	USBD_STATUS Status;
+} USBD_ISO_PACKET_DESCRIPTOR, *PUSBD_ISO_PACKET_DESCRIPTOR;
+
 typedef enum _USBD_PIPE_TYPE {
 	UsbdPipeTypeControl,
 	UsbdPipeTypeIsochronous,
@@ -429,6 +439,14 @@
 	UsbdPipeTypeInterrupt
 } USBD_PIPE_TYPE;
 
+typedef struct {
+	USBD_PIPE_TYPE PipeType;
+	UCHAR PipeId;
+	USHORT MaximumPacketSize;
+	UCHAR Interval;
+	ULONG MaximumBytesPerInterval;
+} WINUSB_PIPE_INFORMATION_EX, *PWINUSB_PIPE_INFORMATION_EX;
+
 #include <pshpack1.h>
 
 typedef struct _WINUSB_SETUP_PACKET {
@@ -441,7 +459,8 @@
 
 #include <poppack.h>
 
-typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE;
+typedef PVOID WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE;
+typedef PVOID WINUSB_ISOCH_BUFFER_HANDLE, *PWINUSB_ISOCH_BUFFER_HANDLE;
 
 typedef BOOL (WINAPI *WinUsb_AbortPipe_t)(
 	WINUSB_INTERFACE_HANDLE InterfaceHandle,
@@ -471,6 +490,21 @@
 	HANDLE DeviceHandle,
 	PWINUSB_INTERFACE_HANDLE InterfaceHandle
 );
+typedef BOOL (WINAPI *WinUsb_QueryPipeEx_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	UCHAR AlternateInterfaceHandle,
+	UCHAR PipeIndex,
+	PWINUSB_PIPE_INFORMATION_EX PipeInformationEx
+);
+typedef BOOL (WINAPI *WinUsb_ReadIsochPipeAsap_t)(
+	PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
+	ULONG Offset,
+	ULONG Length,
+	BOOL ContinueStream,
+	ULONG NumberOfPackets,
+	PUSBD_ISO_PACKET_DESCRIPTOR IsoPacketDescriptors,
+	LPOVERLAPPED Overlapped
+);
 typedef BOOL (WINAPI *WinUsb_ReadPipe_t)(
 	WINUSB_INTERFACE_HANDLE InterfaceHandle,
 	UCHAR PipeID,
@@ -479,8 +513,12 @@
 	PULONG LengthTransferred,
 	LPOVERLAPPED Overlapped
 );
-typedef BOOL (WINAPI *WinUsb_ResetDevice_t)(
-	WINUSB_INTERFACE_HANDLE InterfaceHandle
+typedef BOOL (WINAPI *WinUsb_RegisterIsochBuffer_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	UCHAR PipeID,
+	PVOID Buffer,
+	ULONG BufferLength,
+	PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle
 );
 typedef BOOL (WINAPI *WinUsb_ResetPipe_t)(
 	WINUSB_INTERFACE_HANDLE InterfaceHandle,
@@ -497,29 +535,9 @@
 	ULONG ValueLength,
 	PVOID Value
 );
-typedef BOOL (WINAPI *WinUsb_WritePipe_t)(
-	WINUSB_INTERFACE_HANDLE InterfaceHandle,
-	UCHAR PipeID,
-	PUCHAR Buffer,
-	ULONG BufferLength,
-	PULONG LengthTransferred,
-	LPOVERLAPPED Overlapped
-);
-
-typedef PVOID WINUSB_ISOCH_BUFFER_HANDLE, *PWINUSB_ISOCH_BUFFER_HANDLE;
-
-typedef BOOL (WINAPI *WinUsb_RegisterIsochBuffer_t)(
-	WINUSB_INTERFACE_HANDLE InterfaceHandle,
-	UCHAR PipeID,
-	PVOID Buffer,
-	ULONG BufferLength,
-	PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle
-);
-
 typedef BOOL (WINAPI *WinUsb_UnregisterIsochBuffer_t)(
 	WINUSB_ISOCH_BUFFER_HANDLE BufferHandle
 );
-
 typedef BOOL (WINAPI *WinUsb_WriteIsochPipeAsap_t)(
 	WINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
 	ULONG Offset,
@@ -527,37 +545,13 @@
 	BOOL ContinueStream,
 	LPOVERLAPPED Overlapped
 );
-
-typedef LONG USBD_STATUS;
-typedef struct {
-	ULONG Offset;
-	ULONG Length;
-	USBD_STATUS Status;
-} USBD_ISO_PACKET_DESCRIPTOR, *PUSBD_ISO_PACKET_DESCRIPTOR;
-
-typedef BOOL (WINAPI *WinUsb_ReadIsochPipeAsap_t)(
-	PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
-	ULONG Offset,
-	ULONG Length,
-	BOOL ContinueStream,
-	ULONG NumberOfPackets,
-	PUSBD_ISO_PACKET_DESCRIPTOR IsoPacketDescriptors,
-	LPOVERLAPPED Overlapped
-);
-
-typedef struct {
-	USBD_PIPE_TYPE PipeType;
-	UCHAR PipeId;
-	USHORT MaximumPacketSize;
-	UCHAR Interval;
-	ULONG MaximumBytesPerInterval;
-} WINUSB_PIPE_INFORMATION_EX, *PWINUSB_PIPE_INFORMATION_EX;
-
-typedef BOOL (WINAPI *WinUsb_QueryPipeEx_t)(
+typedef BOOL (WINAPI *WinUsb_WritePipe_t)(
 	WINUSB_INTERFACE_HANDLE InterfaceHandle,
-	UCHAR AlternateInterfaceHandle,
-	UCHAR PipeIndex,
-	PWINUSB_PIPE_INFORMATION_EX PipeInformationEx
+	UCHAR PipeID,
+	PUCHAR Buffer,
+	ULONG BufferLength,
+	PULONG LengthTransferred,
+	LPOVERLAPPED Overlapped
 );
 
 /* /!\ These must match the ones from the official libusbk.h */
@@ -607,15 +601,19 @@
 } KLIB_VERSION, *PKLIB_VERSION;
 
 typedef BOOL (WINAPI *LibK_GetProcAddress_t)(
-	PVOID *ProcAddress,
-	ULONG DriverID,
-	ULONG FunctionID
+	PVOID ProcAddress,
+	INT DriverID,
+	INT FunctionID
 );
 
 typedef VOID (WINAPI *LibK_GetVersion_t)(
 	PKLIB_VERSION Version
 );
 
+typedef BOOL (WINAPI *LibK_ResetDevice_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle
+);
+
 //KISO_PACKET is equivalent of libusb_iso_packet_descriptor except uses absolute "offset" field instead of sequential Lengths
 typedef struct _KISO_PACKET {
 	UINT offset;
@@ -638,7 +636,7 @@
 	KISO_PACKET IsoPackets[0];
 } KISO_CONTEXT, *PKISO_CONTEXT;
 
-typedef BOOL(WINAPI *WinUsb_IsoReadPipe_t)(
+typedef BOOL(WINAPI *LibK_IsoReadPipe_t)(
 	WINUSB_INTERFACE_HANDLE InterfaceHandle,
 	UCHAR PipeID,
 	PUCHAR Buffer,
@@ -647,7 +645,7 @@
 	PKISO_CONTEXT IsoContext
 );
 
-typedef BOOL(WINAPI *WinUsb_IsoWritePipe_t)(
+typedef BOOL(WINAPI *LibK_IsoWritePipe_t)(
 	WINUSB_INTERFACE_HANDLE InterfaceHandle,
 	UCHAR PipeID,
 	PUCHAR Buffer,
@@ -657,8 +655,7 @@
 );
 
 struct winusb_interface {
-	bool initialized;
-	bool CancelIoEx_supported;
+	HMODULE hDll;
 	WinUsb_AbortPipe_t AbortPipe;
 	WinUsb_ControlTransfer_t ControlTransfer;
 	WinUsb_FlushPipe_t FlushPipe;
@@ -666,22 +663,27 @@
 	WinUsb_GetAssociatedInterface_t GetAssociatedInterface;
 	WinUsb_Initialize_t Initialize;
 	WinUsb_ReadPipe_t ReadPipe;
-	WinUsb_ResetDevice_t ResetDevice;
 	WinUsb_ResetPipe_t ResetPipe;
 	WinUsb_SetCurrentAlternateSetting_t SetCurrentAlternateSetting;
 	WinUsb_SetPipePolicy_t SetPipePolicy;
 	WinUsb_WritePipe_t WritePipe;
-
-	// Isochoronous functions for LibUSBk sub api:
-	WinUsb_IsoReadPipe_t IsoReadPipe;
-	WinUsb_IsoWritePipe_t IsoWritePipe;
-
-	// Isochronous functions for Microsoft WinUSB sub api (native WinUSB):
-	WinUsb_RegisterIsochBuffer_t RegisterIsochBuffer;
-	WinUsb_UnregisterIsochBuffer_t UnregisterIsochBuffer;
-	WinUsb_WriteIsochPipeAsap_t WriteIsochPipeAsap;
-	WinUsb_ReadIsochPipeAsap_t ReadIsochPipeAsap;
-	WinUsb_QueryPipeEx_t QueryPipeEx;
+	union {
+		struct {
+			// Isochoronous functions for libusbK sub api:
+			LibK_IsoReadPipe_t IsoReadPipe;
+			LibK_IsoWritePipe_t IsoWritePipe;
+			// Reset device function for libusbK sub api:
+			LibK_ResetDevice_t ResetDevice;
+		};
+		struct {
+			// Isochronous functions for WinUSB sub api:
+			WinUsb_QueryPipeEx_t QueryPipeEx;
+			WinUsb_ReadIsochPipeAsap_t ReadIsochPipeAsap;
+			WinUsb_RegisterIsochBuffer_t RegisterIsochBuffer;
+			WinUsb_UnregisterIsochBuffer_t UnregisterIsochBuffer;
+			WinUsb_WriteIsochPipeAsap_t WriteIsochPipeAsap;
+		};
+	};
 };
 
 /* hid.dll interface */
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index 7e27bf5..8c3a7c4 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 11453
+#define LIBUSB_NANO 11454