Home | History | Annotate | Download | only in os
      1 /*
      2  * windows UsbDk backend for libusb 1.0
      3  * Copyright  2014 Red Hat, Inc.
      4 
      5  * Authors:
      6  * Dmitry Fleytman <dmitry (at) daynix.com>
      7  * Pavel Gurvich <pavel (at) daynix.com>
      8  *
      9  * This library is free software; you can redistribute it and/or
     10  * modify it under the terms of the GNU Lesser General Public
     11  * License as published by the Free Software Foundation; either
     12  * version 2.1 of the License, or (at your option) any later version.
     13  *
     14  * This library is distributed in the hope that it will be useful,
     15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17  * Lesser General Public License for more details.
     18  *
     19  * You should have received a copy of the GNU Lesser General Public
     20  * License along with this library; if not, write to the Free Software
     21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     22  */
     23 
     24 #include <config.h>
     25 
     26 #if defined(USE_USBDK)
     27 
     28 #include <windows.h>
     29 #include <cfgmgr32.h>
     30 #include <stdio.h>
     31 
     32 #include "libusbi.h"
     33 #include "windows_common.h"
     34 #include "windows_nt_common.h"
     35 
     36 #define ULONG64 uint64_t
     37 #define PVOID64 uint64_t
     38 
     39 typedef CONST WCHAR *PCWCHAR;
     40 #define wcsncpy_s wcsncpy
     41 
     42 #include "windows_usbdk.h"
     43 
     44 #if !defined(STATUS_SUCCESS)
     45 typedef LONG NTSTATUS;
     46 #define STATUS_SUCCESS			((NTSTATUS)0x00000000L)
     47 #endif
     48 
     49 #if !defined(STATUS_CANCELLED)
     50 #define STATUS_CANCELLED		((NTSTATUS)0xC0000120L)
     51 #endif
     52 
     53 #if !defined(STATUS_REQUEST_CANCELED)
     54 #define STATUS_REQUEST_CANCELED		((NTSTATUS)0xC0000703L)
     55 #endif
     56 
     57 #if !defined(USBD_SUCCESS)
     58 typedef int32_t USBD_STATUS;
     59 #define USBD_SUCCESS(Status)		((USBD_STATUS) (Status) >= 0)
     60 #define USBD_PENDING(Status)		((ULONG) (Status) >> 30 == 1)
     61 #define USBD_ERROR(Status)		((USBD_STATUS) (Status) < 0)
     62 #define USBD_STATUS_STALL_PID		((USBD_STATUS) 0xc0000004)
     63 #define USBD_STATUS_ENDPOINT_HALTED	((USBD_STATUS) 0xc0000030)
     64 #define USBD_STATUS_BAD_START_FRAME	((USBD_STATUS) 0xc0000a00)
     65 #define USBD_STATUS_TIMEOUT		((USBD_STATUS) 0xc0006000)
     66 #define USBD_STATUS_CANCELED		((USBD_STATUS) 0xc0010000)
     67 #endif
     68 
     69 static int concurrent_usage = -1;
     70 
     71 struct usbdk_device_priv {
     72 	USB_DK_DEVICE_INFO info;
     73 	PUSB_CONFIGURATION_DESCRIPTOR *config_descriptors;
     74 	HANDLE redirector_handle;
     75 	uint8_t active_configuration;
     76 };
     77 
     78 struct usbdk_transfer_priv {
     79 	USB_DK_TRANSFER_REQUEST request;
     80 	struct winfd pollable_fd;
     81 	PULONG64 IsochronousPacketsArray;
     82 	PUSB_DK_ISO_TRANSFER_RESULT IsochronousResultsArray;
     83 };
     84 
     85 static inline struct usbdk_device_priv *_usbdk_device_priv(struct libusb_device *dev)
     86 {
     87 	return (struct usbdk_device_priv *)dev->os_priv;
     88 }
     89 
     90 static inline struct usbdk_transfer_priv *_usbdk_transfer_priv(struct usbi_transfer *itransfer)
     91 {
     92 	return (struct usbdk_transfer_priv *)usbi_transfer_get_os_priv(itransfer);
     93 }
     94 
     95 static struct {
     96 	HMODULE module;
     97 
     98 	USBDK_GET_DEVICES_LIST			GetDevicesList;
     99 	USBDK_RELEASE_DEVICES_LIST		ReleaseDevicesList;
    100 	USBDK_START_REDIRECT			StartRedirect;
    101 	USBDK_STOP_REDIRECT			StopRedirect;
    102 	USBDK_GET_CONFIGURATION_DESCRIPTOR	GetConfigurationDescriptor;
    103 	USBDK_RELEASE_CONFIGURATION_DESCRIPTOR	ReleaseConfigurationDescriptor;
    104 	USBDK_READ_PIPE				ReadPipe;
    105 	USBDK_WRITE_PIPE			WritePipe;
    106 	USBDK_ABORT_PIPE			AbortPipe;
    107 	USBDK_RESET_PIPE			ResetPipe;
    108 	USBDK_SET_ALTSETTING			SetAltsetting;
    109 	USBDK_RESET_DEVICE			ResetDevice;
    110 	USBDK_GET_REDIRECTOR_SYSTEM_HANDLE	GetRedirectorSystemHandle;
    111 } usbdk_helper;
    112 
    113 static FARPROC get_usbdk_proc_addr(struct libusb_context *ctx, LPCSTR api_name)
    114 {
    115 	FARPROC api_ptr = GetProcAddress(usbdk_helper.module, api_name);
    116 
    117 	if (api_ptr == NULL)
    118 		usbi_err(ctx, "UsbDkHelper API %s not found, error %d", api_name, GetLastError());
    119 
    120 	return api_ptr;
    121 }
    122 
    123 static void unload_usbdk_helper_dll(void)
    124 {
    125 	if (usbdk_helper.module != NULL) {
    126 		FreeLibrary(usbdk_helper.module);
    127 		usbdk_helper.module = NULL;
    128 	}
    129 }
    130 
    131 static int load_usbdk_helper_dll(struct libusb_context *ctx)
    132 {
    133 	usbdk_helper.module = LoadLibraryA("UsbDkHelper");
    134 	if (usbdk_helper.module == NULL) {
    135 		usbi_err(ctx, "Failed to load UsbDkHelper.dll, error %d", GetLastError());
    136 		return LIBUSB_ERROR_NOT_FOUND;
    137 	}
    138 
    139 	usbdk_helper.GetDevicesList = (USBDK_GET_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_GetDevicesList");
    140 	if (usbdk_helper.GetDevicesList == NULL)
    141 		goto error_unload;
    142 
    143 	usbdk_helper.ReleaseDevicesList = (USBDK_RELEASE_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseDevicesList");
    144 	if (usbdk_helper.ReleaseDevicesList == NULL)
    145 		goto error_unload;
    146 
    147 	usbdk_helper.StartRedirect = (USBDK_START_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StartRedirect");
    148 	if (usbdk_helper.StartRedirect == NULL)
    149 		goto error_unload;
    150 
    151 	usbdk_helper.StopRedirect = (USBDK_STOP_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StopRedirect");
    152 	if (usbdk_helper.StopRedirect == NULL)
    153 		goto error_unload;
    154 
    155 	usbdk_helper.GetConfigurationDescriptor = (USBDK_GET_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_GetConfigurationDescriptor");
    156 	if (usbdk_helper.GetConfigurationDescriptor == NULL)
    157 		goto error_unload;
    158 
    159 	usbdk_helper.ReleaseConfigurationDescriptor = (USBDK_RELEASE_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseConfigurationDescriptor");
    160 	if (usbdk_helper.ReleaseConfigurationDescriptor == NULL)
    161 		goto error_unload;
    162 
    163 	usbdk_helper.ReadPipe = (USBDK_READ_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ReadPipe");
    164 	if (usbdk_helper.ReadPipe == NULL)
    165 		goto error_unload;
    166 
    167 	usbdk_helper.WritePipe = (USBDK_WRITE_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_WritePipe");
    168 	if (usbdk_helper.WritePipe == NULL)
    169 		goto error_unload;
    170 
    171 	usbdk_helper.AbortPipe = (USBDK_ABORT_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_AbortPipe");
    172 	if (usbdk_helper.AbortPipe == NULL)
    173 		goto error_unload;
    174 
    175 	usbdk_helper.ResetPipe = (USBDK_RESET_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ResetPipe");
    176 	if (usbdk_helper.ResetPipe == NULL)
    177 		goto error_unload;
    178 
    179 	usbdk_helper.SetAltsetting = (USBDK_SET_ALTSETTING)get_usbdk_proc_addr(ctx, "UsbDk_SetAltsetting");
    180 	if (usbdk_helper.SetAltsetting == NULL)
    181 		goto error_unload;
    182 
    183 	usbdk_helper.ResetDevice = (USBDK_RESET_DEVICE)get_usbdk_proc_addr(ctx, "UsbDk_ResetDevice");
    184 	if (usbdk_helper.ResetDevice == NULL)
    185 		goto error_unload;
    186 
    187 	usbdk_helper.GetRedirectorSystemHandle = (USBDK_GET_REDIRECTOR_SYSTEM_HANDLE)get_usbdk_proc_addr(ctx, "UsbDk_GetRedirectorSystemHandle");
    188 	if (usbdk_helper.GetRedirectorSystemHandle == NULL)
    189 		goto error_unload;
    190 
    191 	return LIBUSB_SUCCESS;
    192 
    193 error_unload:
    194 	FreeLibrary(usbdk_helper.module);
    195 	usbdk_helper.module = NULL;
    196 	return LIBUSB_ERROR_NOT_FOUND;
    197 }
    198 
    199 static int usbdk_init(struct libusb_context *ctx)
    200 {
    201 	int r;
    202 
    203 	if (++concurrent_usage == 0) { // First init?
    204 		r = load_usbdk_helper_dll(ctx);
    205 		if (r)
    206 			goto init_exit;
    207 
    208 		init_polling();
    209 
    210 		r = windows_common_init(ctx);
    211 		if (r)
    212 			goto init_exit;
    213 	}
    214 	// At this stage, either we went through full init successfully, or didn't need to
    215 	r = LIBUSB_SUCCESS;
    216 
    217 init_exit:
    218 	if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed?
    219 		exit_polling();
    220 		windows_common_exit();
    221 		unload_usbdk_helper_dll();
    222 	}
    223 
    224 	if (r != LIBUSB_SUCCESS)
    225 		--concurrent_usage; // Not expected to call libusb_exit if we failed.
    226 
    227 	return r;
    228 }
    229 
    230 static int usbdk_get_session_id_for_device(struct libusb_context *ctx,
    231 	PUSB_DK_DEVICE_ID id, unsigned long *session_id)
    232 {
    233 	char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID)];
    234 
    235 	if (sprintf(dev_identity, "%S%S", id->DeviceID, id->InstanceID) == -1) {
    236 		usbi_warn(ctx, "cannot form device identity", id->DeviceID);
    237 		return LIBUSB_ERROR_NOT_SUPPORTED;
    238 	}
    239 
    240 	*session_id = htab_hash(dev_identity);
    241 
    242 	return LIBUSB_SUCCESS;
    243 }
    244 
    245 static void usbdk_release_config_descriptors(struct usbdk_device_priv *p, uint8_t count)
    246 {
    247 	uint8_t i;
    248 
    249 	for (i = 0; i < count; i++)
    250 		usbdk_helper.ReleaseConfigurationDescriptor(p->config_descriptors[i]);
    251 
    252 	free(p->config_descriptors);
    253 	p->config_descriptors = NULL;
    254 }
    255 
    256 static int usbdk_cache_config_descriptors(struct libusb_context *ctx,
    257 	struct usbdk_device_priv *p, PUSB_DK_DEVICE_INFO info)
    258 {
    259 	uint8_t i;
    260 	USB_DK_CONFIG_DESCRIPTOR_REQUEST Request;
    261 	Request.ID = info->ID;
    262 
    263 	p->config_descriptors = calloc(info->DeviceDescriptor.bNumConfigurations, sizeof(PUSB_CONFIGURATION_DESCRIPTOR));
    264 	if (p->config_descriptors == NULL) {
    265 		usbi_err(ctx, "failed to allocate configuration descriptors holder");
    266 		return LIBUSB_ERROR_NO_MEM;
    267 	}
    268 
    269 	for (i = 0; i < info->DeviceDescriptor.bNumConfigurations; i++) {
    270 		ULONG Length;
    271 
    272 		Request.Index = i;
    273 		if (!usbdk_helper.GetConfigurationDescriptor(&Request, &p->config_descriptors[i], &Length)) {
    274 			usbi_err(ctx, "failed to retrieve configuration descriptors");
    275 			usbdk_release_config_descriptors(p, i);
    276 			return LIBUSB_ERROR_OTHER;
    277 		}
    278 	}
    279 
    280 	return LIBUSB_SUCCESS;
    281 }
    282 
    283 static inline int usbdk_device_priv_init(struct libusb_context *ctx, struct libusb_device *dev, PUSB_DK_DEVICE_INFO info)
    284 {
    285 	struct usbdk_device_priv *p = _usbdk_device_priv(dev);
    286 
    287 	p->info = *info;
    288 	p->active_configuration = 0;
    289 
    290 	return usbdk_cache_config_descriptors(ctx, p, info);
    291 }
    292 
    293 static void usbdk_device_init(libusb_device *dev, PUSB_DK_DEVICE_INFO info)
    294 {
    295 	dev->bus_number = (uint8_t)info->FilterID;
    296 	dev->port_number = (uint8_t)info->Port;
    297 	dev->parent_dev = NULL;
    298 
    299 	//Addresses in libusb are 1-based
    300 	dev->device_address = (uint8_t)(info->Port + 1);
    301 
    302 	dev->num_configurations = info->DeviceDescriptor.bNumConfigurations;
    303 	dev->device_descriptor = info->DeviceDescriptor;
    304 
    305 	switch (info->Speed) {
    306 	case LowSpeed:
    307 		dev->speed = LIBUSB_SPEED_LOW;
    308 		break;
    309 	case FullSpeed:
    310 		dev->speed = LIBUSB_SPEED_FULL;
    311 		break;
    312 	case HighSpeed:
    313 		dev->speed = LIBUSB_SPEED_HIGH;
    314 		break;
    315 	case SuperSpeed:
    316 		dev->speed = LIBUSB_SPEED_SUPER;
    317 		break;
    318 	case NoSpeed:
    319 	default:
    320 		dev->speed = LIBUSB_SPEED_UNKNOWN;
    321 		break;
    322 	}
    323 }
    324 
    325 static int usbdk_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
    326 {
    327 	int r = LIBUSB_SUCCESS;
    328 	ULONG i;
    329 	struct discovered_devs *discdevs = NULL;
    330 	ULONG dev_number;
    331 	PUSB_DK_DEVICE_INFO devices;
    332 
    333 	if(!usbdk_helper.GetDevicesList(&devices, &dev_number))
    334 		return LIBUSB_ERROR_OTHER;
    335 
    336 	for (i = 0; i < dev_number; i++) {
    337 		unsigned long session_id;
    338 		struct libusb_device *dev = NULL;
    339 
    340 		if (usbdk_get_session_id_for_device(ctx, &devices[i].ID, &session_id))
    341 			continue;
    342 
    343 		dev = usbi_get_device_by_session_id(ctx, session_id);
    344 		if (dev == NULL) {
    345 			dev = usbi_alloc_device(ctx, session_id);
    346 			if (dev == NULL) {
    347 				usbi_err(ctx, "failed to allocate a new device structure");
    348 				continue;
    349 			}
    350 
    351 			usbdk_device_init(dev, &devices[i]);
    352 			if (usbdk_device_priv_init(ctx, dev, &devices[i]) != LIBUSB_SUCCESS) {
    353 				libusb_unref_device(dev);
    354 				continue;
    355 			}
    356 		}
    357 
    358 		discdevs = discovered_devs_append(*_discdevs, dev);
    359 		libusb_unref_device(dev);
    360 		if (!discdevs) {
    361 			usbi_err(ctx, "cannot append new device to list");
    362 			r = LIBUSB_ERROR_NO_MEM;
    363 			goto func_exit;
    364 		}
    365 
    366 		*_discdevs = discdevs;
    367 	}
    368 
    369 func_exit:
    370 	usbdk_helper.ReleaseDevicesList(devices);
    371 	return r;
    372 }
    373 
    374 static void usbdk_exit(void)
    375 {
    376 	if (--concurrent_usage < 0) {
    377 		windows_common_exit();
    378 		exit_polling();
    379 		unload_usbdk_helper_dll();
    380 	}
    381 }
    382 
    383 static int usbdk_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian)
    384 {
    385 	struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
    386 
    387 	memcpy(buffer, &priv->info.DeviceDescriptor, DEVICE_DESC_LENGTH);
    388 	*host_endian = 0;
    389 
    390 	return LIBUSB_SUCCESS;
    391 }
    392 
    393 static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
    394 {
    395 	struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
    396 	PUSB_CONFIGURATION_DESCRIPTOR config_header;
    397 	size_t size;
    398 
    399 	if (config_index >= dev->num_configurations)
    400 		return LIBUSB_ERROR_INVALID_PARAM;
    401 
    402 	config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptors[config_index];
    403 
    404 	size = min(config_header->wTotalLength, len);
    405 	memcpy(buffer, config_header, size);
    406 	*host_endian = 0;
    407 
    408 	return (int)size;
    409 }
    410 
    411 static inline int usbdk_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian)
    412 {
    413 	return usbdk_get_config_descriptor(dev, _usbdk_device_priv(dev)->active_configuration,
    414 			buffer, len, host_endian);
    415 }
    416 
    417 static int usbdk_open(struct libusb_device_handle *dev_handle)
    418 {
    419 	struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
    420 
    421 	priv->redirector_handle = usbdk_helper.StartRedirect(&priv->info.ID);
    422 	if (priv->redirector_handle == INVALID_HANDLE_VALUE) {
    423 		usbi_err(DEVICE_CTX(dev_handle->dev), "Redirector startup failed");
    424 		return LIBUSB_ERROR_OTHER;
    425 	}
    426 
    427 	return LIBUSB_SUCCESS;
    428 }
    429 
    430 static void usbdk_close(struct libusb_device_handle *dev_handle)
    431 {
    432 	struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
    433 
    434 	if (!usbdk_helper.StopRedirect(priv->redirector_handle)) {
    435 		struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
    436 		usbi_err(ctx, "Redirector shutdown failed");
    437 	}
    438 }
    439 
    440 static int usbdk_get_configuration(struct libusb_device_handle *dev_handle, int *config)
    441 {
    442 	*config = _usbdk_device_priv(dev_handle->dev)->active_configuration;
    443 
    444 	return LIBUSB_SUCCESS;
    445 }
    446 
    447 static int usbdk_set_configuration(struct libusb_device_handle *dev_handle, int config)
    448 {
    449 	UNUSED(dev_handle);
    450 	UNUSED(config);
    451 	return LIBUSB_SUCCESS;
    452 }
    453 
    454 static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, int iface)
    455 {
    456 	UNUSED(dev_handle);
    457 	UNUSED(iface);
    458 	return LIBUSB_SUCCESS;
    459 }
    460 
    461 static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
    462 {
    463 	struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
    464 	struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
    465 
    466 	if (!usbdk_helper.SetAltsetting(priv->redirector_handle, iface, altsetting)) {
    467 		usbi_err(ctx, "SetAltsetting failed: %s", windows_error_str(0));
    468 		return LIBUSB_ERROR_NO_DEVICE;
    469 	}
    470 
    471 	return LIBUSB_SUCCESS;
    472 }
    473 
    474 static int usbdk_release_interface(struct libusb_device_handle *dev_handle, int iface)
    475 {
    476 	UNUSED(dev_handle);
    477 	UNUSED(iface);
    478 	return LIBUSB_SUCCESS;
    479 }
    480 
    481 static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
    482 {
    483 	struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
    484 	struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
    485 
    486 	if (!usbdk_helper.ResetPipe(priv->redirector_handle, endpoint)) {
    487 		usbi_err(ctx, "ResetPipe failed: %s", windows_error_str(0));
    488 		return LIBUSB_ERROR_NO_DEVICE;
    489 	}
    490 
    491 	return LIBUSB_SUCCESS;
    492 }
    493 
    494 static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
    495 {
    496 	struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
    497 	struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
    498 
    499 	if (!usbdk_helper.ResetDevice(priv->redirector_handle)) {
    500 		usbi_err(ctx, "ResetDevice failed: %s", windows_error_str(0));
    501 		return LIBUSB_ERROR_NO_DEVICE;
    502 	}
    503 
    504 	return LIBUSB_SUCCESS;
    505 }
    506 
    507 static int usbdk_kernel_driver_active(struct libusb_device_handle *dev_handle, int iface)
    508 {
    509 	UNUSED(dev_handle);
    510 	UNUSED(iface);
    511 	return LIBUSB_ERROR_NOT_SUPPORTED;
    512 }
    513 
    514 static int usbdk_attach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
    515 {
    516 	UNUSED(dev_handle);
    517 	UNUSED(iface);
    518 	return LIBUSB_ERROR_NOT_SUPPORTED;
    519 }
    520 
    521 static int usbdk_detach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
    522 {
    523 	UNUSED(dev_handle);
    524 	UNUSED(iface);
    525 	return LIBUSB_ERROR_NOT_SUPPORTED;
    526 }
    527 
    528 static void usbdk_destroy_device(struct libusb_device *dev)
    529 {
    530 	struct usbdk_device_priv* p = _usbdk_device_priv(dev);
    531 
    532 	if (p->config_descriptors != NULL)
    533 		usbdk_release_config_descriptors(p, p->info.DeviceDescriptor.bNumConfigurations);
    534 }
    535 
    536 void windows_clear_transfer_priv(struct usbi_transfer *itransfer)
    537 {
    538 	struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
    539 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
    540 
    541 	usbi_free_fd(&transfer_priv->pollable_fd);
    542 
    543 	if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
    544 		safe_free(transfer_priv->IsochronousPacketsArray);
    545 		safe_free(transfer_priv->IsochronousResultsArray);
    546 	}
    547 }
    548 
    549 static int usbdk_do_control_transfer(struct usbi_transfer *itransfer)
    550 {
    551 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
    552 	struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
    553 	struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
    554 	struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
    555 	struct winfd wfd;
    556 	ULONG Length;
    557 	TransferResult transResult;
    558 	HANDLE sysHandle;
    559 
    560 	sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
    561 
    562 	wfd = usbi_create_fd(sysHandle, RW_READ, NULL, NULL);
    563 	// Always use the handle returned from usbi_create_fd (wfd.handle)
    564 	if (wfd.fd < 0)
    565 		return LIBUSB_ERROR_NO_MEM;
    566 
    567 	transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer;
    568 	transfer_priv->request.BufferLength = transfer->length;
    569 	transfer_priv->request.TransferType = ControlTransferType;
    570 	transfer_priv->pollable_fd = INVALID_WINFD;
    571 	Length = (ULONG)transfer->length;
    572 
    573 	if (IS_XFERIN(transfer))
    574 		transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
    575 	else
    576 		transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
    577 
    578 	switch (transResult) {
    579 	case TransferSuccess:
    580 		wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
    581 		wfd.overlapped->InternalHigh = (DWORD)Length;
    582 		break;
    583 	case TransferSuccessAsync:
    584 		break;
    585 	case TransferFailure:
    586 		usbi_err(ctx, "ControlTransfer failed: %s", windows_error_str(0));
    587 		usbi_free_fd(&wfd);
    588 		return LIBUSB_ERROR_IO;
    589 	}
    590 
    591 	// Use priv_transfer to store data needed for async polling
    592 	transfer_priv->pollable_fd = wfd;
    593 	usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN);
    594 
    595 	return LIBUSB_SUCCESS;
    596 }
    597 
    598 static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
    599 {
    600 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
    601 	struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
    602 	struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
    603 	struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
    604 	struct winfd wfd;
    605 	TransferResult transferRes;
    606 	HANDLE sysHandle;
    607 
    608 	transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer;
    609 	transfer_priv->request.BufferLength = transfer->length;
    610 	transfer_priv->request.EndpointAddress = transfer->endpoint;
    611 
    612 	switch (transfer->type) {
    613 	case LIBUSB_TRANSFER_TYPE_BULK:
    614 		transfer_priv->request.TransferType = BulkTransferType;
    615 		break;
    616 	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
    617 		transfer_priv->request.TransferType = IntertuptTransferType;
    618 		break;
    619 	default:
    620 		usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer. %s", transfer->type, windows_error_str(0));
    621 		return LIBUSB_ERROR_INVALID_PARAM;
    622 	}
    623 
    624 	transfer_priv->pollable_fd = INVALID_WINFD;
    625 
    626 	sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
    627 
    628 	wfd = usbi_create_fd(sysHandle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL);
    629 	// Always use the handle returned from usbi_create_fd (wfd.handle)
    630 	if (wfd.fd < 0)
    631 		return LIBUSB_ERROR_NO_MEM;
    632 
    633 	if (IS_XFERIN(transfer))
    634 		transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
    635 	else
    636 		transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
    637 
    638 	switch (transferRes) {
    639 	case TransferSuccess:
    640 		wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
    641 		break;
    642 	case TransferSuccessAsync:
    643 		break;
    644 	case TransferFailure:
    645 		usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
    646 		usbi_free_fd(&wfd);
    647 		return LIBUSB_ERROR_IO;
    648 	}
    649 
    650 	transfer_priv->pollable_fd = wfd;
    651 	usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, IS_XFERIN(transfer) ? POLLIN : POLLOUT);
    652 
    653 	return LIBUSB_SUCCESS;
    654 }
    655 
    656 static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
    657 {
    658 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
    659 	struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
    660 	struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
    661 	struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
    662 	struct winfd wfd;
    663 	TransferResult transferRes;
    664 	int i;
    665 	HANDLE sysHandle;
    666 
    667 	transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer;
    668 	transfer_priv->request.BufferLength = transfer->length;
    669 	transfer_priv->request.EndpointAddress = transfer->endpoint;
    670 	transfer_priv->request.TransferType = IsochronousTransferType;
    671 	transfer_priv->request.IsochronousPacketsArraySize = transfer->num_iso_packets;
    672 	transfer_priv->IsochronousPacketsArray = malloc(transfer->num_iso_packets * sizeof(ULONG64));
    673 	transfer_priv->request.IsochronousPacketsArray = (PVOID64)(uintptr_t)transfer_priv->IsochronousPacketsArray;
    674 	if (!transfer_priv->IsochronousPacketsArray) {
    675 		usbi_err(ctx, "Allocation of IsochronousPacketsArray is failed, %s", windows_error_str(0));
    676 		return LIBUSB_ERROR_IO;
    677 	}
    678 
    679 	transfer_priv->IsochronousResultsArray = malloc(transfer->num_iso_packets * sizeof(USB_DK_ISO_TRANSFER_RESULT));
    680 	transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)(uintptr_t)transfer_priv->IsochronousResultsArray;
    681 	if (!transfer_priv->IsochronousResultsArray) {
    682 		usbi_err(ctx, "Allocation of isochronousResultsArray is failed, %s", windows_error_str(0));
    683 		free(transfer_priv->IsochronousPacketsArray);
    684 		return LIBUSB_ERROR_IO;
    685 	}
    686 
    687 	for (i = 0; i < transfer->num_iso_packets; i++)
    688 		transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length;
    689 
    690 	transfer_priv->pollable_fd = INVALID_WINFD;
    691 
    692 	sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
    693 
    694 	wfd = usbi_create_fd(sysHandle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL);
    695 	// Always use the handle returned from usbi_create_fd (wfd.handle)
    696 	if (wfd.fd < 0) {
    697 		free(transfer_priv->IsochronousPacketsArray);
    698 		free(transfer_priv->IsochronousResultsArray);
    699 		return LIBUSB_ERROR_NO_MEM;
    700 	}
    701 
    702 	if (IS_XFERIN(transfer))
    703 		transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
    704 	else
    705 		transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
    706 
    707 	switch (transferRes) {
    708 	case TransferSuccess:
    709 		wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
    710 		break;
    711 	case TransferSuccessAsync:
    712 		break;
    713 	case TransferFailure:
    714 		usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
    715 		usbi_free_fd(&wfd);
    716 		free(transfer_priv->IsochronousPacketsArray);
    717 		free(transfer_priv->IsochronousResultsArray);
    718 		return LIBUSB_ERROR_IO;
    719 	}
    720 
    721 	transfer_priv->pollable_fd = wfd;
    722 	usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, IS_XFERIN(transfer) ? POLLIN : POLLOUT);
    723 
    724 	return LIBUSB_SUCCESS;
    725 }
    726 
    727 static int usbdk_submit_transfer(struct usbi_transfer *itransfer)
    728 {
    729 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
    730 
    731 	switch (transfer->type) {
    732 	case LIBUSB_TRANSFER_TYPE_CONTROL:
    733 		return usbdk_do_control_transfer(itransfer);
    734 	case LIBUSB_TRANSFER_TYPE_BULK:
    735 	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
    736 		if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
    737 			return LIBUSB_ERROR_NOT_SUPPORTED; //TODO: Check whether we can support this in UsbDk
    738 		else
    739 			return usbdk_do_bulk_transfer(itransfer);
    740 	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
    741 		return usbdk_do_iso_transfer(itransfer);
    742 	default:
    743 		usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
    744 		return LIBUSB_ERROR_INVALID_PARAM;
    745 	}
    746 }
    747 
    748 static int usbdk_abort_transfers(struct usbi_transfer *itransfer)
    749 {
    750 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
    751 	struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
    752 	struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
    753 
    754 	if (!usbdk_helper.AbortPipe(priv->redirector_handle, transfer->endpoint)) {
    755 		usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0));
    756 		return LIBUSB_ERROR_NO_DEVICE;
    757 	}
    758 
    759 	return LIBUSB_SUCCESS;
    760 }
    761 
    762 static int usbdk_cancel_transfer(struct usbi_transfer *itransfer)
    763 {
    764 	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
    765 
    766 	switch (transfer->type) {
    767 	case LIBUSB_TRANSFER_TYPE_CONTROL:
    768 		// Control transfers cancelled by IoCancelXXX() API
    769 		// No special treatment needed
    770 		return LIBUSB_SUCCESS;
    771 	case LIBUSB_TRANSFER_TYPE_BULK:
    772 	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
    773 	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
    774 		return usbdk_abort_transfers(itransfer);
    775 	default:
    776 		usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
    777 		return LIBUSB_ERROR_INVALID_PARAM;
    778 	}
    779 }
    780 
    781 int windows_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
    782 {
    783 	itransfer->transferred += io_size;
    784 	return LIBUSB_TRANSFER_COMPLETED;
    785 }
    786 
    787 struct winfd *windows_get_fd(struct usbi_transfer *transfer)
    788 {
    789 	struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer);
    790 	return &transfer_priv->pollable_fd;
    791 }
    792 
    793 static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus)
    794 {
    795 	if (USBD_SUCCESS(UsbdStatus))
    796 		return NO_ERROR;
    797 
    798 	switch (UsbdStatus) {
    799 	case USBD_STATUS_STALL_PID:
    800 	case USBD_STATUS_ENDPOINT_HALTED:
    801 	case USBD_STATUS_BAD_START_FRAME:
    802 		return ERROR_GEN_FAILURE;
    803 	case USBD_STATUS_TIMEOUT:
    804 		return ERROR_SEM_TIMEOUT;
    805 	case USBD_STATUS_CANCELED:
    806 		return ERROR_OPERATION_ABORTED;
    807 	default:
    808 		return ERROR_FUNCTION_FAILED;
    809 	}
    810 }
    811 
    812 void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size)
    813 {
    814 	if (HasOverlappedIoCompletedSync(pollable_fd->overlapped) // Handle async requests that completed synchronously first
    815 			|| GetOverlappedResult(pollable_fd->handle, pollable_fd->overlapped, io_size, false)) { // Regular async overlapped
    816 		struct libusb_transfer *ltransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer);
    817 		struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer);
    818 
    819 		if (ltransfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
    820 			int i;
    821 			for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) {
    822 				struct libusb_iso_packet_descriptor *lib_desc = &ltransfer->iso_packet_desc[i];
    823 
    824 				switch (transfer_priv->IsochronousResultsArray[i].TransferResult) {
    825 				case STATUS_SUCCESS:
    826 				case STATUS_CANCELLED:
    827 				case STATUS_REQUEST_CANCELED:
    828 					lib_desc->status = LIBUSB_TRANSFER_COMPLETED; // == ERROR_SUCCESS
    829 					break;
    830 				default:
    831 					lib_desc->status = LIBUSB_TRANSFER_ERROR; // ERROR_UNKNOWN_EXCEPTION;
    832 					break;
    833 				}
    834 
    835 				lib_desc->actual_length = (unsigned int)transfer_priv->IsochronousResultsArray[i].ActualLength;
    836 			}
    837 		}
    838 
    839 		*io_size = (DWORD) transfer_priv->request.Result.GenResult.BytesTransferred;
    840 		*io_result = usbdk_translate_usbd_status((USBD_STATUS) transfer_priv->request.Result.GenResult.UsbdStatus);
    841 	}
    842 	else {
    843 		*io_result = GetLastError();
    844 	}
    845 }
    846 
    847 static int usbdk_clock_gettime(int clk_id, struct timespec *tp)
    848 {
    849 	return windows_clock_gettime(clk_id, tp);
    850 }
    851 
    852 const struct usbi_os_backend usbdk_backend = {
    853 	"Windows",
    854 	USBI_CAP_HAS_HID_ACCESS,
    855 	usbdk_init,
    856 	usbdk_exit,
    857 
    858 	usbdk_get_device_list,
    859 	NULL,
    860 	usbdk_open,
    861 	usbdk_close,
    862 
    863 	usbdk_get_device_descriptor,
    864 	usbdk_get_active_config_descriptor,
    865 	usbdk_get_config_descriptor,
    866 	NULL,
    867 
    868 	usbdk_get_configuration,
    869 	usbdk_set_configuration,
    870 	usbdk_claim_interface,
    871 	usbdk_release_interface,
    872 
    873 	usbdk_set_interface_altsetting,
    874 	usbdk_clear_halt,
    875 	usbdk_reset_device,
    876 
    877 	NULL,
    878 	NULL,
    879 
    880 	NULL,	// dev_mem_alloc()
    881 	NULL,	// dev_mem_free()
    882 
    883 	usbdk_kernel_driver_active,
    884 	usbdk_detach_kernel_driver,
    885 	usbdk_attach_kernel_driver,
    886 
    887 	usbdk_destroy_device,
    888 
    889 	usbdk_submit_transfer,
    890 	usbdk_cancel_transfer,
    891 	windows_clear_transfer_priv,
    892 
    893 	windows_handle_events,
    894 	NULL,
    895 
    896 	usbdk_clock_gettime,
    897 #if defined(USBI_TIMERFD_AVAILABLE)
    898 	NULL,
    899 #endif
    900 	sizeof(struct usbdk_device_priv),
    901 	0,
    902 	sizeof(struct usbdk_transfer_priv),
    903 };
    904 
    905 #endif /* USE_USBDK */
    906