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_nt_common.h"
32 #include "windows_usbdk.h"
34 #if !defined(STATUS_SUCCESS)
35 typedef LONG NTSTATUS;
36 #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
39 #if !defined(STATUS_CANCELLED)
40 #define STATUS_CANCELLED ((NTSTATUS)0xC0000120L)
43 #if !defined(STATUS_REQUEST_CANCELED)
44 #define STATUS_REQUEST_CANCELED ((NTSTATUS)0xC0000703L)
47 #if !defined(USBD_SUCCESS)
48 typedef LONG USBD_STATUS;
49 #define USBD_SUCCESS(Status) ((USBD_STATUS) (Status) >= 0)
50 #define USBD_PENDING(Status) ((ULONG) (Status) >> 30 == 1)
51 #define USBD_ERROR(Status) ((USBD_STATUS) (Status) < 0)
52 #define USBD_STATUS_STALL_PID ((USBD_STATUS) 0xc0000004)
53 #define USBD_STATUS_ENDPOINT_HALTED ((USBD_STATUS) 0xc0000030)
54 #define USBD_STATUS_BAD_START_FRAME ((USBD_STATUS) 0xc0000a00)
55 #define USBD_STATUS_TIMEOUT ((USBD_STATUS) 0xc0006000)
56 #define USBD_STATUS_CANCELED ((USBD_STATUS) 0xc0010000)
59 static inline struct usbdk_device_priv *_usbdk_device_priv(struct libusb_device *dev)
61 return (struct usbdk_device_priv *)dev->os_priv;
64 static inline struct usbdk_transfer_priv *_usbdk_transfer_priv(struct usbi_transfer *itransfer)
66 return (struct usbdk_transfer_priv *)usbi_transfer_get_os_priv(itransfer);
72 USBDK_GET_DEVICES_LIST GetDevicesList;
73 USBDK_RELEASE_DEVICES_LIST ReleaseDevicesList;
74 USBDK_START_REDIRECT StartRedirect;
75 USBDK_STOP_REDIRECT StopRedirect;
76 USBDK_GET_CONFIGURATION_DESCRIPTOR GetConfigurationDescriptor;
77 USBDK_RELEASE_CONFIGURATION_DESCRIPTOR ReleaseConfigurationDescriptor;
78 USBDK_READ_PIPE ReadPipe;
79 USBDK_WRITE_PIPE WritePipe;
80 USBDK_ABORT_PIPE AbortPipe;
81 USBDK_RESET_PIPE ResetPipe;
82 USBDK_SET_ALTSETTING SetAltsetting;
83 USBDK_RESET_DEVICE ResetDevice;
84 USBDK_GET_REDIRECTOR_SYSTEM_HANDLE GetRedirectorSystemHandle;
87 static FARPROC get_usbdk_proc_addr(struct libusb_context *ctx, LPCSTR api_name)
89 FARPROC api_ptr = GetProcAddress(usbdk_helper.module, api_name);
92 usbi_err(ctx, "UsbDkHelper API %s not found: %s", api_name, windows_error_str(0));
97 static void unload_usbdk_helper_dll(void)
99 if (usbdk_helper.module != NULL) {
100 FreeLibrary(usbdk_helper.module);
101 usbdk_helper.module = NULL;
105 static int load_usbdk_helper_dll(struct libusb_context *ctx)
107 usbdk_helper.module = LoadLibraryA("UsbDkHelper");
108 if (usbdk_helper.module == NULL) {
109 usbi_err(ctx, "Failed to load UsbDkHelper.dll: %s", windows_error_str(0));
110 return LIBUSB_ERROR_NOT_FOUND;
113 usbdk_helper.GetDevicesList = (USBDK_GET_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_GetDevicesList");
114 if (usbdk_helper.GetDevicesList == NULL)
117 usbdk_helper.ReleaseDevicesList = (USBDK_RELEASE_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseDevicesList");
118 if (usbdk_helper.ReleaseDevicesList == NULL)
121 usbdk_helper.StartRedirect = (USBDK_START_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StartRedirect");
122 if (usbdk_helper.StartRedirect == NULL)
125 usbdk_helper.StopRedirect = (USBDK_STOP_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StopRedirect");
126 if (usbdk_helper.StopRedirect == NULL)
129 usbdk_helper.GetConfigurationDescriptor = (USBDK_GET_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_GetConfigurationDescriptor");
130 if (usbdk_helper.GetConfigurationDescriptor == NULL)
133 usbdk_helper.ReleaseConfigurationDescriptor = (USBDK_RELEASE_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseConfigurationDescriptor");
134 if (usbdk_helper.ReleaseConfigurationDescriptor == NULL)
137 usbdk_helper.ReadPipe = (USBDK_READ_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ReadPipe");
138 if (usbdk_helper.ReadPipe == NULL)
141 usbdk_helper.WritePipe = (USBDK_WRITE_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_WritePipe");
142 if (usbdk_helper.WritePipe == NULL)
145 usbdk_helper.AbortPipe = (USBDK_ABORT_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_AbortPipe");
146 if (usbdk_helper.AbortPipe == NULL)
149 usbdk_helper.ResetPipe = (USBDK_RESET_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ResetPipe");
150 if (usbdk_helper.ResetPipe == NULL)
153 usbdk_helper.SetAltsetting = (USBDK_SET_ALTSETTING)get_usbdk_proc_addr(ctx, "UsbDk_SetAltsetting");
154 if (usbdk_helper.SetAltsetting == NULL)
157 usbdk_helper.ResetDevice = (USBDK_RESET_DEVICE)get_usbdk_proc_addr(ctx, "UsbDk_ResetDevice");
158 if (usbdk_helper.ResetDevice == NULL)
161 usbdk_helper.GetRedirectorSystemHandle = (USBDK_GET_REDIRECTOR_SYSTEM_HANDLE)get_usbdk_proc_addr(ctx, "UsbDk_GetRedirectorSystemHandle");
162 if (usbdk_helper.GetRedirectorSystemHandle == NULL)
165 return LIBUSB_SUCCESS;
168 FreeLibrary(usbdk_helper.module);
169 usbdk_helper.module = NULL;
170 return LIBUSB_ERROR_NOT_FOUND;
173 static int usbdk_init(struct libusb_context *ctx)
175 SC_HANDLE managerHandle;
176 SC_HANDLE serviceHandle;
178 managerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
179 if (managerHandle == NULL) {
180 usbi_warn(ctx, "failed to open service control manager: %s", windows_error_str(0));
181 return LIBUSB_ERROR_OTHER;
184 serviceHandle = OpenServiceA(managerHandle, "UsbDk", GENERIC_READ);
185 CloseServiceHandle(managerHandle);
187 if (serviceHandle == NULL) {
188 if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
189 usbi_warn(ctx, "failed to open UsbDk service: %s", windows_error_str(0));
190 return LIBUSB_ERROR_NOT_FOUND;
193 CloseServiceHandle(serviceHandle);
195 return load_usbdk_helper_dll(ctx);
198 static void usbdk_exit(struct libusb_context *ctx)
201 unload_usbdk_helper_dll();
204 static int usbdk_get_session_id_for_device(struct libusb_context *ctx,
205 PUSB_DK_DEVICE_ID id, unsigned long *session_id)
207 char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID) + 1];
209 if (snprintf(dev_identity, sizeof(dev_identity), "%S%S", id->DeviceID, id->InstanceID) == -1) {
210 usbi_warn(ctx, "cannot form device identity", id->DeviceID);
211 return LIBUSB_ERROR_NOT_SUPPORTED;
214 *session_id = htab_hash(dev_identity);
216 return LIBUSB_SUCCESS;
219 static void usbdk_release_config_descriptors(struct usbdk_device_priv *p, uint8_t count)
223 for (i = 0; i < count; i++)
224 usbdk_helper.ReleaseConfigurationDescriptor(p->config_descriptors[i]);
226 free(p->config_descriptors);
227 p->config_descriptors = NULL;
230 static int usbdk_cache_config_descriptors(struct libusb_context *ctx,
231 struct usbdk_device_priv *p, PUSB_DK_DEVICE_INFO info)
234 USB_DK_CONFIG_DESCRIPTOR_REQUEST Request;
235 Request.ID = info->ID;
237 p->config_descriptors = calloc(info->DeviceDescriptor.bNumConfigurations, sizeof(PUSB_CONFIGURATION_DESCRIPTOR));
238 if (p->config_descriptors == NULL) {
239 usbi_err(ctx, "failed to allocate configuration descriptors holder");
240 return LIBUSB_ERROR_NO_MEM;
243 for (i = 0; i < info->DeviceDescriptor.bNumConfigurations; i++) {
247 if (!usbdk_helper.GetConfigurationDescriptor(&Request, &p->config_descriptors[i], &Length)) {
248 usbi_err(ctx, "failed to retrieve configuration descriptors");
249 usbdk_release_config_descriptors(p, i);
250 return LIBUSB_ERROR_OTHER;
254 return LIBUSB_SUCCESS;
257 static inline int usbdk_device_priv_init(struct libusb_context *ctx, struct libusb_device *dev, PUSB_DK_DEVICE_INFO info)
259 struct usbdk_device_priv *p = _usbdk_device_priv(dev);
262 p->active_configuration = 0;
264 return usbdk_cache_config_descriptors(ctx, p, info);
267 static void usbdk_device_init(libusb_device *dev, PUSB_DK_DEVICE_INFO info)
269 dev->bus_number = (uint8_t)info->FilterID;
270 dev->port_number = (uint8_t)info->Port;
271 dev->parent_dev = NULL;
273 // Addresses in libusb are 1-based
274 dev->device_address = (uint8_t)(info->Port + 1);
276 dev->num_configurations = info->DeviceDescriptor.bNumConfigurations;
277 memcpy(&dev->device_descriptor, &info->DeviceDescriptor, LIBUSB_DT_DEVICE_SIZE);
279 switch (info->Speed) {
281 dev->speed = LIBUSB_SPEED_LOW;
284 dev->speed = LIBUSB_SPEED_FULL;
287 dev->speed = LIBUSB_SPEED_HIGH;
290 dev->speed = LIBUSB_SPEED_SUPER;
294 dev->speed = LIBUSB_SPEED_UNKNOWN;
299 static int usbdk_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
301 int r = LIBUSB_SUCCESS;
303 struct discovered_devs *discdevs = NULL;
305 PUSB_DK_DEVICE_INFO devices;
307 if (!usbdk_helper.GetDevicesList(&devices, &dev_number))
308 return LIBUSB_ERROR_OTHER;
310 for (i = 0; i < dev_number; i++) {
311 unsigned long session_id;
312 struct libusb_device *dev = NULL;
314 if (usbdk_get_session_id_for_device(ctx, &devices[i].ID, &session_id))
317 dev = usbi_get_device_by_session_id(ctx, session_id);
319 dev = usbi_alloc_device(ctx, session_id);
321 usbi_err(ctx, "failed to allocate a new device structure");
325 usbdk_device_init(dev, &devices[i]);
326 if (usbdk_device_priv_init(ctx, dev, &devices[i]) != LIBUSB_SUCCESS) {
327 libusb_unref_device(dev);
332 discdevs = discovered_devs_append(*_discdevs, dev);
333 libusb_unref_device(dev);
335 usbi_err(ctx, "cannot append new device to list");
336 r = LIBUSB_ERROR_NO_MEM;
340 *_discdevs = discdevs;
344 usbdk_helper.ReleaseDevicesList(devices);
348 static int usbdk_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer)
350 struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
352 memcpy(buffer, &priv->info.DeviceDescriptor, DEVICE_DESC_LENGTH);
354 return LIBUSB_SUCCESS;
357 static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len)
359 struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
360 PUSB_CONFIGURATION_DESCRIPTOR config_header;
363 if (config_index >= dev->num_configurations)
364 return LIBUSB_ERROR_INVALID_PARAM;
366 config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptors[config_index];
368 size = min(config_header->wTotalLength, len);
369 memcpy(buffer, config_header, size);
373 static int usbdk_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue,
374 unsigned char **buffer)
376 struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
377 PUSB_CONFIGURATION_DESCRIPTOR config_header;
380 for (index = 0; index < dev->num_configurations; index++) {
381 config_header = priv->config_descriptors[index];
382 if (config_header->bConfigurationValue == bConfigurationValue) {
383 *buffer = (unsigned char *)priv->config_descriptors[index];
384 return (int)config_header->wTotalLength;
388 return LIBUSB_ERROR_NOT_FOUND;
391 static int usbdk_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len)
393 return usbdk_get_config_descriptor(dev, _usbdk_device_priv(dev)->active_configuration,
397 static int usbdk_open(struct libusb_device_handle *dev_handle)
399 struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
401 priv->redirector_handle = usbdk_helper.StartRedirect(&priv->info.ID);
402 if (priv->redirector_handle == INVALID_HANDLE_VALUE) {
403 usbi_err(DEVICE_CTX(dev_handle->dev), "Redirector startup failed");
404 return LIBUSB_ERROR_OTHER;
407 priv->system_handle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
409 return LIBUSB_SUCCESS;
412 static void usbdk_close(struct libusb_device_handle *dev_handle)
414 struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
416 if (!usbdk_helper.StopRedirect(priv->redirector_handle))
417 usbi_err(HANDLE_CTX(dev_handle), "Redirector shutdown failed");
420 static int usbdk_get_configuration(struct libusb_device_handle *dev_handle, int *config)
422 *config = _usbdk_device_priv(dev_handle->dev)->active_configuration;
424 return LIBUSB_SUCCESS;
427 static int usbdk_set_configuration(struct libusb_device_handle *dev_handle, int config)
431 return LIBUSB_SUCCESS;
434 static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, int iface)
438 return LIBUSB_SUCCESS;
441 static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
443 struct libusb_context *ctx = HANDLE_CTX(dev_handle);
444 struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
446 if (!usbdk_helper.SetAltsetting(priv->redirector_handle, iface, altsetting)) {
447 usbi_err(ctx, "SetAltsetting failed: %s", windows_error_str(0));
448 return LIBUSB_ERROR_NO_DEVICE;
451 return LIBUSB_SUCCESS;
454 static int usbdk_release_interface(struct libusb_device_handle *dev_handle, int iface)
458 return LIBUSB_SUCCESS;
461 static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
463 struct libusb_context *ctx = HANDLE_CTX(dev_handle);
464 struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
466 if (!usbdk_helper.ResetPipe(priv->redirector_handle, endpoint)) {
467 usbi_err(ctx, "ResetPipe failed: %s", windows_error_str(0));
468 return LIBUSB_ERROR_NO_DEVICE;
471 return LIBUSB_SUCCESS;
474 static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
476 struct libusb_context *ctx = HANDLE_CTX(dev_handle);
477 struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
479 if (!usbdk_helper.ResetDevice(priv->redirector_handle)) {
480 usbi_err(ctx, "ResetDevice failed: %s", windows_error_str(0));
481 return LIBUSB_ERROR_NO_DEVICE;
484 return LIBUSB_SUCCESS;
487 static void usbdk_destroy_device(struct libusb_device *dev)
489 struct usbdk_device_priv* p = _usbdk_device_priv(dev);
491 if (p->config_descriptors != NULL)
492 usbdk_release_config_descriptors(p, p->info.DeviceDescriptor.bNumConfigurations);
495 static void usbdk_clear_transfer_priv(struct usbi_transfer *itransfer)
497 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
498 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
500 usbi_close(transfer_priv->pollable_fd.fd);
501 transfer_priv->pollable_fd = INVALID_WINFD;
502 transfer_priv->system_handle = NULL;
504 if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
505 safe_free(transfer_priv->IsochronousPacketsArray);
506 safe_free(transfer_priv->IsochronousResultsArray);
510 static int usbdk_do_control_transfer(struct usbi_transfer *itransfer)
512 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
513 struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
514 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
515 struct libusb_context *ctx = TRANSFER_CTX(transfer);
516 OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
517 TransferResult transResult;
519 transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
520 transfer_priv->request.BufferLength = transfer->length;
521 transfer_priv->request.TransferType = ControlTransferType;
523 if (transfer->buffer[0] & LIBUSB_ENDPOINT_IN)
524 transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
526 transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
528 switch (transResult) {
529 case TransferSuccess:
530 windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
532 case TransferSuccessAsync:
534 case TransferFailure:
535 usbi_err(ctx, "ControlTransfer failed: %s", windows_error_str(0));
536 return LIBUSB_ERROR_IO;
539 return LIBUSB_SUCCESS;
542 static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
544 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
545 struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
546 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
547 struct libusb_context *ctx = TRANSFER_CTX(transfer);
548 OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
549 TransferResult transferRes;
551 transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
552 transfer_priv->request.BufferLength = transfer->length;
553 transfer_priv->request.EndpointAddress = transfer->endpoint;
555 switch (transfer->type) {
556 case LIBUSB_TRANSFER_TYPE_BULK:
557 transfer_priv->request.TransferType = BulkTransferType;
559 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
560 transfer_priv->request.TransferType = InterruptTransferType;
563 usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer", transfer->type);
564 return LIBUSB_ERROR_INVALID_PARAM;
567 if (IS_XFERIN(transfer))
568 transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
570 transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
572 switch (transferRes) {
573 case TransferSuccess:
574 windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
576 case TransferSuccessAsync:
578 case TransferFailure:
579 usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
580 return LIBUSB_ERROR_IO;
583 return LIBUSB_SUCCESS;
586 static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
588 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
589 struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
590 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
591 struct libusb_context *ctx = TRANSFER_CTX(transfer);
592 OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
593 TransferResult transferRes;
596 transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
597 transfer_priv->request.BufferLength = transfer->length;
598 transfer_priv->request.EndpointAddress = transfer->endpoint;
599 transfer_priv->request.TransferType = IsochronousTransferType;
600 transfer_priv->request.IsochronousPacketsArraySize = transfer->num_iso_packets;
601 transfer_priv->IsochronousPacketsArray = malloc(transfer->num_iso_packets * sizeof(ULONG64));
602 transfer_priv->request.IsochronousPacketsArray = (PVOID64)transfer_priv->IsochronousPacketsArray;
603 if (!transfer_priv->IsochronousPacketsArray) {
604 usbi_err(ctx, "Allocation of IsochronousPacketsArray failed");
605 return LIBUSB_ERROR_NO_MEM;
608 transfer_priv->IsochronousResultsArray = malloc(transfer->num_iso_packets * sizeof(USB_DK_ISO_TRANSFER_RESULT));
609 transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)transfer_priv->IsochronousResultsArray;
610 if (!transfer_priv->IsochronousResultsArray) {
611 usbi_err(ctx, "Allocation of isochronousResultsArray failed");
612 return LIBUSB_ERROR_NO_MEM;
615 for (i = 0; i < transfer->num_iso_packets; i++)
616 transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length;
618 if (IS_XFERIN(transfer))
619 transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
621 transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
623 switch (transferRes) {
624 case TransferSuccess:
625 windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
627 case TransferSuccessAsync:
629 case TransferFailure:
630 return LIBUSB_ERROR_IO;
633 return LIBUSB_SUCCESS;
636 static int usbdk_do_submit_transfer(struct usbi_transfer *itransfer,
637 short events, int (*transfer_fn)(struct usbi_transfer *))
639 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
640 struct libusb_context *ctx = TRANSFER_CTX(transfer);
641 struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
642 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
646 wfd = usbi_create_fd();
648 return LIBUSB_ERROR_NO_MEM;
650 r = usbi_add_pollfd(ctx, wfd.fd, events);
656 // Use transfer_priv to store data needed for async polling
657 transfer_priv->pollable_fd = wfd;
658 transfer_priv->system_handle = priv->system_handle;
660 r = transfer_fn(itransfer);
661 if (r != LIBUSB_SUCCESS) {
662 usbi_remove_pollfd(ctx, wfd.fd);
663 usbdk_clear_transfer_priv(itransfer);
667 return LIBUSB_SUCCESS;
670 static int usbdk_submit_transfer(struct usbi_transfer *itransfer)
672 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
673 int (*transfer_fn)(struct usbi_transfer *);
676 switch (transfer->type) {
677 case LIBUSB_TRANSFER_TYPE_CONTROL:
678 events = (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) ? POLLIN : POLLOUT;
679 transfer_fn = usbdk_do_control_transfer;
681 case LIBUSB_TRANSFER_TYPE_BULK:
682 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
683 if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
684 return LIBUSB_ERROR_NOT_SUPPORTED; //TODO: Check whether we can support this in UsbDk
685 events = IS_XFERIN(transfer) ? POLLIN : POLLOUT;
686 transfer_fn = usbdk_do_bulk_transfer;
688 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
689 events = IS_XFERIN(transfer) ? POLLIN : POLLOUT;
690 transfer_fn = usbdk_do_iso_transfer;
693 usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
694 return LIBUSB_ERROR_INVALID_PARAM;
697 return usbdk_do_submit_transfer(itransfer, events, transfer_fn);
700 static int usbdk_abort_transfers(struct usbi_transfer *itransfer)
702 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
703 struct libusb_context *ctx = TRANSFER_CTX(transfer);
704 struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
705 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
706 struct winfd *pollable_fd = &transfer_priv->pollable_fd;
708 if (pCancelIoEx != NULL) {
709 // Use CancelIoEx if available to cancel just a single transfer
710 if (!pCancelIoEx(priv->system_handle, pollable_fd->overlapped)) {
711 usbi_err(ctx, "CancelIoEx failed: %s", windows_error_str(0));
712 return LIBUSB_ERROR_NO_DEVICE;
715 if (!usbdk_helper.AbortPipe(priv->redirector_handle, transfer->endpoint)) {
716 usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0));
717 return LIBUSB_ERROR_NO_DEVICE;
721 return LIBUSB_SUCCESS;
724 static int usbdk_cancel_transfer(struct usbi_transfer *itransfer)
726 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
728 switch (transfer->type) {
729 case LIBUSB_TRANSFER_TYPE_CONTROL:
730 // Control transfers cancelled by IoCancelXXX() API
731 // No special treatment needed
732 return LIBUSB_SUCCESS;
733 case LIBUSB_TRANSFER_TYPE_BULK:
734 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
735 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
736 return usbdk_abort_transfers(itransfer);
738 usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
739 return LIBUSB_ERROR_INVALID_PARAM;
743 static int usbdk_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
745 itransfer->transferred += io_size;
746 return LIBUSB_TRANSFER_COMPLETED;
749 static int usbdk_get_transfer_fd(struct usbi_transfer *itransfer)
751 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
752 return transfer_priv->pollable_fd.fd;
755 static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus)
757 if (USBD_SUCCESS(UsbdStatus))
760 switch (UsbdStatus) {
761 case USBD_STATUS_TIMEOUT:
762 return ERROR_SEM_TIMEOUT;
763 case USBD_STATUS_CANCELED:
764 return ERROR_OPERATION_ABORTED;
766 return ERROR_GEN_FAILURE;
770 static void usbdk_get_overlapped_result(struct usbi_transfer *itransfer, DWORD *io_result, DWORD *io_size)
772 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
773 struct winfd *pollable_fd = &transfer_priv->pollable_fd;
775 if (HasOverlappedIoCompletedSync(pollable_fd->overlapped) // Handle async requests that completed synchronously first
776 || GetOverlappedResult(transfer_priv->system_handle, pollable_fd->overlapped, io_size, FALSE)) { // Regular async overlapped
777 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
779 if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
781 for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) {
782 struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i];
784 switch (transfer_priv->IsochronousResultsArray[i].TransferResult) {
786 case STATUS_CANCELLED:
787 case STATUS_REQUEST_CANCELED:
788 lib_desc->status = LIBUSB_TRANSFER_COMPLETED; // == ERROR_SUCCESS
791 lib_desc->status = LIBUSB_TRANSFER_ERROR; // ERROR_UNKNOWN_EXCEPTION;
795 lib_desc->actual_length = (unsigned int)transfer_priv->IsochronousResultsArray[i].ActualLength;
799 *io_size = (DWORD)transfer_priv->request.Result.GenResult.BytesTransferred;
800 *io_result = usbdk_translate_usbd_status((USBD_STATUS)transfer_priv->request.Result.GenResult.UsbdStatus);
802 *io_result = GetLastError();
806 const struct windows_backend usbdk_backend = {
809 usbdk_get_device_list,
812 usbdk_get_device_descriptor,
813 usbdk_get_active_config_descriptor,
814 usbdk_get_config_descriptor,
815 usbdk_get_config_descriptor_by_value,
816 usbdk_get_configuration,
817 usbdk_set_configuration,
818 usbdk_claim_interface,
819 usbdk_release_interface,
820 usbdk_set_interface_altsetting,
823 usbdk_destroy_device,
824 usbdk_submit_transfer,
825 usbdk_cancel_transfer,
826 usbdk_clear_transfer_priv,
827 usbdk_copy_transfer_data,
828 usbdk_get_transfer_fd,
829 usbdk_get_overlapped_result,