Add libusb and libuvc
[rtmpclient.git] / app / src / main / jni / libusb-1.0.22 / libusb / os / windows_usbdk.c
1 /*
2  * windows UsbDk backend for libusb 1.0
3  * Copyright © 2014 Red Hat, Inc.
4
5  * Authors:
6  * Dmitry Fleytman <dmitry@daynix.com>
7  * Pavel Gurvich <pavel@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 #include <windows.h>
27 #include <stdio.h>
28
29 #include "libusbi.h"
30 #include "windows_common.h"
31 #include "windows_nt_common.h"
32 #include "windows_usbdk.h"
33
34 #if !defined(STATUS_SUCCESS)
35 typedef LONG NTSTATUS;
36 #define STATUS_SUCCESS                  ((NTSTATUS)0x00000000L)
37 #endif
38
39 #if !defined(STATUS_CANCELLED)
40 #define STATUS_CANCELLED                ((NTSTATUS)0xC0000120L)
41 #endif
42
43 #if !defined(STATUS_REQUEST_CANCELED)
44 #define STATUS_REQUEST_CANCELED         ((NTSTATUS)0xC0000703L)
45 #endif
46
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)
57 #endif
58
59 static inline struct usbdk_device_priv *_usbdk_device_priv(struct libusb_device *dev)
60 {
61         return (struct usbdk_device_priv *)dev->os_priv;
62 }
63
64 static inline struct usbdk_transfer_priv *_usbdk_transfer_priv(struct usbi_transfer *itransfer)
65 {
66         return (struct usbdk_transfer_priv *)usbi_transfer_get_os_priv(itransfer);
67 }
68
69 static struct {
70         HMODULE module;
71
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;
85 } usbdk_helper;
86
87 static FARPROC get_usbdk_proc_addr(struct libusb_context *ctx, LPCSTR api_name)
88 {
89         FARPROC api_ptr = GetProcAddress(usbdk_helper.module, api_name);
90
91         if (api_ptr == NULL)
92                 usbi_err(ctx, "UsbDkHelper API %s not found: %s", api_name, windows_error_str(0));
93
94         return api_ptr;
95 }
96
97 static void unload_usbdk_helper_dll(void)
98 {
99         if (usbdk_helper.module != NULL) {
100                 FreeLibrary(usbdk_helper.module);
101                 usbdk_helper.module = NULL;
102         }
103 }
104
105 static int load_usbdk_helper_dll(struct libusb_context *ctx)
106 {
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;
111         }
112
113         usbdk_helper.GetDevicesList = (USBDK_GET_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_GetDevicesList");
114         if (usbdk_helper.GetDevicesList == NULL)
115                 goto error_unload;
116
117         usbdk_helper.ReleaseDevicesList = (USBDK_RELEASE_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseDevicesList");
118         if (usbdk_helper.ReleaseDevicesList == NULL)
119                 goto error_unload;
120
121         usbdk_helper.StartRedirect = (USBDK_START_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StartRedirect");
122         if (usbdk_helper.StartRedirect == NULL)
123                 goto error_unload;
124
125         usbdk_helper.StopRedirect = (USBDK_STOP_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StopRedirect");
126         if (usbdk_helper.StopRedirect == NULL)
127                 goto error_unload;
128
129         usbdk_helper.GetConfigurationDescriptor = (USBDK_GET_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_GetConfigurationDescriptor");
130         if (usbdk_helper.GetConfigurationDescriptor == NULL)
131                 goto error_unload;
132
133         usbdk_helper.ReleaseConfigurationDescriptor = (USBDK_RELEASE_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseConfigurationDescriptor");
134         if (usbdk_helper.ReleaseConfigurationDescriptor == NULL)
135                 goto error_unload;
136
137         usbdk_helper.ReadPipe = (USBDK_READ_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ReadPipe");
138         if (usbdk_helper.ReadPipe == NULL)
139                 goto error_unload;
140
141         usbdk_helper.WritePipe = (USBDK_WRITE_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_WritePipe");
142         if (usbdk_helper.WritePipe == NULL)
143                 goto error_unload;
144
145         usbdk_helper.AbortPipe = (USBDK_ABORT_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_AbortPipe");
146         if (usbdk_helper.AbortPipe == NULL)
147                 goto error_unload;
148
149         usbdk_helper.ResetPipe = (USBDK_RESET_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ResetPipe");
150         if (usbdk_helper.ResetPipe == NULL)
151                 goto error_unload;
152
153         usbdk_helper.SetAltsetting = (USBDK_SET_ALTSETTING)get_usbdk_proc_addr(ctx, "UsbDk_SetAltsetting");
154         if (usbdk_helper.SetAltsetting == NULL)
155                 goto error_unload;
156
157         usbdk_helper.ResetDevice = (USBDK_RESET_DEVICE)get_usbdk_proc_addr(ctx, "UsbDk_ResetDevice");
158         if (usbdk_helper.ResetDevice == NULL)
159                 goto error_unload;
160
161         usbdk_helper.GetRedirectorSystemHandle = (USBDK_GET_REDIRECTOR_SYSTEM_HANDLE)get_usbdk_proc_addr(ctx, "UsbDk_GetRedirectorSystemHandle");
162         if (usbdk_helper.GetRedirectorSystemHandle == NULL)
163                 goto error_unload;
164
165         return LIBUSB_SUCCESS;
166
167 error_unload:
168         FreeLibrary(usbdk_helper.module);
169         usbdk_helper.module = NULL;
170         return LIBUSB_ERROR_NOT_FOUND;
171 }
172
173 static int usbdk_init(struct libusb_context *ctx)
174 {
175         SC_HANDLE managerHandle;
176         SC_HANDLE serviceHandle;
177
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;
182         }
183
184         serviceHandle = OpenServiceA(managerHandle, "UsbDk", GENERIC_READ);
185         CloseServiceHandle(managerHandle);
186
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;
191         }
192
193         CloseServiceHandle(serviceHandle);
194
195         return load_usbdk_helper_dll(ctx);
196 }
197
198 static void usbdk_exit(struct libusb_context *ctx)
199 {
200         UNUSED(ctx);
201         unload_usbdk_helper_dll();
202 }
203
204 static int usbdk_get_session_id_for_device(struct libusb_context *ctx,
205         PUSB_DK_DEVICE_ID id, unsigned long *session_id)
206 {
207         char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID) + 1];
208
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;
212         }
213
214         *session_id = htab_hash(dev_identity);
215
216         return LIBUSB_SUCCESS;
217 }
218
219 static void usbdk_release_config_descriptors(struct usbdk_device_priv *p, uint8_t count)
220 {
221         uint8_t i;
222
223         for (i = 0; i < count; i++)
224                 usbdk_helper.ReleaseConfigurationDescriptor(p->config_descriptors[i]);
225
226         free(p->config_descriptors);
227         p->config_descriptors = NULL;
228 }
229
230 static int usbdk_cache_config_descriptors(struct libusb_context *ctx,
231         struct usbdk_device_priv *p, PUSB_DK_DEVICE_INFO info)
232 {
233         uint8_t i;
234         USB_DK_CONFIG_DESCRIPTOR_REQUEST Request;
235         Request.ID = info->ID;
236
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;
241         }
242
243         for (i = 0; i < info->DeviceDescriptor.bNumConfigurations; i++) {
244                 ULONG Length;
245
246                 Request.Index = 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;
251                 }
252         }
253
254         return LIBUSB_SUCCESS;
255 }
256
257 static inline int usbdk_device_priv_init(struct libusb_context *ctx, struct libusb_device *dev, PUSB_DK_DEVICE_INFO info)
258 {
259         struct usbdk_device_priv *p = _usbdk_device_priv(dev);
260
261         p->info = *info;
262         p->active_configuration = 0;
263
264         return usbdk_cache_config_descriptors(ctx, p, info);
265 }
266
267 static void usbdk_device_init(libusb_device *dev, PUSB_DK_DEVICE_INFO info)
268 {
269         dev->bus_number = (uint8_t)info->FilterID;
270         dev->port_number = (uint8_t)info->Port;
271         dev->parent_dev = NULL;
272
273         // Addresses in libusb are 1-based
274         dev->device_address = (uint8_t)(info->Port + 1);
275
276         dev->num_configurations = info->DeviceDescriptor.bNumConfigurations;
277         memcpy(&dev->device_descriptor, &info->DeviceDescriptor, LIBUSB_DT_DEVICE_SIZE);
278
279         switch (info->Speed) {
280         case LowSpeed:
281                 dev->speed = LIBUSB_SPEED_LOW;
282                 break;
283         case FullSpeed:
284                 dev->speed = LIBUSB_SPEED_FULL;
285                 break;
286         case HighSpeed:
287                 dev->speed = LIBUSB_SPEED_HIGH;
288                 break;
289         case SuperSpeed:
290                 dev->speed = LIBUSB_SPEED_SUPER;
291                 break;
292         case NoSpeed:
293         default:
294                 dev->speed = LIBUSB_SPEED_UNKNOWN;
295                 break;
296         }
297 }
298
299 static int usbdk_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
300 {
301         int r = LIBUSB_SUCCESS;
302         ULONG i;
303         struct discovered_devs *discdevs = NULL;
304         ULONG dev_number;
305         PUSB_DK_DEVICE_INFO devices;
306
307         if (!usbdk_helper.GetDevicesList(&devices, &dev_number))
308                 return LIBUSB_ERROR_OTHER;
309
310         for (i = 0; i < dev_number; i++) {
311                 unsigned long session_id;
312                 struct libusb_device *dev = NULL;
313
314                 if (usbdk_get_session_id_for_device(ctx, &devices[i].ID, &session_id))
315                         continue;
316
317                 dev = usbi_get_device_by_session_id(ctx, session_id);
318                 if (dev == NULL) {
319                         dev = usbi_alloc_device(ctx, session_id);
320                         if (dev == NULL) {
321                                 usbi_err(ctx, "failed to allocate a new device structure");
322                                 continue;
323                         }
324
325                         usbdk_device_init(dev, &devices[i]);
326                         if (usbdk_device_priv_init(ctx, dev, &devices[i]) != LIBUSB_SUCCESS) {
327                                 libusb_unref_device(dev);
328                                 continue;
329                         }
330                 }
331
332                 discdevs = discovered_devs_append(*_discdevs, dev);
333                 libusb_unref_device(dev);
334                 if (!discdevs) {
335                         usbi_err(ctx, "cannot append new device to list");
336                         r = LIBUSB_ERROR_NO_MEM;
337                         goto func_exit;
338                 }
339
340                 *_discdevs = discdevs;
341         }
342
343 func_exit:
344         usbdk_helper.ReleaseDevicesList(devices);
345         return r;
346 }
347
348 static int usbdk_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer)
349 {
350         struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
351
352         memcpy(buffer, &priv->info.DeviceDescriptor, DEVICE_DESC_LENGTH);
353
354         return LIBUSB_SUCCESS;
355 }
356
357 static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len)
358 {
359         struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
360         PUSB_CONFIGURATION_DESCRIPTOR config_header;
361         size_t size;
362
363         if (config_index >= dev->num_configurations)
364                 return LIBUSB_ERROR_INVALID_PARAM;
365
366         config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptors[config_index];
367
368         size = min(config_header->wTotalLength, len);
369         memcpy(buffer, config_header, size);
370         return (int)size;
371 }
372
373 static int usbdk_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue,
374         unsigned char **buffer)
375 {
376         struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
377         PUSB_CONFIGURATION_DESCRIPTOR config_header;
378         uint8_t index;
379
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;
385                 }
386         }
387
388         return LIBUSB_ERROR_NOT_FOUND;
389 }
390
391 static int usbdk_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len)
392 {
393         return usbdk_get_config_descriptor(dev, _usbdk_device_priv(dev)->active_configuration,
394                         buffer, len);
395 }
396
397 static int usbdk_open(struct libusb_device_handle *dev_handle)
398 {
399         struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
400
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;
405         }
406
407         priv->system_handle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
408
409         return LIBUSB_SUCCESS;
410 }
411
412 static void usbdk_close(struct libusb_device_handle *dev_handle)
413 {
414         struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
415
416         if (!usbdk_helper.StopRedirect(priv->redirector_handle))
417                 usbi_err(HANDLE_CTX(dev_handle), "Redirector shutdown failed");
418 }
419
420 static int usbdk_get_configuration(struct libusb_device_handle *dev_handle, int *config)
421 {
422         *config = _usbdk_device_priv(dev_handle->dev)->active_configuration;
423
424         return LIBUSB_SUCCESS;
425 }
426
427 static int usbdk_set_configuration(struct libusb_device_handle *dev_handle, int config)
428 {
429         UNUSED(dev_handle);
430         UNUSED(config);
431         return LIBUSB_SUCCESS;
432 }
433
434 static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, int iface)
435 {
436         UNUSED(dev_handle);
437         UNUSED(iface);
438         return LIBUSB_SUCCESS;
439 }
440
441 static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
442 {
443         struct libusb_context *ctx = HANDLE_CTX(dev_handle);
444         struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
445
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;
449         }
450
451         return LIBUSB_SUCCESS;
452 }
453
454 static int usbdk_release_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_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
462 {
463         struct libusb_context *ctx = HANDLE_CTX(dev_handle);
464         struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
465
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;
469         }
470
471         return LIBUSB_SUCCESS;
472 }
473
474 static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
475 {
476         struct libusb_context *ctx = HANDLE_CTX(dev_handle);
477         struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
478
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;
482         }
483
484         return LIBUSB_SUCCESS;
485 }
486
487 static void usbdk_destroy_device(struct libusb_device *dev)
488 {
489         struct usbdk_device_priv* p = _usbdk_device_priv(dev);
490
491         if (p->config_descriptors != NULL)
492                 usbdk_release_config_descriptors(p, p->info.DeviceDescriptor.bNumConfigurations);
493 }
494
495 static void usbdk_clear_transfer_priv(struct usbi_transfer *itransfer)
496 {
497         struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
498         struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
499
500         usbi_close(transfer_priv->pollable_fd.fd);
501         transfer_priv->pollable_fd = INVALID_WINFD;
502         transfer_priv->system_handle = NULL;
503
504         if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
505                 safe_free(transfer_priv->IsochronousPacketsArray);
506                 safe_free(transfer_priv->IsochronousResultsArray);
507         }
508 }
509
510 static int usbdk_do_control_transfer(struct usbi_transfer *itransfer)
511 {
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;
518
519         transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
520         transfer_priv->request.BufferLength = transfer->length;
521         transfer_priv->request.TransferType = ControlTransferType;
522
523         if (transfer->buffer[0] & LIBUSB_ENDPOINT_IN)
524                 transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
525         else
526                 transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
527
528         switch (transResult) {
529         case TransferSuccess:
530                 windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
531                 break;
532         case TransferSuccessAsync:
533                 break;
534         case TransferFailure:
535                 usbi_err(ctx, "ControlTransfer failed: %s", windows_error_str(0));
536                 return LIBUSB_ERROR_IO;
537         }
538
539         return LIBUSB_SUCCESS;
540 }
541
542 static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
543 {
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;
550
551         transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
552         transfer_priv->request.BufferLength = transfer->length;
553         transfer_priv->request.EndpointAddress = transfer->endpoint;
554
555         switch (transfer->type) {
556         case LIBUSB_TRANSFER_TYPE_BULK:
557                 transfer_priv->request.TransferType = BulkTransferType;
558                 break;
559         case LIBUSB_TRANSFER_TYPE_INTERRUPT:
560                 transfer_priv->request.TransferType = InterruptTransferType;
561                 break;
562         default:
563                 usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer", transfer->type);
564                 return LIBUSB_ERROR_INVALID_PARAM;
565         }
566
567         if (IS_XFERIN(transfer))
568                 transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
569         else
570                 transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
571
572         switch (transferRes) {
573         case TransferSuccess:
574                 windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
575                 break;
576         case TransferSuccessAsync:
577                 break;
578         case TransferFailure:
579                 usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
580                 return LIBUSB_ERROR_IO;
581         }
582
583         return LIBUSB_SUCCESS;
584 }
585
586 static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
587 {
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;
594         int i;
595
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;
606         }
607
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;
613         }
614
615         for (i = 0; i < transfer->num_iso_packets; i++)
616                 transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length;
617
618         if (IS_XFERIN(transfer))
619                 transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
620         else
621                 transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
622
623         switch (transferRes) {
624         case TransferSuccess:
625                 windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
626                 break;
627         case TransferSuccessAsync:
628                 break;
629         case TransferFailure:
630                 return LIBUSB_ERROR_IO;
631         }
632
633         return LIBUSB_SUCCESS;
634 }
635
636 static int usbdk_do_submit_transfer(struct usbi_transfer *itransfer,
637         short events, int (*transfer_fn)(struct usbi_transfer *))
638 {
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);
643         struct winfd wfd;
644         int r;
645
646         wfd = usbi_create_fd();
647         if (wfd.fd < 0)
648                 return LIBUSB_ERROR_NO_MEM;
649
650         r = usbi_add_pollfd(ctx, wfd.fd, events);
651         if (r) {
652                 usbi_close(wfd.fd);
653                 return r;
654         }
655
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;
659
660         r = transfer_fn(itransfer);
661         if (r != LIBUSB_SUCCESS) {
662                 usbi_remove_pollfd(ctx, wfd.fd);
663                 usbdk_clear_transfer_priv(itransfer);
664                 return r;
665         }
666
667         return LIBUSB_SUCCESS;
668 }
669
670 static int usbdk_submit_transfer(struct usbi_transfer *itransfer)
671 {
672         struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
673         int (*transfer_fn)(struct usbi_transfer *);
674         short events;
675
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;
680                 break;
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;
687                 break;
688         case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
689                 events = IS_XFERIN(transfer) ? POLLIN : POLLOUT;
690                 transfer_fn = usbdk_do_iso_transfer;
691                 break;
692         default:
693                 usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
694                 return LIBUSB_ERROR_INVALID_PARAM;
695         }
696
697         return usbdk_do_submit_transfer(itransfer, events, transfer_fn);
698 }
699
700 static int usbdk_abort_transfers(struct usbi_transfer *itransfer)
701 {
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;
707
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;
713                 }
714         } else {
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;
718                 }
719         }
720
721         return LIBUSB_SUCCESS;
722 }
723
724 static int usbdk_cancel_transfer(struct usbi_transfer *itransfer)
725 {
726         struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
727
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);
737         default:
738                 usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
739                 return LIBUSB_ERROR_INVALID_PARAM;
740         }
741 }
742
743 static int usbdk_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
744 {
745         itransfer->transferred += io_size;
746         return LIBUSB_TRANSFER_COMPLETED;
747 }
748
749 static int usbdk_get_transfer_fd(struct usbi_transfer *itransfer)
750 {
751         struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
752         return transfer_priv->pollable_fd.fd;
753 }
754
755 static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus)
756 {
757         if (USBD_SUCCESS(UsbdStatus))
758                 return NO_ERROR;
759
760         switch (UsbdStatus) {
761         case USBD_STATUS_TIMEOUT:
762                 return ERROR_SEM_TIMEOUT;
763         case USBD_STATUS_CANCELED:
764                 return ERROR_OPERATION_ABORTED;
765         default:
766                 return ERROR_GEN_FAILURE;
767         }
768 }
769
770 static void usbdk_get_overlapped_result(struct usbi_transfer *itransfer, DWORD *io_result, DWORD *io_size)
771 {
772         struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
773         struct winfd *pollable_fd = &transfer_priv->pollable_fd;
774
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);
778
779                 if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
780                         ULONG64 i;
781                         for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) {
782                                 struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i];
783
784                                 switch (transfer_priv->IsochronousResultsArray[i].TransferResult) {
785                                 case STATUS_SUCCESS:
786                                 case STATUS_CANCELLED:
787                                 case STATUS_REQUEST_CANCELED:
788                                         lib_desc->status = LIBUSB_TRANSFER_COMPLETED; // == ERROR_SUCCESS
789                                         break;
790                                 default:
791                                         lib_desc->status = LIBUSB_TRANSFER_ERROR; // ERROR_UNKNOWN_EXCEPTION;
792                                         break;
793                                 }
794
795                                 lib_desc->actual_length = (unsigned int)transfer_priv->IsochronousResultsArray[i].ActualLength;
796                         }
797                 }
798
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);
801         } else {
802                 *io_result = GetLastError();
803         }
804 }
805
806 const struct windows_backend usbdk_backend = {
807         usbdk_init,
808         usbdk_exit,
809         usbdk_get_device_list,
810         usbdk_open,
811         usbdk_close,
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,
821         usbdk_clear_halt,
822         usbdk_reset_device,
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,
830 };