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 = <ransfer->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