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
30 #include "windows_common.h"
31 #include "windows_usbdk.h"
33 #if !defined(STATUS_SUCCESS)
34 typedef LONG NTSTATUS;
35 #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
38 #if !defined(STATUS_CANCELLED)
39 #define STATUS_CANCELLED ((NTSTATUS)0xC0000120L)
42 #if !defined(STATUS_REQUEST_CANCELED)
43 #define STATUS_REQUEST_CANCELED ((NTSTATUS)0xC0000703L)
46 static inline struct usbdk_device_priv *_usbdk_device_priv(struct libusb_device *dev)
48 return (struct usbdk_device_priv *)dev->os_priv;
51 static inline struct usbdk_transfer_priv *_usbdk_transfer_priv(struct usbi_transfer *itransfer)
53 return (struct usbdk_transfer_priv *)usbi_transfer_get_os_priv(itransfer);
59 USBDK_GET_DEVICES_LIST GetDevicesList;
60 USBDK_RELEASE_DEVICES_LIST ReleaseDevicesList;
61 USBDK_START_REDIRECT StartRedirect;
62 USBDK_STOP_REDIRECT StopRedirect;
63 USBDK_GET_CONFIGURATION_DESCRIPTOR GetConfigurationDescriptor;
64 USBDK_RELEASE_CONFIGURATION_DESCRIPTOR ReleaseConfigurationDescriptor;
65 USBDK_READ_PIPE ReadPipe;
66 USBDK_WRITE_PIPE WritePipe;
67 USBDK_ABORT_PIPE AbortPipe;
68 USBDK_RESET_PIPE ResetPipe;
69 USBDK_SET_ALTSETTING SetAltsetting;
70 USBDK_RESET_DEVICE ResetDevice;
71 USBDK_GET_REDIRECTOR_SYSTEM_HANDLE GetRedirectorSystemHandle;
74 static FARPROC get_usbdk_proc_addr(struct libusb_context *ctx, LPCSTR api_name)
76 FARPROC api_ptr = GetProcAddress(usbdk_helper.module, api_name);
79 usbi_err(ctx, "UsbDkHelper API %s not found: %s", api_name, windows_error_str(0));
84 static void unload_usbdk_helper_dll(void)
86 if (usbdk_helper.module != NULL) {
87 FreeLibrary(usbdk_helper.module);
88 usbdk_helper.module = NULL;
92 static int load_usbdk_helper_dll(struct libusb_context *ctx)
94 usbdk_helper.module = LoadLibraryA("UsbDkHelper");
95 if (usbdk_helper.module == NULL) {
96 usbi_err(ctx, "Failed to load UsbDkHelper.dll: %s", windows_error_str(0));
97 return LIBUSB_ERROR_NOT_FOUND;
100 usbdk_helper.GetDevicesList = (USBDK_GET_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_GetDevicesList");
101 if (usbdk_helper.GetDevicesList == NULL)
104 usbdk_helper.ReleaseDevicesList = (USBDK_RELEASE_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseDevicesList");
105 if (usbdk_helper.ReleaseDevicesList == NULL)
108 usbdk_helper.StartRedirect = (USBDK_START_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StartRedirect");
109 if (usbdk_helper.StartRedirect == NULL)
112 usbdk_helper.StopRedirect = (USBDK_STOP_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StopRedirect");
113 if (usbdk_helper.StopRedirect == NULL)
116 usbdk_helper.GetConfigurationDescriptor = (USBDK_GET_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_GetConfigurationDescriptor");
117 if (usbdk_helper.GetConfigurationDescriptor == NULL)
120 usbdk_helper.ReleaseConfigurationDescriptor = (USBDK_RELEASE_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseConfigurationDescriptor");
121 if (usbdk_helper.ReleaseConfigurationDescriptor == NULL)
124 usbdk_helper.ReadPipe = (USBDK_READ_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ReadPipe");
125 if (usbdk_helper.ReadPipe == NULL)
128 usbdk_helper.WritePipe = (USBDK_WRITE_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_WritePipe");
129 if (usbdk_helper.WritePipe == NULL)
132 usbdk_helper.AbortPipe = (USBDK_ABORT_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_AbortPipe");
133 if (usbdk_helper.AbortPipe == NULL)
136 usbdk_helper.ResetPipe = (USBDK_RESET_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ResetPipe");
137 if (usbdk_helper.ResetPipe == NULL)
140 usbdk_helper.SetAltsetting = (USBDK_SET_ALTSETTING)get_usbdk_proc_addr(ctx, "UsbDk_SetAltsetting");
141 if (usbdk_helper.SetAltsetting == NULL)
144 usbdk_helper.ResetDevice = (USBDK_RESET_DEVICE)get_usbdk_proc_addr(ctx, "UsbDk_ResetDevice");
145 if (usbdk_helper.ResetDevice == NULL)
148 usbdk_helper.GetRedirectorSystemHandle = (USBDK_GET_REDIRECTOR_SYSTEM_HANDLE)get_usbdk_proc_addr(ctx, "UsbDk_GetRedirectorSystemHandle");
149 if (usbdk_helper.GetRedirectorSystemHandle == NULL)
152 return LIBUSB_SUCCESS;
155 FreeLibrary(usbdk_helper.module);
156 usbdk_helper.module = NULL;
157 return LIBUSB_ERROR_NOT_FOUND;
160 typedef SC_HANDLE (WINAPI *POPENSCMANAGERA)(LPCSTR, LPCSTR, DWORD);
161 typedef SC_HANDLE (WINAPI *POPENSERVICEA)(SC_HANDLE, LPCSTR, DWORD);
162 typedef BOOL (WINAPI *PCLOSESERVICEHANDLE)(SC_HANDLE);
164 static int usbdk_init(struct libusb_context *ctx)
166 POPENSCMANAGERA pOpenSCManagerA;
167 POPENSERVICEA pOpenServiceA;
168 PCLOSESERVICEHANDLE pCloseServiceHandle;
169 SC_HANDLE managerHandle;
170 SC_HANDLE serviceHandle;
173 h = LoadLibraryA("Advapi32");
175 usbi_warn(ctx, "failed to open Advapi32\n");
176 return LIBUSB_ERROR_OTHER;
179 pOpenSCManagerA = (POPENSCMANAGERA)GetProcAddress(h, "OpenSCManagerA");
180 if (pOpenSCManagerA == NULL) {
181 usbi_warn(ctx, "failed to find %s in Advapi32\n", "OpenSCManagerA");
182 goto error_free_library;
184 pOpenServiceA = (POPENSERVICEA)GetProcAddress(h, "OpenServiceA");
185 if (pOpenServiceA == NULL) {
186 usbi_warn(ctx, "failed to find %s in Advapi32\n", "OpenServiceA");
187 goto error_free_library;
189 pCloseServiceHandle = (PCLOSESERVICEHANDLE)GetProcAddress(h, "CloseServiceHandle");
190 if (pCloseServiceHandle == NULL) {
191 usbi_warn(ctx, "failed to find %s in Advapi32\n", "CloseServiceHandle");
192 goto error_free_library;
195 managerHandle = pOpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
196 if (managerHandle == NULL) {
197 usbi_warn(ctx, "failed to open service control manager: %s", windows_error_str(0));
198 goto error_free_library;
201 serviceHandle = pOpenServiceA(managerHandle, "UsbDk", GENERIC_READ);
202 pCloseServiceHandle(managerHandle);
204 if (serviceHandle == NULL) {
205 if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
206 usbi_warn(ctx, "failed to open UsbDk service: %s", windows_error_str(0));
208 return LIBUSB_ERROR_NOT_FOUND;
211 pCloseServiceHandle(serviceHandle);
214 return load_usbdk_helper_dll(ctx);
218 return LIBUSB_ERROR_OTHER;
221 static void usbdk_exit(struct libusb_context *ctx)
224 unload_usbdk_helper_dll();
227 static int usbdk_get_session_id_for_device(struct libusb_context *ctx,
228 PUSB_DK_DEVICE_ID id, unsigned long *session_id)
230 char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID) + 1];
232 if (snprintf(dev_identity, sizeof(dev_identity), "%S%S", id->DeviceID, id->InstanceID) == -1) {
233 usbi_warn(ctx, "cannot form device identity");
234 return LIBUSB_ERROR_NOT_SUPPORTED;
237 *session_id = htab_hash(dev_identity);
239 return LIBUSB_SUCCESS;
242 static void usbdk_release_config_descriptors(struct usbdk_device_priv *p, uint8_t count)
246 for (i = 0; i < count; i++)
247 usbdk_helper.ReleaseConfigurationDescriptor(p->config_descriptors[i]);
249 free(p->config_descriptors);
250 p->config_descriptors = NULL;
253 static int usbdk_cache_config_descriptors(struct libusb_context *ctx,
254 struct usbdk_device_priv *p, PUSB_DK_DEVICE_INFO info)
257 USB_DK_CONFIG_DESCRIPTOR_REQUEST Request;
258 Request.ID = info->ID;
260 p->config_descriptors = calloc(info->DeviceDescriptor.bNumConfigurations, sizeof(PUSB_CONFIGURATION_DESCRIPTOR));
261 if (p->config_descriptors == NULL) {
262 usbi_err(ctx, "failed to allocate configuration descriptors holder");
263 return LIBUSB_ERROR_NO_MEM;
266 for (i = 0; i < info->DeviceDescriptor.bNumConfigurations; i++) {
270 if (!usbdk_helper.GetConfigurationDescriptor(&Request, &p->config_descriptors[i], &Length)) {
271 usbi_err(ctx, "failed to retrieve configuration descriptors");
272 usbdk_release_config_descriptors(p, i);
273 return LIBUSB_ERROR_OTHER;
277 return LIBUSB_SUCCESS;
280 static inline int usbdk_device_priv_init(struct libusb_context *ctx, struct libusb_device *dev, PUSB_DK_DEVICE_INFO info)
282 struct usbdk_device_priv *p = _usbdk_device_priv(dev);
285 p->active_configuration = 0;
287 return usbdk_cache_config_descriptors(ctx, p, info);
290 static void usbdk_device_init(libusb_device *dev, PUSB_DK_DEVICE_INFO info)
292 dev->bus_number = (uint8_t)info->FilterID;
293 dev->port_number = (uint8_t)info->Port;
294 dev->parent_dev = NULL;
296 // Addresses in libusb are 1-based
297 dev->device_address = (uint8_t)(info->Port + 1);
299 dev->num_configurations = info->DeviceDescriptor.bNumConfigurations;
300 memcpy(&dev->device_descriptor, &info->DeviceDescriptor, LIBUSB_DT_DEVICE_SIZE);
302 switch (info->Speed) {
304 dev->speed = LIBUSB_SPEED_LOW;
307 dev->speed = LIBUSB_SPEED_FULL;
310 dev->speed = LIBUSB_SPEED_HIGH;
313 dev->speed = LIBUSB_SPEED_SUPER;
317 dev->speed = LIBUSB_SPEED_UNKNOWN;
322 static int usbdk_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
324 int r = LIBUSB_SUCCESS;
326 struct discovered_devs *discdevs = NULL;
328 PUSB_DK_DEVICE_INFO devices;
330 if (!usbdk_helper.GetDevicesList(&devices, &dev_number))
331 return LIBUSB_ERROR_OTHER;
333 for (i = 0; i < dev_number; i++) {
334 unsigned long session_id;
335 struct libusb_device *dev = NULL;
337 if (usbdk_get_session_id_for_device(ctx, &devices[i].ID, &session_id))
340 dev = usbi_get_device_by_session_id(ctx, session_id);
342 dev = usbi_alloc_device(ctx, session_id);
344 usbi_err(ctx, "failed to allocate a new device structure");
348 usbdk_device_init(dev, &devices[i]);
349 if (usbdk_device_priv_init(ctx, dev, &devices[i]) != LIBUSB_SUCCESS) {
350 libusb_unref_device(dev);
355 discdevs = discovered_devs_append(*_discdevs, dev);
356 libusb_unref_device(dev);
358 usbi_err(ctx, "cannot append new device to list");
359 r = LIBUSB_ERROR_NO_MEM;
363 *_discdevs = discdevs;
367 usbdk_helper.ReleaseDevicesList(devices);
371 static int usbdk_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer)
373 struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
375 memcpy(buffer, &priv->info.DeviceDescriptor, DEVICE_DESC_LENGTH);
377 return LIBUSB_SUCCESS;
380 static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len)
382 struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
383 PUSB_CONFIGURATION_DESCRIPTOR config_header;
386 if (config_index >= dev->num_configurations)
387 return LIBUSB_ERROR_INVALID_PARAM;
389 config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptors[config_index];
391 size = min(config_header->wTotalLength, len);
392 memcpy(buffer, config_header, size);
396 static int usbdk_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue,
397 unsigned char **buffer)
399 struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
400 PUSB_CONFIGURATION_DESCRIPTOR config_header;
403 for (index = 0; index < dev->num_configurations; index++) {
404 config_header = priv->config_descriptors[index];
405 if (config_header->bConfigurationValue == bConfigurationValue) {
406 *buffer = (unsigned char *)priv->config_descriptors[index];
407 return (int)config_header->wTotalLength;
411 return LIBUSB_ERROR_NOT_FOUND;
414 static int usbdk_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len)
416 return usbdk_get_config_descriptor(dev, _usbdk_device_priv(dev)->active_configuration,
420 static int usbdk_open(struct libusb_device_handle *dev_handle)
422 struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
424 priv->redirector_handle = usbdk_helper.StartRedirect(&priv->info.ID);
425 if (priv->redirector_handle == INVALID_HANDLE_VALUE) {
426 usbi_err(DEVICE_CTX(dev_handle->dev), "Redirector startup failed");
427 return LIBUSB_ERROR_OTHER;
430 priv->system_handle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
432 return LIBUSB_SUCCESS;
435 static void usbdk_close(struct libusb_device_handle *dev_handle)
437 struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
439 if (!usbdk_helper.StopRedirect(priv->redirector_handle))
440 usbi_err(HANDLE_CTX(dev_handle), "Redirector shutdown failed");
443 static int usbdk_get_configuration(struct libusb_device_handle *dev_handle, int *config)
445 *config = _usbdk_device_priv(dev_handle->dev)->active_configuration;
447 return LIBUSB_SUCCESS;
450 static int usbdk_set_configuration(struct libusb_device_handle *dev_handle, int config)
454 return LIBUSB_SUCCESS;
457 static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, int iface)
461 return LIBUSB_SUCCESS;
464 static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
466 struct libusb_context *ctx = HANDLE_CTX(dev_handle);
467 struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
469 if (!usbdk_helper.SetAltsetting(priv->redirector_handle, iface, altsetting)) {
470 usbi_err(ctx, "SetAltsetting failed: %s", windows_error_str(0));
471 return LIBUSB_ERROR_NO_DEVICE;
474 return LIBUSB_SUCCESS;
477 static int usbdk_release_interface(struct libusb_device_handle *dev_handle, int iface)
481 return LIBUSB_SUCCESS;
484 static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
486 struct libusb_context *ctx = HANDLE_CTX(dev_handle);
487 struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
489 if (!usbdk_helper.ResetPipe(priv->redirector_handle, endpoint)) {
490 usbi_err(ctx, "ResetPipe failed: %s", windows_error_str(0));
491 return LIBUSB_ERROR_NO_DEVICE;
494 return LIBUSB_SUCCESS;
497 static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
499 struct libusb_context *ctx = HANDLE_CTX(dev_handle);
500 struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
502 if (!usbdk_helper.ResetDevice(priv->redirector_handle)) {
503 usbi_err(ctx, "ResetDevice failed: %s", windows_error_str(0));
504 return LIBUSB_ERROR_NO_DEVICE;
507 return LIBUSB_SUCCESS;
510 static void usbdk_destroy_device(struct libusb_device *dev)
512 struct usbdk_device_priv* p = _usbdk_device_priv(dev);
514 if (p->config_descriptors != NULL)
515 usbdk_release_config_descriptors(p, p->info.DeviceDescriptor.bNumConfigurations);
518 static void usbdk_clear_transfer_priv(struct usbi_transfer *itransfer)
520 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
521 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
523 usbi_close(transfer_priv->pollable_fd.fd);
524 transfer_priv->pollable_fd = INVALID_WINFD;
525 transfer_priv->system_handle = NULL;
527 if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
528 safe_free(transfer_priv->IsochronousPacketsArray);
529 safe_free(transfer_priv->IsochronousResultsArray);
533 static int usbdk_do_control_transfer(struct usbi_transfer *itransfer)
535 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
536 struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
537 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
538 struct libusb_context *ctx = TRANSFER_CTX(transfer);
539 OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
540 TransferResult transResult;
542 transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
543 transfer_priv->request.BufferLength = transfer->length;
544 transfer_priv->request.TransferType = ControlTransferType;
546 if (transfer->buffer[0] & LIBUSB_ENDPOINT_IN)
547 transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
549 transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
551 switch (transResult) {
552 case TransferSuccess:
553 windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
555 case TransferSuccessAsync:
557 case TransferFailure:
558 usbi_err(ctx, "ControlTransfer failed: %s", windows_error_str(0));
559 return LIBUSB_ERROR_IO;
562 return LIBUSB_SUCCESS;
565 static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
567 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
568 struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
569 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
570 struct libusb_context *ctx = TRANSFER_CTX(transfer);
571 OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
572 TransferResult transferRes;
574 transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
575 transfer_priv->request.BufferLength = transfer->length;
576 transfer_priv->request.EndpointAddress = transfer->endpoint;
578 switch (transfer->type) {
579 case LIBUSB_TRANSFER_TYPE_BULK:
580 transfer_priv->request.TransferType = BulkTransferType;
582 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
583 transfer_priv->request.TransferType = InterruptTransferType;
586 usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer", transfer->type);
587 return LIBUSB_ERROR_INVALID_PARAM;
590 if (IS_XFERIN(transfer))
591 transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
593 transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
595 switch (transferRes) {
596 case TransferSuccess:
597 windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
599 case TransferSuccessAsync:
601 case TransferFailure:
602 usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
603 return LIBUSB_ERROR_IO;
606 return LIBUSB_SUCCESS;
609 static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
611 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
612 struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
613 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
614 struct libusb_context *ctx = TRANSFER_CTX(transfer);
615 OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
616 TransferResult transferRes;
619 transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
620 transfer_priv->request.BufferLength = transfer->length;
621 transfer_priv->request.EndpointAddress = transfer->endpoint;
622 transfer_priv->request.TransferType = IsochronousTransferType;
623 transfer_priv->request.IsochronousPacketsArraySize = transfer->num_iso_packets;
624 transfer_priv->IsochronousPacketsArray = malloc(transfer->num_iso_packets * sizeof(ULONG64));
625 transfer_priv->request.IsochronousPacketsArray = (PVOID64)transfer_priv->IsochronousPacketsArray;
626 if (!transfer_priv->IsochronousPacketsArray) {
627 usbi_err(ctx, "Allocation of IsochronousPacketsArray failed");
628 return LIBUSB_ERROR_NO_MEM;
631 transfer_priv->IsochronousResultsArray = malloc(transfer->num_iso_packets * sizeof(USB_DK_ISO_TRANSFER_RESULT));
632 transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)transfer_priv->IsochronousResultsArray;
633 if (!transfer_priv->IsochronousResultsArray) {
634 usbi_err(ctx, "Allocation of isochronousResultsArray failed");
635 return LIBUSB_ERROR_NO_MEM;
638 for (i = 0; i < transfer->num_iso_packets; i++)
639 transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length;
641 if (IS_XFERIN(transfer))
642 transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
644 transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
646 switch (transferRes) {
647 case TransferSuccess:
648 windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
650 case TransferSuccessAsync:
652 case TransferFailure:
653 return LIBUSB_ERROR_IO;
656 return LIBUSB_SUCCESS;
659 static int usbdk_do_submit_transfer(struct usbi_transfer *itransfer,
660 short events, int (*transfer_fn)(struct usbi_transfer *))
662 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
663 struct libusb_context *ctx = TRANSFER_CTX(transfer);
664 struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
665 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
669 wfd = usbi_create_fd();
671 return LIBUSB_ERROR_NO_MEM;
673 r = usbi_add_pollfd(ctx, wfd.fd, events);
679 // Use transfer_priv to store data needed for async polling
680 transfer_priv->pollable_fd = wfd;
681 transfer_priv->system_handle = priv->system_handle;
683 r = transfer_fn(itransfer);
684 if (r != LIBUSB_SUCCESS) {
685 usbi_remove_pollfd(ctx, wfd.fd);
686 usbdk_clear_transfer_priv(itransfer);
690 return LIBUSB_SUCCESS;
693 static int usbdk_submit_transfer(struct usbi_transfer *itransfer)
695 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
696 int (*transfer_fn)(struct usbi_transfer *);
699 switch (transfer->type) {
700 case LIBUSB_TRANSFER_TYPE_CONTROL:
701 events = (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) ? POLLIN : POLLOUT;
702 transfer_fn = usbdk_do_control_transfer;
704 case LIBUSB_TRANSFER_TYPE_BULK:
705 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
706 if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
707 return LIBUSB_ERROR_NOT_SUPPORTED; //TODO: Check whether we can support this in UsbDk
708 events = IS_XFERIN(transfer) ? POLLIN : POLLOUT;
709 transfer_fn = usbdk_do_bulk_transfer;
711 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
712 events = IS_XFERIN(transfer) ? POLLIN : POLLOUT;
713 transfer_fn = usbdk_do_iso_transfer;
716 usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
717 return LIBUSB_ERROR_INVALID_PARAM;
720 return usbdk_do_submit_transfer(itransfer, events, transfer_fn);
723 static int usbdk_abort_transfers(struct usbi_transfer *itransfer)
725 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
726 struct libusb_context *ctx = TRANSFER_CTX(transfer);
727 struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
728 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
729 struct winfd *pollable_fd = &transfer_priv->pollable_fd;
731 // Use CancelIoEx to cancel just a single transfer
732 if (CancelIoEx(priv->system_handle, pollable_fd->overlapped))
733 return LIBUSB_SUCCESS;
735 usbi_warn(ctx, "CancelIoEx failed: %s", windows_error_str(0));
736 return LIBUSB_ERROR_NOT_FOUND;
739 static int usbdk_cancel_transfer(struct usbi_transfer *itransfer)
741 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
743 switch (transfer->type) {
744 case LIBUSB_TRANSFER_TYPE_CONTROL:
745 // Control transfers cancelled by IoCancelXXX() API
746 // No special treatment needed
747 return LIBUSB_SUCCESS;
748 case LIBUSB_TRANSFER_TYPE_BULK:
749 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
750 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
751 return usbdk_abort_transfers(itransfer);
753 usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
754 return LIBUSB_ERROR_INVALID_PARAM;
758 static int usbdk_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
760 itransfer->transferred += io_size;
761 return LIBUSB_TRANSFER_COMPLETED;
764 static int usbdk_get_transfer_fd(struct usbi_transfer *itransfer)
766 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
767 return transfer_priv->pollable_fd.fd;
770 static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus)
772 if (USBD_SUCCESS(UsbdStatus))
775 switch (UsbdStatus) {
776 case USBD_STATUS_TIMEOUT:
777 return ERROR_SEM_TIMEOUT;
778 case USBD_STATUS_CANCELED:
779 return ERROR_OPERATION_ABORTED;
781 return ERROR_GEN_FAILURE;
785 static void usbdk_get_overlapped_result(struct usbi_transfer *itransfer, DWORD *io_result, DWORD *io_size)
787 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
788 struct winfd *pollable_fd = &transfer_priv->pollable_fd;
790 if (HasOverlappedIoCompletedSync(pollable_fd->overlapped) // Handle async requests that completed synchronously first
791 || GetOverlappedResult(transfer_priv->system_handle, pollable_fd->overlapped, io_size, FALSE)) { // Regular async overlapped
792 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
794 if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
796 for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) {
797 struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i];
799 switch (transfer_priv->IsochronousResultsArray[i].TransferResult) {
801 case STATUS_CANCELLED:
802 case STATUS_REQUEST_CANCELED:
803 lib_desc->status = LIBUSB_TRANSFER_COMPLETED; // == ERROR_SUCCESS
806 lib_desc->status = LIBUSB_TRANSFER_ERROR; // ERROR_UNKNOWN_EXCEPTION;
810 lib_desc->actual_length = (unsigned int)transfer_priv->IsochronousResultsArray[i].ActualLength;
814 *io_size = (DWORD)transfer_priv->request.Result.GenResult.BytesTransferred;
815 *io_result = usbdk_translate_usbd_status((USBD_STATUS)transfer_priv->request.Result.GenResult.UsbdStatus);
817 *io_result = GetLastError();
821 const struct windows_backend usbdk_backend = {
824 usbdk_get_device_list,
827 usbdk_get_device_descriptor,
828 usbdk_get_active_config_descriptor,
829 usbdk_get_config_descriptor,
830 usbdk_get_config_descriptor_by_value,
831 usbdk_get_configuration,
832 usbdk_set_configuration,
833 usbdk_claim_interface,
834 usbdk_release_interface,
835 usbdk_set_interface_altsetting,
838 usbdk_destroy_device,
839 usbdk_submit_transfer,
840 usbdk_cancel_transfer,
841 usbdk_clear_transfer_priv,
842 usbdk_copy_transfer_data,
843 usbdk_get_transfer_fd,
844 usbdk_get_overlapped_result,