Misc: Trim and consolidate header file usage
[platform/upstream/libusb.git] / 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_usbdk.h"
32
33 #if !defined(STATUS_SUCCESS)
34 typedef LONG NTSTATUS;
35 #define STATUS_SUCCESS                  ((NTSTATUS)0x00000000L)
36 #endif
37
38 #if !defined(STATUS_CANCELLED)
39 #define STATUS_CANCELLED                ((NTSTATUS)0xC0000120L)
40 #endif
41
42 #if !defined(STATUS_REQUEST_CANCELED)
43 #define STATUS_REQUEST_CANCELED         ((NTSTATUS)0xC0000703L)
44 #endif
45
46 static inline struct usbdk_device_priv *_usbdk_device_priv(struct libusb_device *dev)
47 {
48         return (struct usbdk_device_priv *)dev->os_priv;
49 }
50
51 static inline struct usbdk_transfer_priv *_usbdk_transfer_priv(struct usbi_transfer *itransfer)
52 {
53         return (struct usbdk_transfer_priv *)usbi_transfer_get_os_priv(itransfer);
54 }
55
56 static struct {
57         HMODULE module;
58
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;
72 } usbdk_helper;
73
74 static FARPROC get_usbdk_proc_addr(struct libusb_context *ctx, LPCSTR api_name)
75 {
76         FARPROC api_ptr = GetProcAddress(usbdk_helper.module, api_name);
77
78         if (api_ptr == NULL)
79                 usbi_err(ctx, "UsbDkHelper API %s not found: %s", api_name, windows_error_str(0));
80
81         return api_ptr;
82 }
83
84 static void unload_usbdk_helper_dll(void)
85 {
86         if (usbdk_helper.module != NULL) {
87                 FreeLibrary(usbdk_helper.module);
88                 usbdk_helper.module = NULL;
89         }
90 }
91
92 static int load_usbdk_helper_dll(struct libusb_context *ctx)
93 {
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;
98         }
99
100         usbdk_helper.GetDevicesList = (USBDK_GET_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_GetDevicesList");
101         if (usbdk_helper.GetDevicesList == NULL)
102                 goto error_unload;
103
104         usbdk_helper.ReleaseDevicesList = (USBDK_RELEASE_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseDevicesList");
105         if (usbdk_helper.ReleaseDevicesList == NULL)
106                 goto error_unload;
107
108         usbdk_helper.StartRedirect = (USBDK_START_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StartRedirect");
109         if (usbdk_helper.StartRedirect == NULL)
110                 goto error_unload;
111
112         usbdk_helper.StopRedirect = (USBDK_STOP_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StopRedirect");
113         if (usbdk_helper.StopRedirect == NULL)
114                 goto error_unload;
115
116         usbdk_helper.GetConfigurationDescriptor = (USBDK_GET_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_GetConfigurationDescriptor");
117         if (usbdk_helper.GetConfigurationDescriptor == NULL)
118                 goto error_unload;
119
120         usbdk_helper.ReleaseConfigurationDescriptor = (USBDK_RELEASE_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseConfigurationDescriptor");
121         if (usbdk_helper.ReleaseConfigurationDescriptor == NULL)
122                 goto error_unload;
123
124         usbdk_helper.ReadPipe = (USBDK_READ_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ReadPipe");
125         if (usbdk_helper.ReadPipe == NULL)
126                 goto error_unload;
127
128         usbdk_helper.WritePipe = (USBDK_WRITE_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_WritePipe");
129         if (usbdk_helper.WritePipe == NULL)
130                 goto error_unload;
131
132         usbdk_helper.AbortPipe = (USBDK_ABORT_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_AbortPipe");
133         if (usbdk_helper.AbortPipe == NULL)
134                 goto error_unload;
135
136         usbdk_helper.ResetPipe = (USBDK_RESET_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ResetPipe");
137         if (usbdk_helper.ResetPipe == NULL)
138                 goto error_unload;
139
140         usbdk_helper.SetAltsetting = (USBDK_SET_ALTSETTING)get_usbdk_proc_addr(ctx, "UsbDk_SetAltsetting");
141         if (usbdk_helper.SetAltsetting == NULL)
142                 goto error_unload;
143
144         usbdk_helper.ResetDevice = (USBDK_RESET_DEVICE)get_usbdk_proc_addr(ctx, "UsbDk_ResetDevice");
145         if (usbdk_helper.ResetDevice == NULL)
146                 goto error_unload;
147
148         usbdk_helper.GetRedirectorSystemHandle = (USBDK_GET_REDIRECTOR_SYSTEM_HANDLE)get_usbdk_proc_addr(ctx, "UsbDk_GetRedirectorSystemHandle");
149         if (usbdk_helper.GetRedirectorSystemHandle == NULL)
150                 goto error_unload;
151
152         return LIBUSB_SUCCESS;
153
154 error_unload:
155         FreeLibrary(usbdk_helper.module);
156         usbdk_helper.module = NULL;
157         return LIBUSB_ERROR_NOT_FOUND;
158 }
159
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);
163
164 static int usbdk_init(struct libusb_context *ctx)
165 {
166         POPENSCMANAGERA pOpenSCManagerA;
167         POPENSERVICEA pOpenServiceA;
168         PCLOSESERVICEHANDLE pCloseServiceHandle;
169         SC_HANDLE managerHandle;
170         SC_HANDLE serviceHandle;
171         HMODULE h;
172
173         h = LoadLibraryA("Advapi32");
174         if (h == NULL) {
175                 usbi_warn(ctx, "failed to open Advapi32\n");
176                 return LIBUSB_ERROR_OTHER;
177         }
178
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;
183         }
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;
188         }
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;
193         }
194
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;
199         }
200
201         serviceHandle = pOpenServiceA(managerHandle, "UsbDk", GENERIC_READ);
202         pCloseServiceHandle(managerHandle);
203
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));
207                 FreeLibrary(h);
208                 return LIBUSB_ERROR_NOT_FOUND;
209         }
210
211         pCloseServiceHandle(serviceHandle);
212         FreeLibrary(h);
213
214         return load_usbdk_helper_dll(ctx);
215
216 error_free_library:
217         FreeLibrary(h);
218         return LIBUSB_ERROR_OTHER;
219 }
220
221 static void usbdk_exit(struct libusb_context *ctx)
222 {
223         UNUSED(ctx);
224         unload_usbdk_helper_dll();
225 }
226
227 static int usbdk_get_session_id_for_device(struct libusb_context *ctx,
228         PUSB_DK_DEVICE_ID id, unsigned long *session_id)
229 {
230         char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID) + 1];
231
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;
235         }
236
237         *session_id = htab_hash(dev_identity);
238
239         return LIBUSB_SUCCESS;
240 }
241
242 static void usbdk_release_config_descriptors(struct usbdk_device_priv *p, uint8_t count)
243 {
244         uint8_t i;
245
246         for (i = 0; i < count; i++)
247                 usbdk_helper.ReleaseConfigurationDescriptor(p->config_descriptors[i]);
248
249         free(p->config_descriptors);
250         p->config_descriptors = NULL;
251 }
252
253 static int usbdk_cache_config_descriptors(struct libusb_context *ctx,
254         struct usbdk_device_priv *p, PUSB_DK_DEVICE_INFO info)
255 {
256         uint8_t i;
257         USB_DK_CONFIG_DESCRIPTOR_REQUEST Request;
258         Request.ID = info->ID;
259
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;
264         }
265
266         for (i = 0; i < info->DeviceDescriptor.bNumConfigurations; i++) {
267                 ULONG Length;
268
269                 Request.Index = 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;
274                 }
275         }
276
277         return LIBUSB_SUCCESS;
278 }
279
280 static inline int usbdk_device_priv_init(struct libusb_context *ctx, struct libusb_device *dev, PUSB_DK_DEVICE_INFO info)
281 {
282         struct usbdk_device_priv *p = _usbdk_device_priv(dev);
283
284         p->info = *info;
285         p->active_configuration = 0;
286
287         return usbdk_cache_config_descriptors(ctx, p, info);
288 }
289
290 static void usbdk_device_init(libusb_device *dev, PUSB_DK_DEVICE_INFO info)
291 {
292         dev->bus_number = (uint8_t)info->FilterID;
293         dev->port_number = (uint8_t)info->Port;
294         dev->parent_dev = NULL;
295
296         // Addresses in libusb are 1-based
297         dev->device_address = (uint8_t)(info->Port + 1);
298
299         dev->num_configurations = info->DeviceDescriptor.bNumConfigurations;
300         memcpy(&dev->device_descriptor, &info->DeviceDescriptor, LIBUSB_DT_DEVICE_SIZE);
301
302         switch (info->Speed) {
303         case LowSpeed:
304                 dev->speed = LIBUSB_SPEED_LOW;
305                 break;
306         case FullSpeed:
307                 dev->speed = LIBUSB_SPEED_FULL;
308                 break;
309         case HighSpeed:
310                 dev->speed = LIBUSB_SPEED_HIGH;
311                 break;
312         case SuperSpeed:
313                 dev->speed = LIBUSB_SPEED_SUPER;
314                 break;
315         case NoSpeed:
316         default:
317                 dev->speed = LIBUSB_SPEED_UNKNOWN;
318                 break;
319         }
320 }
321
322 static int usbdk_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
323 {
324         int r = LIBUSB_SUCCESS;
325         ULONG i;
326         struct discovered_devs *discdevs = NULL;
327         ULONG dev_number;
328         PUSB_DK_DEVICE_INFO devices;
329
330         if (!usbdk_helper.GetDevicesList(&devices, &dev_number))
331                 return LIBUSB_ERROR_OTHER;
332
333         for (i = 0; i < dev_number; i++) {
334                 unsigned long session_id;
335                 struct libusb_device *dev = NULL;
336
337                 if (usbdk_get_session_id_for_device(ctx, &devices[i].ID, &session_id))
338                         continue;
339
340                 dev = usbi_get_device_by_session_id(ctx, session_id);
341                 if (dev == NULL) {
342                         dev = usbi_alloc_device(ctx, session_id);
343                         if (dev == NULL) {
344                                 usbi_err(ctx, "failed to allocate a new device structure");
345                                 continue;
346                         }
347
348                         usbdk_device_init(dev, &devices[i]);
349                         if (usbdk_device_priv_init(ctx, dev, &devices[i]) != LIBUSB_SUCCESS) {
350                                 libusb_unref_device(dev);
351                                 continue;
352                         }
353                 }
354
355                 discdevs = discovered_devs_append(*_discdevs, dev);
356                 libusb_unref_device(dev);
357                 if (!discdevs) {
358                         usbi_err(ctx, "cannot append new device to list");
359                         r = LIBUSB_ERROR_NO_MEM;
360                         goto func_exit;
361                 }
362
363                 *_discdevs = discdevs;
364         }
365
366 func_exit:
367         usbdk_helper.ReleaseDevicesList(devices);
368         return r;
369 }
370
371 static int usbdk_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer)
372 {
373         struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
374
375         memcpy(buffer, &priv->info.DeviceDescriptor, DEVICE_DESC_LENGTH);
376
377         return LIBUSB_SUCCESS;
378 }
379
380 static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len)
381 {
382         struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
383         PUSB_CONFIGURATION_DESCRIPTOR config_header;
384         size_t size;
385
386         if (config_index >= dev->num_configurations)
387                 return LIBUSB_ERROR_INVALID_PARAM;
388
389         config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptors[config_index];
390
391         size = min(config_header->wTotalLength, len);
392         memcpy(buffer, config_header, size);
393         return (int)size;
394 }
395
396 static int usbdk_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue,
397         unsigned char **buffer)
398 {
399         struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
400         PUSB_CONFIGURATION_DESCRIPTOR config_header;
401         uint8_t index;
402
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;
408                 }
409         }
410
411         return LIBUSB_ERROR_NOT_FOUND;
412 }
413
414 static int usbdk_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len)
415 {
416         return usbdk_get_config_descriptor(dev, _usbdk_device_priv(dev)->active_configuration,
417                         buffer, len);
418 }
419
420 static int usbdk_open(struct libusb_device_handle *dev_handle)
421 {
422         struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
423
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;
428         }
429
430         priv->system_handle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
431
432         return LIBUSB_SUCCESS;
433 }
434
435 static void usbdk_close(struct libusb_device_handle *dev_handle)
436 {
437         struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
438
439         if (!usbdk_helper.StopRedirect(priv->redirector_handle))
440                 usbi_err(HANDLE_CTX(dev_handle), "Redirector shutdown failed");
441 }
442
443 static int usbdk_get_configuration(struct libusb_device_handle *dev_handle, int *config)
444 {
445         *config = _usbdk_device_priv(dev_handle->dev)->active_configuration;
446
447         return LIBUSB_SUCCESS;
448 }
449
450 static int usbdk_set_configuration(struct libusb_device_handle *dev_handle, int config)
451 {
452         UNUSED(dev_handle);
453         UNUSED(config);
454         return LIBUSB_SUCCESS;
455 }
456
457 static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, int iface)
458 {
459         UNUSED(dev_handle);
460         UNUSED(iface);
461         return LIBUSB_SUCCESS;
462 }
463
464 static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
465 {
466         struct libusb_context *ctx = HANDLE_CTX(dev_handle);
467         struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
468
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;
472         }
473
474         return LIBUSB_SUCCESS;
475 }
476
477 static int usbdk_release_interface(struct libusb_device_handle *dev_handle, int iface)
478 {
479         UNUSED(dev_handle);
480         UNUSED(iface);
481         return LIBUSB_SUCCESS;
482 }
483
484 static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
485 {
486         struct libusb_context *ctx = HANDLE_CTX(dev_handle);
487         struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
488
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;
492         }
493
494         return LIBUSB_SUCCESS;
495 }
496
497 static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
498 {
499         struct libusb_context *ctx = HANDLE_CTX(dev_handle);
500         struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
501
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;
505         }
506
507         return LIBUSB_SUCCESS;
508 }
509
510 static void usbdk_destroy_device(struct libusb_device *dev)
511 {
512         struct usbdk_device_priv* p = _usbdk_device_priv(dev);
513
514         if (p->config_descriptors != NULL)
515                 usbdk_release_config_descriptors(p, p->info.DeviceDescriptor.bNumConfigurations);
516 }
517
518 static void usbdk_clear_transfer_priv(struct usbi_transfer *itransfer)
519 {
520         struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
521         struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
522
523         usbi_close(transfer_priv->pollable_fd.fd);
524         transfer_priv->pollable_fd = INVALID_WINFD;
525         transfer_priv->system_handle = NULL;
526
527         if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
528                 safe_free(transfer_priv->IsochronousPacketsArray);
529                 safe_free(transfer_priv->IsochronousResultsArray);
530         }
531 }
532
533 static int usbdk_do_control_transfer(struct usbi_transfer *itransfer)
534 {
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;
541
542         transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
543         transfer_priv->request.BufferLength = transfer->length;
544         transfer_priv->request.TransferType = ControlTransferType;
545
546         if (transfer->buffer[0] & LIBUSB_ENDPOINT_IN)
547                 transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
548         else
549                 transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
550
551         switch (transResult) {
552         case TransferSuccess:
553                 windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
554                 break;
555         case TransferSuccessAsync:
556                 break;
557         case TransferFailure:
558                 usbi_err(ctx, "ControlTransfer failed: %s", windows_error_str(0));
559                 return LIBUSB_ERROR_IO;
560         }
561
562         return LIBUSB_SUCCESS;
563 }
564
565 static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
566 {
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;
573
574         transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
575         transfer_priv->request.BufferLength = transfer->length;
576         transfer_priv->request.EndpointAddress = transfer->endpoint;
577
578         switch (transfer->type) {
579         case LIBUSB_TRANSFER_TYPE_BULK:
580                 transfer_priv->request.TransferType = BulkTransferType;
581                 break;
582         case LIBUSB_TRANSFER_TYPE_INTERRUPT:
583                 transfer_priv->request.TransferType = InterruptTransferType;
584                 break;
585         default:
586                 usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer", transfer->type);
587                 return LIBUSB_ERROR_INVALID_PARAM;
588         }
589
590         if (IS_XFERIN(transfer))
591                 transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
592         else
593                 transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
594
595         switch (transferRes) {
596         case TransferSuccess:
597                 windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
598                 break;
599         case TransferSuccessAsync:
600                 break;
601         case TransferFailure:
602                 usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
603                 return LIBUSB_ERROR_IO;
604         }
605
606         return LIBUSB_SUCCESS;
607 }
608
609 static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
610 {
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;
617         int i;
618
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;
629         }
630
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;
636         }
637
638         for (i = 0; i < transfer->num_iso_packets; i++)
639                 transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length;
640
641         if (IS_XFERIN(transfer))
642                 transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
643         else
644                 transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
645
646         switch (transferRes) {
647         case TransferSuccess:
648                 windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
649                 break;
650         case TransferSuccessAsync:
651                 break;
652         case TransferFailure:
653                 return LIBUSB_ERROR_IO;
654         }
655
656         return LIBUSB_SUCCESS;
657 }
658
659 static int usbdk_do_submit_transfer(struct usbi_transfer *itransfer,
660         short events, int (*transfer_fn)(struct usbi_transfer *))
661 {
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);
666         struct winfd wfd;
667         int r;
668
669         wfd = usbi_create_fd();
670         if (wfd.fd < 0)
671                 return LIBUSB_ERROR_NO_MEM;
672
673         r = usbi_add_pollfd(ctx, wfd.fd, events);
674         if (r) {
675                 usbi_close(wfd.fd);
676                 return r;
677         }
678
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;
682
683         r = transfer_fn(itransfer);
684         if (r != LIBUSB_SUCCESS) {
685                 usbi_remove_pollfd(ctx, wfd.fd);
686                 usbdk_clear_transfer_priv(itransfer);
687                 return r;
688         }
689
690         return LIBUSB_SUCCESS;
691 }
692
693 static int usbdk_submit_transfer(struct usbi_transfer *itransfer)
694 {
695         struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
696         int (*transfer_fn)(struct usbi_transfer *);
697         short events;
698
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;
703                 break;
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;
710                 break;
711         case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
712                 events = IS_XFERIN(transfer) ? POLLIN : POLLOUT;
713                 transfer_fn = usbdk_do_iso_transfer;
714                 break;
715         default:
716                 usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
717                 return LIBUSB_ERROR_INVALID_PARAM;
718         }
719
720         return usbdk_do_submit_transfer(itransfer, events, transfer_fn);
721 }
722
723 static int usbdk_abort_transfers(struct usbi_transfer *itransfer)
724 {
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;
730
731         // Use CancelIoEx to cancel just a single transfer
732         if (CancelIoEx(priv->system_handle, pollable_fd->overlapped))
733                 return LIBUSB_SUCCESS;
734
735         usbi_warn(ctx, "CancelIoEx failed: %s", windows_error_str(0));
736         return LIBUSB_ERROR_NOT_FOUND;
737 }
738
739 static int usbdk_cancel_transfer(struct usbi_transfer *itransfer)
740 {
741         struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
742
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);
752         default:
753                 usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
754                 return LIBUSB_ERROR_INVALID_PARAM;
755         }
756 }
757
758 static int usbdk_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
759 {
760         itransfer->transferred += io_size;
761         return LIBUSB_TRANSFER_COMPLETED;
762 }
763
764 static int usbdk_get_transfer_fd(struct usbi_transfer *itransfer)
765 {
766         struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
767         return transfer_priv->pollable_fd.fd;
768 }
769
770 static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus)
771 {
772         if (USBD_SUCCESS(UsbdStatus))
773                 return NO_ERROR;
774
775         switch (UsbdStatus) {
776         case USBD_STATUS_TIMEOUT:
777                 return ERROR_SEM_TIMEOUT;
778         case USBD_STATUS_CANCELED:
779                 return ERROR_OPERATION_ABORTED;
780         default:
781                 return ERROR_GEN_FAILURE;
782         }
783 }
784
785 static void usbdk_get_overlapped_result(struct usbi_transfer *itransfer, DWORD *io_result, DWORD *io_size)
786 {
787         struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
788         struct winfd *pollable_fd = &transfer_priv->pollable_fd;
789
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);
793
794                 if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
795                         ULONG64 i;
796                         for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) {
797                                 struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i];
798
799                                 switch (transfer_priv->IsochronousResultsArray[i].TransferResult) {
800                                 case STATUS_SUCCESS:
801                                 case STATUS_CANCELLED:
802                                 case STATUS_REQUEST_CANCELED:
803                                         lib_desc->status = LIBUSB_TRANSFER_COMPLETED; // == ERROR_SUCCESS
804                                         break;
805                                 default:
806                                         lib_desc->status = LIBUSB_TRANSFER_ERROR; // ERROR_UNKNOWN_EXCEPTION;
807                                         break;
808                                 }
809
810                                 lib_desc->actual_length = (unsigned int)transfer_priv->IsochronousResultsArray[i].ActualLength;
811                         }
812                 }
813
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);
816         } else {
817                 *io_result = GetLastError();
818         }
819 }
820
821 const struct windows_backend usbdk_backend = {
822         usbdk_init,
823         usbdk_exit,
824         usbdk_get_device_list,
825         usbdk_open,
826         usbdk_close,
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,
836         usbdk_clear_halt,
837         usbdk_reset_device,
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,
845 };