2 * windows UsbDk backend for libusb 1.0
3 * Copyright © 2014 Red Hat, Inc.
6 * Dmitry Fleytman <dmitry@daynix.com>
7 * Pavel Gurvich <pavel@daynix.com>
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.
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.
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
26 #if defined(USE_USBDK)
33 #include "windows_common.h"
34 #include "windows_nt_common.h"
36 #define ULONG64 uint64_t
37 #define PVOID64 uint64_t
39 typedef CONST WCHAR *PCWCHAR;
40 #define wcsncpy_s wcsncpy
42 #include "windows_usbdk.h"
44 #if !defined(STATUS_SUCCESS)
45 typedef LONG NTSTATUS;
46 #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
49 #if !defined(STATUS_CANCELLED)
50 #define STATUS_CANCELLED ((NTSTATUS)0xC0000120L)
53 #if !defined(STATUS_REQUEST_CANCELED)
54 #define STATUS_REQUEST_CANCELED ((NTSTATUS)0xC0000703L)
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)
69 static int concurrent_usage = -1;
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;
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;
85 static inline struct usbdk_device_priv *_usbdk_device_priv(struct libusb_device *dev)
87 return (struct usbdk_device_priv *)dev->os_priv;
90 static inline struct usbdk_transfer_priv *_usbdk_transfer_priv(struct usbi_transfer *itransfer)
92 return (struct usbdk_transfer_priv *)usbi_transfer_get_os_priv(itransfer);
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;
113 static FARPROC get_usbdk_proc_addr(struct libusb_context *ctx, LPCSTR api_name)
115 FARPROC api_ptr = GetProcAddress(usbdk_helper.module, api_name);
118 usbi_err(ctx, "UsbDkHelper API %s not found, error %d", api_name, GetLastError());
123 static void unload_usbdk_helper_dll(void)
125 if (usbdk_helper.module != NULL) {
126 FreeLibrary(usbdk_helper.module);
127 usbdk_helper.module = NULL;
131 static int load_usbdk_helper_dll(struct libusb_context *ctx)
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;
139 usbdk_helper.GetDevicesList = (USBDK_GET_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_GetDevicesList");
140 if (usbdk_helper.GetDevicesList == NULL)
143 usbdk_helper.ReleaseDevicesList = (USBDK_RELEASE_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseDevicesList");
144 if (usbdk_helper.ReleaseDevicesList == NULL)
147 usbdk_helper.StartRedirect = (USBDK_START_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StartRedirect");
148 if (usbdk_helper.StartRedirect == NULL)
151 usbdk_helper.StopRedirect = (USBDK_STOP_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StopRedirect");
152 if (usbdk_helper.StopRedirect == NULL)
155 usbdk_helper.GetConfigurationDescriptor = (USBDK_GET_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_GetConfigurationDescriptor");
156 if (usbdk_helper.GetConfigurationDescriptor == NULL)
159 usbdk_helper.ReleaseConfigurationDescriptor = (USBDK_RELEASE_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseConfigurationDescriptor");
160 if (usbdk_helper.ReleaseConfigurationDescriptor == NULL)
163 usbdk_helper.ReadPipe = (USBDK_READ_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ReadPipe");
164 if (usbdk_helper.ReadPipe == NULL)
167 usbdk_helper.WritePipe = (USBDK_WRITE_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_WritePipe");
168 if (usbdk_helper.WritePipe == NULL)
171 usbdk_helper.AbortPipe = (USBDK_ABORT_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_AbortPipe");
172 if (usbdk_helper.AbortPipe == NULL)
175 usbdk_helper.ResetPipe = (USBDK_RESET_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ResetPipe");
176 if (usbdk_helper.ResetPipe == NULL)
179 usbdk_helper.SetAltsetting = (USBDK_SET_ALTSETTING)get_usbdk_proc_addr(ctx, "UsbDk_SetAltsetting");
180 if (usbdk_helper.SetAltsetting == NULL)
183 usbdk_helper.ResetDevice = (USBDK_RESET_DEVICE)get_usbdk_proc_addr(ctx, "UsbDk_ResetDevice");
184 if (usbdk_helper.ResetDevice == NULL)
187 usbdk_helper.GetRedirectorSystemHandle = (USBDK_GET_REDIRECTOR_SYSTEM_HANDLE)get_usbdk_proc_addr(ctx, "UsbDk_GetRedirectorSystemHandle");
188 if (usbdk_helper.GetRedirectorSystemHandle == NULL)
191 return LIBUSB_SUCCESS;
194 FreeLibrary(usbdk_helper.module);
195 usbdk_helper.module = NULL;
196 return LIBUSB_ERROR_NOT_FOUND;
199 static int usbdk_init(struct libusb_context *ctx)
203 if (++concurrent_usage == 0) { // First init?
204 r = load_usbdk_helper_dll(ctx);
210 r = windows_common_init(ctx);
214 // At this stage, either we went through full init successfully, or didn't need to
218 if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed?
220 windows_common_exit();
221 unload_usbdk_helper_dll();
224 if (r != LIBUSB_SUCCESS)
225 --concurrent_usage; // Not expected to call libusb_exit if we failed.
230 static int usbdk_get_session_id_for_device(struct libusb_context *ctx,
231 PUSB_DK_DEVICE_ID id, unsigned long *session_id)
233 char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID)];
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;
240 *session_id = htab_hash(dev_identity);
242 return LIBUSB_SUCCESS;
245 static void usbdk_release_config_descriptors(struct usbdk_device_priv *p, uint8_t count)
249 for (i = 0; i < count; i++)
250 usbdk_helper.ReleaseConfigurationDescriptor(p->config_descriptors[i]);
252 free(p->config_descriptors);
253 p->config_descriptors = NULL;
256 static int usbdk_cache_config_descriptors(struct libusb_context *ctx,
257 struct usbdk_device_priv *p, PUSB_DK_DEVICE_INFO info)
260 USB_DK_CONFIG_DESCRIPTOR_REQUEST Request;
261 Request.ID = info->ID;
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;
269 for (i = 0; i < info->DeviceDescriptor.bNumConfigurations; 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;
280 return LIBUSB_SUCCESS;
283 static inline int usbdk_device_priv_init(struct libusb_context *ctx, struct libusb_device *dev, PUSB_DK_DEVICE_INFO info)
285 struct usbdk_device_priv *p = _usbdk_device_priv(dev);
288 p->active_configuration = 0;
290 return usbdk_cache_config_descriptors(ctx, p, info);
293 static void usbdk_device_init(libusb_device *dev, PUSB_DK_DEVICE_INFO info)
295 dev->bus_number = (uint8_t)info->FilterID;
296 dev->port_number = (uint8_t)info->Port;
297 dev->parent_dev = NULL;
299 //Addresses in libusb are 1-based
300 dev->device_address = (uint8_t)(info->Port + 1);
302 dev->num_configurations = info->DeviceDescriptor.bNumConfigurations;
303 dev->device_descriptor = info->DeviceDescriptor;
305 switch (info->Speed) {
307 dev->speed = LIBUSB_SPEED_LOW;
310 dev->speed = LIBUSB_SPEED_FULL;
313 dev->speed = LIBUSB_SPEED_HIGH;
316 dev->speed = LIBUSB_SPEED_SUPER;
320 dev->speed = LIBUSB_SPEED_UNKNOWN;
325 static int usbdk_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
327 int r = LIBUSB_SUCCESS;
329 struct discovered_devs *discdevs = NULL;
331 PUSB_DK_DEVICE_INFO devices;
333 if(!usbdk_helper.GetDevicesList(&devices, &dev_number))
334 return LIBUSB_ERROR_OTHER;
336 for (i = 0; i < dev_number; i++) {
337 unsigned long session_id;
338 struct libusb_device *dev = NULL;
340 if (usbdk_get_session_id_for_device(ctx, &devices[i].ID, &session_id))
343 dev = usbi_get_device_by_session_id(ctx, session_id);
345 dev = usbi_alloc_device(ctx, session_id);
347 usbi_err(ctx, "failed to allocate a new device structure");
351 usbdk_device_init(dev, &devices[i]);
352 if (usbdk_device_priv_init(ctx, dev, &devices[i]) != LIBUSB_SUCCESS) {
353 libusb_unref_device(dev);
358 discdevs = discovered_devs_append(*_discdevs, dev);
359 libusb_unref_device(dev);
361 usbi_err(ctx, "cannot append new device to list");
362 r = LIBUSB_ERROR_NO_MEM;
366 *_discdevs = discdevs;
370 usbdk_helper.ReleaseDevicesList(devices);
374 static void usbdk_exit(void)
376 if (--concurrent_usage < 0) {
377 windows_common_exit();
379 unload_usbdk_helper_dll();
383 static int usbdk_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian)
385 struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
387 memcpy(buffer, &priv->info.DeviceDescriptor, DEVICE_DESC_LENGTH);
390 return LIBUSB_SUCCESS;
393 static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
395 struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
396 PUSB_CONFIGURATION_DESCRIPTOR config_header;
399 if (config_index >= dev->num_configurations)
400 return LIBUSB_ERROR_INVALID_PARAM;
402 config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptors[config_index];
404 size = min(config_header->wTotalLength, len);
405 memcpy(buffer, config_header, size);
411 static inline int usbdk_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian)
413 return usbdk_get_config_descriptor(dev, _usbdk_device_priv(dev)->active_configuration,
414 buffer, len, host_endian);
417 static int usbdk_open(struct libusb_device_handle *dev_handle)
419 struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
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;
427 return LIBUSB_SUCCESS;
430 static void usbdk_close(struct libusb_device_handle *dev_handle)
432 struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
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");
440 static int usbdk_get_configuration(struct libusb_device_handle *dev_handle, int *config)
442 *config = _usbdk_device_priv(dev_handle->dev)->active_configuration;
444 return LIBUSB_SUCCESS;
447 static int usbdk_set_configuration(struct libusb_device_handle *dev_handle, int config)
451 return LIBUSB_SUCCESS;
454 static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, int iface)
458 return LIBUSB_SUCCESS;
461 static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
463 struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
464 struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
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;
471 return LIBUSB_SUCCESS;
474 static int usbdk_release_interface(struct libusb_device_handle *dev_handle, int iface)
478 return LIBUSB_SUCCESS;
481 static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
483 struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
484 struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
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;
491 return LIBUSB_SUCCESS;
494 static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
496 struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
497 struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
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;
504 return LIBUSB_SUCCESS;
507 static int usbdk_kernel_driver_active(struct libusb_device_handle *dev_handle, int iface)
511 return LIBUSB_ERROR_NOT_SUPPORTED;
514 static int usbdk_attach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
518 return LIBUSB_ERROR_NOT_SUPPORTED;
521 static int usbdk_detach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
525 return LIBUSB_ERROR_NOT_SUPPORTED;
528 static void usbdk_destroy_device(struct libusb_device *dev)
530 struct usbdk_device_priv* p = _usbdk_device_priv(dev);
532 if (p->config_descriptors != NULL)
533 usbdk_release_config_descriptors(p, p->info.DeviceDescriptor.bNumConfigurations);
536 void windows_clear_transfer_priv(struct usbi_transfer *itransfer)
538 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
539 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
541 usbi_free_fd(&transfer_priv->pollable_fd);
543 if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
544 safe_free(transfer_priv->IsochronousPacketsArray);
545 safe_free(transfer_priv->IsochronousResultsArray);
549 static int usbdk_do_control_transfer(struct usbi_transfer *itransfer)
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);
557 TransferResult transResult;
560 sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
562 wfd = usbi_create_fd(sysHandle, RW_READ, NULL, NULL);
563 // Always use the handle returned from usbi_create_fd (wfd.handle)
565 return LIBUSB_ERROR_NO_MEM;
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;
573 if (IS_XFERIN(transfer))
574 transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
576 transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
578 switch (transResult) {
579 case TransferSuccess:
580 wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
581 wfd.overlapped->InternalHigh = (DWORD)Length;
583 case TransferSuccessAsync:
585 case TransferFailure:
586 usbi_err(ctx, "ControlTransfer failed: %s", windows_error_str(0));
588 return LIBUSB_ERROR_IO;
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);
595 return LIBUSB_SUCCESS;
598 static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
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);
605 TransferResult transferRes;
608 transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer;
609 transfer_priv->request.BufferLength = transfer->length;
610 transfer_priv->request.EndpointAddress = transfer->endpoint;
612 switch (transfer->type) {
613 case LIBUSB_TRANSFER_TYPE_BULK:
614 transfer_priv->request.TransferType = BulkTransferType;
616 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
617 transfer_priv->request.TransferType = IntertuptTransferType;
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;
624 transfer_priv->pollable_fd = INVALID_WINFD;
626 sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
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)
631 return LIBUSB_ERROR_NO_MEM;
633 if (IS_XFERIN(transfer))
634 transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
636 transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
638 switch (transferRes) {
639 case TransferSuccess:
640 wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
642 case TransferSuccessAsync:
644 case TransferFailure:
645 usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
647 return LIBUSB_ERROR_IO;
650 transfer_priv->pollable_fd = wfd;
651 usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, IS_XFERIN(transfer) ? POLLIN : POLLOUT);
653 return LIBUSB_SUCCESS;
656 static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
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);
663 TransferResult transferRes;
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;
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;
687 for (i = 0; i < transfer->num_iso_packets; i++)
688 transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length;
690 transfer_priv->pollable_fd = INVALID_WINFD;
692 sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
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)
697 free(transfer_priv->IsochronousPacketsArray);
698 free(transfer_priv->IsochronousResultsArray);
699 return LIBUSB_ERROR_NO_MEM;
702 if (IS_XFERIN(transfer))
703 transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
705 transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
707 switch (transferRes) {
708 case TransferSuccess:
709 wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
711 case TransferSuccessAsync:
713 case TransferFailure:
714 usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
716 free(transfer_priv->IsochronousPacketsArray);
717 free(transfer_priv->IsochronousResultsArray);
718 return LIBUSB_ERROR_IO;
721 transfer_priv->pollable_fd = wfd;
722 usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, IS_XFERIN(transfer) ? POLLIN : POLLOUT);
724 return LIBUSB_SUCCESS;
727 static int usbdk_submit_transfer(struct usbi_transfer *itransfer)
729 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
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
739 return usbdk_do_bulk_transfer(itransfer);
740 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
741 return usbdk_do_iso_transfer(itransfer);
743 usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
744 return LIBUSB_ERROR_INVALID_PARAM;
748 static int usbdk_abort_transfers(struct usbi_transfer *itransfer)
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);
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;
759 return LIBUSB_SUCCESS;
762 static int usbdk_cancel_transfer(struct usbi_transfer *itransfer)
764 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
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);
776 usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
777 return LIBUSB_ERROR_INVALID_PARAM;
781 int windows_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
783 itransfer->transferred += io_size;
784 return LIBUSB_TRANSFER_COMPLETED;
787 struct winfd *windows_get_fd(struct usbi_transfer *transfer)
789 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer);
790 return &transfer_priv->pollable_fd;
793 static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus)
795 if (USBD_SUCCESS(UsbdStatus))
798 switch (UsbdStatus) {
799 case USBD_STATUS_TIMEOUT:
800 return ERROR_SEM_TIMEOUT;
801 case USBD_STATUS_CANCELED:
802 return ERROR_OPERATION_ABORTED;
804 return ERROR_GEN_FAILURE;
808 void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size)
810 if (HasOverlappedIoCompletedSync(pollable_fd->overlapped) // Handle async requests that completed synchronously first
811 || GetOverlappedResult(pollable_fd->handle, pollable_fd->overlapped, io_size, false)) { // Regular async overlapped
812 struct libusb_transfer *ltransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer);
813 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer);
815 if (ltransfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
817 for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) {
818 struct libusb_iso_packet_descriptor *lib_desc = <ransfer->iso_packet_desc[i];
820 switch (transfer_priv->IsochronousResultsArray[i].TransferResult) {
822 case STATUS_CANCELLED:
823 case STATUS_REQUEST_CANCELED:
824 lib_desc->status = LIBUSB_TRANSFER_COMPLETED; // == ERROR_SUCCESS
827 lib_desc->status = LIBUSB_TRANSFER_ERROR; // ERROR_UNKNOWN_EXCEPTION;
831 lib_desc->actual_length = (unsigned int)transfer_priv->IsochronousResultsArray[i].ActualLength;
835 *io_size = (DWORD) transfer_priv->request.Result.GenResult.BytesTransferred;
836 *io_result = usbdk_translate_usbd_status((USBD_STATUS) transfer_priv->request.Result.GenResult.UsbdStatus);
839 *io_result = GetLastError();
843 static int usbdk_clock_gettime(int clk_id, struct timespec *tp)
845 return windows_clock_gettime(clk_id, tp);
848 const struct usbi_os_backend usbi_backend = {
850 USBI_CAP_HAS_HID_ACCESS,
854 usbdk_get_device_list,
859 usbdk_get_device_descriptor,
860 usbdk_get_active_config_descriptor,
861 usbdk_get_config_descriptor,
864 usbdk_get_configuration,
865 usbdk_set_configuration,
866 usbdk_claim_interface,
867 usbdk_release_interface,
869 usbdk_set_interface_altsetting,
876 NULL, // dev_mem_alloc()
877 NULL, // dev_mem_free()
879 usbdk_kernel_driver_active,
880 usbdk_detach_kernel_driver,
881 usbdk_attach_kernel_driver,
883 usbdk_destroy_device,
885 usbdk_submit_transfer,
886 usbdk_cancel_transfer,
887 windows_clear_transfer_priv,
889 windows_handle_events,
893 #if defined(USBI_TIMERFD_AVAILABLE)
896 sizeof(struct usbdk_device_priv),
898 sizeof(struct usbdk_transfer_priv),
901 #endif /* USE_USBDK */