core: Kill usbi_os_backend structure definition madness
[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 #if defined(USE_USBDK)
27
28 #include <windows.h>
29 #include <cfgmgr32.h>
30 #include <stdio.h>
31
32 #include "libusbi.h"
33 #include "windows_common.h"
34 #include "windows_nt_common.h"
35
36 #define ULONG64 uint64_t
37 #define PVOID64 uint64_t
38
39 typedef CONST WCHAR *PCWCHAR;
40 #define wcsncpy_s wcsncpy
41
42 #include "windows_usbdk.h"
43
44 #if !defined(STATUS_SUCCESS)
45 typedef LONG NTSTATUS;
46 #define STATUS_SUCCESS                  ((NTSTATUS)0x00000000L)
47 #endif
48
49 #if !defined(STATUS_CANCELLED)
50 #define STATUS_CANCELLED                ((NTSTATUS)0xC0000120L)
51 #endif
52
53 #if !defined(STATUS_REQUEST_CANCELED)
54 #define STATUS_REQUEST_CANCELED         ((NTSTATUS)0xC0000703L)
55 #endif
56
57 #if !defined(USBD_SUCCESS)
58 typedef int32_t USBD_STATUS;
59 #define USBD_SUCCESS(Status)            ((USBD_STATUS) (Status) >= 0)
60 #define USBD_PENDING(Status)            ((ULONG) (Status) >> 30 == 1)
61 #define USBD_ERROR(Status)              ((USBD_STATUS) (Status) < 0)
62 #define USBD_STATUS_STALL_PID           ((USBD_STATUS) 0xc0000004)
63 #define USBD_STATUS_ENDPOINT_HALTED     ((USBD_STATUS) 0xc0000030)
64 #define USBD_STATUS_BAD_START_FRAME     ((USBD_STATUS) 0xc0000a00)
65 #define USBD_STATUS_TIMEOUT             ((USBD_STATUS) 0xc0006000)
66 #define USBD_STATUS_CANCELED            ((USBD_STATUS) 0xc0010000)
67 #endif
68
69 static int concurrent_usage = -1;
70
71 struct usbdk_device_priv {
72         USB_DK_DEVICE_INFO info;
73         PUSB_CONFIGURATION_DESCRIPTOR *config_descriptors;
74         HANDLE redirector_handle;
75         uint8_t active_configuration;
76 };
77
78 struct usbdk_transfer_priv {
79         USB_DK_TRANSFER_REQUEST request;
80         struct winfd pollable_fd;
81         PULONG64 IsochronousPacketsArray;
82         PUSB_DK_ISO_TRANSFER_RESULT IsochronousResultsArray;
83 };
84
85 static inline struct usbdk_device_priv *_usbdk_device_priv(struct libusb_device *dev)
86 {
87         return (struct usbdk_device_priv *)dev->os_priv;
88 }
89
90 static inline struct usbdk_transfer_priv *_usbdk_transfer_priv(struct usbi_transfer *itransfer)
91 {
92         return (struct usbdk_transfer_priv *)usbi_transfer_get_os_priv(itransfer);
93 }
94
95 static struct {
96         HMODULE module;
97
98         USBDK_GET_DEVICES_LIST                  GetDevicesList;
99         USBDK_RELEASE_DEVICES_LIST              ReleaseDevicesList;
100         USBDK_START_REDIRECT                    StartRedirect;
101         USBDK_STOP_REDIRECT                     StopRedirect;
102         USBDK_GET_CONFIGURATION_DESCRIPTOR      GetConfigurationDescriptor;
103         USBDK_RELEASE_CONFIGURATION_DESCRIPTOR  ReleaseConfigurationDescriptor;
104         USBDK_READ_PIPE                         ReadPipe;
105         USBDK_WRITE_PIPE                        WritePipe;
106         USBDK_ABORT_PIPE                        AbortPipe;
107         USBDK_RESET_PIPE                        ResetPipe;
108         USBDK_SET_ALTSETTING                    SetAltsetting;
109         USBDK_RESET_DEVICE                      ResetDevice;
110         USBDK_GET_REDIRECTOR_SYSTEM_HANDLE      GetRedirectorSystemHandle;
111 } usbdk_helper;
112
113 static FARPROC get_usbdk_proc_addr(struct libusb_context *ctx, LPCSTR api_name)
114 {
115         FARPROC api_ptr = GetProcAddress(usbdk_helper.module, api_name);
116
117         if (api_ptr == NULL)
118                 usbi_err(ctx, "UsbDkHelper API %s not found, error %d", api_name, GetLastError());
119
120         return api_ptr;
121 }
122
123 static void unload_usbdk_helper_dll(void)
124 {
125         if (usbdk_helper.module != NULL) {
126                 FreeLibrary(usbdk_helper.module);
127                 usbdk_helper.module = NULL;
128         }
129 }
130
131 static int load_usbdk_helper_dll(struct libusb_context *ctx)
132 {
133         usbdk_helper.module = LoadLibraryA("UsbDkHelper");
134         if (usbdk_helper.module == NULL) {
135                 usbi_err(ctx, "Failed to load UsbDkHelper.dll, error %d", GetLastError());
136                 return LIBUSB_ERROR_NOT_FOUND;
137         }
138
139         usbdk_helper.GetDevicesList = (USBDK_GET_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_GetDevicesList");
140         if (usbdk_helper.GetDevicesList == NULL)
141                 goto error_unload;
142
143         usbdk_helper.ReleaseDevicesList = (USBDK_RELEASE_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseDevicesList");
144         if (usbdk_helper.ReleaseDevicesList == NULL)
145                 goto error_unload;
146
147         usbdk_helper.StartRedirect = (USBDK_START_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StartRedirect");
148         if (usbdk_helper.StartRedirect == NULL)
149                 goto error_unload;
150
151         usbdk_helper.StopRedirect = (USBDK_STOP_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StopRedirect");
152         if (usbdk_helper.StopRedirect == NULL)
153                 goto error_unload;
154
155         usbdk_helper.GetConfigurationDescriptor = (USBDK_GET_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_GetConfigurationDescriptor");
156         if (usbdk_helper.GetConfigurationDescriptor == NULL)
157                 goto error_unload;
158
159         usbdk_helper.ReleaseConfigurationDescriptor = (USBDK_RELEASE_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseConfigurationDescriptor");
160         if (usbdk_helper.ReleaseConfigurationDescriptor == NULL)
161                 goto error_unload;
162
163         usbdk_helper.ReadPipe = (USBDK_READ_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ReadPipe");
164         if (usbdk_helper.ReadPipe == NULL)
165                 goto error_unload;
166
167         usbdk_helper.WritePipe = (USBDK_WRITE_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_WritePipe");
168         if (usbdk_helper.WritePipe == NULL)
169                 goto error_unload;
170
171         usbdk_helper.AbortPipe = (USBDK_ABORT_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_AbortPipe");
172         if (usbdk_helper.AbortPipe == NULL)
173                 goto error_unload;
174
175         usbdk_helper.ResetPipe = (USBDK_RESET_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ResetPipe");
176         if (usbdk_helper.ResetPipe == NULL)
177                 goto error_unload;
178
179         usbdk_helper.SetAltsetting = (USBDK_SET_ALTSETTING)get_usbdk_proc_addr(ctx, "UsbDk_SetAltsetting");
180         if (usbdk_helper.SetAltsetting == NULL)
181                 goto error_unload;
182
183         usbdk_helper.ResetDevice = (USBDK_RESET_DEVICE)get_usbdk_proc_addr(ctx, "UsbDk_ResetDevice");
184         if (usbdk_helper.ResetDevice == NULL)
185                 goto error_unload;
186
187         usbdk_helper.GetRedirectorSystemHandle = (USBDK_GET_REDIRECTOR_SYSTEM_HANDLE)get_usbdk_proc_addr(ctx, "UsbDk_GetRedirectorSystemHandle");
188         if (usbdk_helper.GetRedirectorSystemHandle == NULL)
189                 goto error_unload;
190
191         return LIBUSB_SUCCESS;
192
193 error_unload:
194         FreeLibrary(usbdk_helper.module);
195         usbdk_helper.module = NULL;
196         return LIBUSB_ERROR_NOT_FOUND;
197 }
198
199 static int usbdk_init(struct libusb_context *ctx)
200 {
201         int r;
202
203         if (++concurrent_usage == 0) { // First init?
204                 r = load_usbdk_helper_dll(ctx);
205                 if (r)
206                         goto init_exit;
207
208                 init_polling();
209
210                 r = windows_common_init(ctx);
211                 if (r)
212                         goto init_exit;
213         }
214         // At this stage, either we went through full init successfully, or didn't need to
215         r = LIBUSB_SUCCESS;
216
217 init_exit:
218         if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed?
219                 exit_polling();
220                 windows_common_exit();
221                 unload_usbdk_helper_dll();
222         }
223
224         if (r != LIBUSB_SUCCESS)
225                 --concurrent_usage; // Not expected to call libusb_exit if we failed.
226
227         return r;
228 }
229
230 static int usbdk_get_session_id_for_device(struct libusb_context *ctx,
231         PUSB_DK_DEVICE_ID id, unsigned long *session_id)
232 {
233         char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID)];
234
235         if (sprintf(dev_identity, "%S%S", id->DeviceID, id->InstanceID) == -1) {
236                 usbi_warn(ctx, "cannot form device identity", id->DeviceID);
237                 return LIBUSB_ERROR_NOT_SUPPORTED;
238         }
239
240         *session_id = htab_hash(dev_identity);
241
242         return LIBUSB_SUCCESS;
243 }
244
245 static void usbdk_release_config_descriptors(struct usbdk_device_priv *p, uint8_t count)
246 {
247         uint8_t i;
248
249         for (i = 0; i < count; i++)
250                 usbdk_helper.ReleaseConfigurationDescriptor(p->config_descriptors[i]);
251
252         free(p->config_descriptors);
253         p->config_descriptors = NULL;
254 }
255
256 static int usbdk_cache_config_descriptors(struct libusb_context *ctx,
257         struct usbdk_device_priv *p, PUSB_DK_DEVICE_INFO info)
258 {
259         uint8_t i;
260         USB_DK_CONFIG_DESCRIPTOR_REQUEST Request;
261         Request.ID = info->ID;
262
263         p->config_descriptors = calloc(info->DeviceDescriptor.bNumConfigurations, sizeof(PUSB_CONFIGURATION_DESCRIPTOR));
264         if (p->config_descriptors == NULL) {
265                 usbi_err(ctx, "failed to allocate configuration descriptors holder");
266                 return LIBUSB_ERROR_NO_MEM;
267         }
268
269         for (i = 0; i < info->DeviceDescriptor.bNumConfigurations; i++) {
270                 ULONG Length;
271
272                 Request.Index = i;
273                 if (!usbdk_helper.GetConfigurationDescriptor(&Request, &p->config_descriptors[i], &Length)) {
274                         usbi_err(ctx, "failed to retrieve configuration descriptors");
275                         usbdk_release_config_descriptors(p, i);
276                         return LIBUSB_ERROR_OTHER;
277                 }
278         }
279
280         return LIBUSB_SUCCESS;
281 }
282
283 static inline int usbdk_device_priv_init(struct libusb_context *ctx, struct libusb_device *dev, PUSB_DK_DEVICE_INFO info)
284 {
285         struct usbdk_device_priv *p = _usbdk_device_priv(dev);
286
287         p->info = *info;
288         p->active_configuration = 0;
289
290         return usbdk_cache_config_descriptors(ctx, p, info);
291 }
292
293 static void usbdk_device_init(libusb_device *dev, PUSB_DK_DEVICE_INFO info)
294 {
295         dev->bus_number = (uint8_t)info->FilterID;
296         dev->port_number = (uint8_t)info->Port;
297         dev->parent_dev = NULL;
298
299         //Addresses in libusb are 1-based
300         dev->device_address = (uint8_t)(info->Port + 1);
301
302         dev->num_configurations = info->DeviceDescriptor.bNumConfigurations;
303         dev->device_descriptor = info->DeviceDescriptor;
304
305         switch (info->Speed) {
306         case LowSpeed:
307                 dev->speed = LIBUSB_SPEED_LOW;
308                 break;
309         case FullSpeed:
310                 dev->speed = LIBUSB_SPEED_FULL;
311                 break;
312         case HighSpeed:
313                 dev->speed = LIBUSB_SPEED_HIGH;
314                 break;
315         case SuperSpeed:
316                 dev->speed = LIBUSB_SPEED_SUPER;
317                 break;
318         case NoSpeed:
319         default:
320                 dev->speed = LIBUSB_SPEED_UNKNOWN;
321                 break;
322         }
323 }
324
325 static int usbdk_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
326 {
327         int r = LIBUSB_SUCCESS;
328         ULONG i;
329         struct discovered_devs *discdevs = NULL;
330         ULONG dev_number;
331         PUSB_DK_DEVICE_INFO devices;
332
333         if(!usbdk_helper.GetDevicesList(&devices, &dev_number))
334                 return LIBUSB_ERROR_OTHER;
335
336         for (i = 0; i < dev_number; i++) {
337                 unsigned long session_id;
338                 struct libusb_device *dev = NULL;
339
340                 if (usbdk_get_session_id_for_device(ctx, &devices[i].ID, &session_id))
341                         continue;
342
343                 dev = usbi_get_device_by_session_id(ctx, session_id);
344                 if (dev == NULL) {
345                         dev = usbi_alloc_device(ctx, session_id);
346                         if (dev == NULL) {
347                                 usbi_err(ctx, "failed to allocate a new device structure");
348                                 continue;
349                         }
350
351                         usbdk_device_init(dev, &devices[i]);
352                         if (usbdk_device_priv_init(ctx, dev, &devices[i]) != LIBUSB_SUCCESS) {
353                                 libusb_unref_device(dev);
354                                 continue;
355                         }
356                 }
357
358                 discdevs = discovered_devs_append(*_discdevs, dev);
359                 libusb_unref_device(dev);
360                 if (!discdevs) {
361                         usbi_err(ctx, "cannot append new device to list");
362                         r = LIBUSB_ERROR_NO_MEM;
363                         goto func_exit;
364                 }
365
366                 *_discdevs = discdevs;
367         }
368
369 func_exit:
370         usbdk_helper.ReleaseDevicesList(devices);
371         return r;
372 }
373
374 static void usbdk_exit(void)
375 {
376         if (--concurrent_usage < 0) {
377                 windows_common_exit();
378                 exit_polling();
379                 unload_usbdk_helper_dll();
380         }
381 }
382
383 static int usbdk_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian)
384 {
385         struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
386
387         memcpy(buffer, &priv->info.DeviceDescriptor, DEVICE_DESC_LENGTH);
388         *host_endian = 0;
389
390         return LIBUSB_SUCCESS;
391 }
392
393 static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
394 {
395         struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
396         PUSB_CONFIGURATION_DESCRIPTOR config_header;
397         size_t size;
398
399         if (config_index >= dev->num_configurations)
400                 return LIBUSB_ERROR_INVALID_PARAM;
401
402         config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptors[config_index];
403
404         size = min(config_header->wTotalLength, len);
405         memcpy(buffer, config_header, size);
406         *host_endian = 0;
407
408         return (int)size;
409 }
410
411 static inline int usbdk_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian)
412 {
413         return usbdk_get_config_descriptor(dev, _usbdk_device_priv(dev)->active_configuration,
414                         buffer, len, host_endian);
415 }
416
417 static int usbdk_open(struct libusb_device_handle *dev_handle)
418 {
419         struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
420
421         priv->redirector_handle = usbdk_helper.StartRedirect(&priv->info.ID);
422         if (priv->redirector_handle == INVALID_HANDLE_VALUE) {
423                 usbi_err(DEVICE_CTX(dev_handle->dev), "Redirector startup failed");
424                 return LIBUSB_ERROR_OTHER;
425         }
426
427         return LIBUSB_SUCCESS;
428 }
429
430 static void usbdk_close(struct libusb_device_handle *dev_handle)
431 {
432         struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
433
434         if (!usbdk_helper.StopRedirect(priv->redirector_handle)) {
435                 struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
436                 usbi_err(ctx, "Redirector shutdown failed");
437         }
438 }
439
440 static int usbdk_get_configuration(struct libusb_device_handle *dev_handle, int *config)
441 {
442         *config = _usbdk_device_priv(dev_handle->dev)->active_configuration;
443
444         return LIBUSB_SUCCESS;
445 }
446
447 static int usbdk_set_configuration(struct libusb_device_handle *dev_handle, int config)
448 {
449         UNUSED(dev_handle);
450         UNUSED(config);
451         return LIBUSB_SUCCESS;
452 }
453
454 static int usbdk_claim_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_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
462 {
463         struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
464         struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
465
466         if (!usbdk_helper.SetAltsetting(priv->redirector_handle, iface, altsetting)) {
467                 usbi_err(ctx, "SetAltsetting failed: %s", windows_error_str(0));
468                 return LIBUSB_ERROR_NO_DEVICE;
469         }
470
471         return LIBUSB_SUCCESS;
472 }
473
474 static int usbdk_release_interface(struct libusb_device_handle *dev_handle, int iface)
475 {
476         UNUSED(dev_handle);
477         UNUSED(iface);
478         return LIBUSB_SUCCESS;
479 }
480
481 static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
482 {
483         struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
484         struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
485
486         if (!usbdk_helper.ResetPipe(priv->redirector_handle, endpoint)) {
487                 usbi_err(ctx, "ResetPipe failed: %s", windows_error_str(0));
488                 return LIBUSB_ERROR_NO_DEVICE;
489         }
490
491         return LIBUSB_SUCCESS;
492 }
493
494 static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
495 {
496         struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
497         struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
498
499         if (!usbdk_helper.ResetDevice(priv->redirector_handle)) {
500                 usbi_err(ctx, "ResetDevice failed: %s", windows_error_str(0));
501                 return LIBUSB_ERROR_NO_DEVICE;
502         }
503
504         return LIBUSB_SUCCESS;
505 }
506
507 static int usbdk_kernel_driver_active(struct libusb_device_handle *dev_handle, int iface)
508 {
509         UNUSED(dev_handle);
510         UNUSED(iface);
511         return LIBUSB_ERROR_NOT_SUPPORTED;
512 }
513
514 static int usbdk_attach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
515 {
516         UNUSED(dev_handle);
517         UNUSED(iface);
518         return LIBUSB_ERROR_NOT_SUPPORTED;
519 }
520
521 static int usbdk_detach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
522 {
523         UNUSED(dev_handle);
524         UNUSED(iface);
525         return LIBUSB_ERROR_NOT_SUPPORTED;
526 }
527
528 static void usbdk_destroy_device(struct libusb_device *dev)
529 {
530         struct usbdk_device_priv* p = _usbdk_device_priv(dev);
531
532         if (p->config_descriptors != NULL)
533                 usbdk_release_config_descriptors(p, p->info.DeviceDescriptor.bNumConfigurations);
534 }
535
536 void windows_clear_transfer_priv(struct usbi_transfer *itransfer)
537 {
538         struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
539         struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
540
541         usbi_free_fd(&transfer_priv->pollable_fd);
542
543         if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
544                 safe_free(transfer_priv->IsochronousPacketsArray);
545                 safe_free(transfer_priv->IsochronousResultsArray);
546         }
547 }
548
549 static int usbdk_do_control_transfer(struct usbi_transfer *itransfer)
550 {
551         struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
552         struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
553         struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
554         struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
555         struct winfd wfd;
556         ULONG Length;
557         TransferResult transResult;
558         HANDLE sysHandle;
559
560         sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
561
562         wfd = usbi_create_fd(sysHandle, RW_READ, NULL, NULL);
563         // Always use the handle returned from usbi_create_fd (wfd.handle)
564         if (wfd.fd < 0)
565                 return LIBUSB_ERROR_NO_MEM;
566
567         transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer;
568         transfer_priv->request.BufferLength = transfer->length;
569         transfer_priv->request.TransferType = ControlTransferType;
570         transfer_priv->pollable_fd = INVALID_WINFD;
571         Length = (ULONG)transfer->length;
572
573         if (IS_XFERIN(transfer))
574                 transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
575         else
576                 transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
577
578         switch (transResult) {
579         case TransferSuccess:
580                 wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
581                 wfd.overlapped->InternalHigh = (DWORD)Length;
582                 break;
583         case TransferSuccessAsync:
584                 break;
585         case TransferFailure:
586                 usbi_err(ctx, "ControlTransfer failed: %s", windows_error_str(0));
587                 usbi_free_fd(&wfd);
588                 return LIBUSB_ERROR_IO;
589         }
590
591         // Use priv_transfer to store data needed for async polling
592         transfer_priv->pollable_fd = wfd;
593         usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN);
594
595         return LIBUSB_SUCCESS;
596 }
597
598 static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
599 {
600         struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
601         struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
602         struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
603         struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
604         struct winfd wfd;
605         TransferResult transferRes;
606         HANDLE sysHandle;
607
608         transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer;
609         transfer_priv->request.BufferLength = transfer->length;
610         transfer_priv->request.EndpointAddress = transfer->endpoint;
611
612         switch (transfer->type) {
613         case LIBUSB_TRANSFER_TYPE_BULK:
614                 transfer_priv->request.TransferType = BulkTransferType;
615                 break;
616         case LIBUSB_TRANSFER_TYPE_INTERRUPT:
617                 transfer_priv->request.TransferType = IntertuptTransferType;
618                 break;
619         default:
620                 usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer. %s", transfer->type, windows_error_str(0));
621                 return LIBUSB_ERROR_INVALID_PARAM;
622         }
623
624         transfer_priv->pollable_fd = INVALID_WINFD;
625
626         sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
627
628         wfd = usbi_create_fd(sysHandle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL);
629         // Always use the handle returned from usbi_create_fd (wfd.handle)
630         if (wfd.fd < 0)
631                 return LIBUSB_ERROR_NO_MEM;
632
633         if (IS_XFERIN(transfer))
634                 transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
635         else
636                 transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
637
638         switch (transferRes) {
639         case TransferSuccess:
640                 wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
641                 break;
642         case TransferSuccessAsync:
643                 break;
644         case TransferFailure:
645                 usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
646                 usbi_free_fd(&wfd);
647                 return LIBUSB_ERROR_IO;
648         }
649
650         transfer_priv->pollable_fd = wfd;
651         usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, IS_XFERIN(transfer) ? POLLIN : POLLOUT);
652
653         return LIBUSB_SUCCESS;
654 }
655
656 static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
657 {
658         struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
659         struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
660         struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
661         struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
662         struct winfd wfd;
663         TransferResult transferRes;
664         int i;
665         HANDLE sysHandle;
666
667         transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer;
668         transfer_priv->request.BufferLength = transfer->length;
669         transfer_priv->request.EndpointAddress = transfer->endpoint;
670         transfer_priv->request.TransferType = IsochronousTransferType;
671         transfer_priv->request.IsochronousPacketsArraySize = transfer->num_iso_packets;
672         transfer_priv->IsochronousPacketsArray = malloc(transfer->num_iso_packets * sizeof(ULONG64));
673         transfer_priv->request.IsochronousPacketsArray = (PVOID64)(uintptr_t)transfer_priv->IsochronousPacketsArray;
674         if (!transfer_priv->IsochronousPacketsArray) {
675                 usbi_err(ctx, "Allocation of IsochronousPacketsArray is failed, %s", windows_error_str(0));
676                 return LIBUSB_ERROR_IO;
677         }
678
679         transfer_priv->IsochronousResultsArray = malloc(transfer->num_iso_packets * sizeof(USB_DK_ISO_TRANSFER_RESULT));
680         transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)(uintptr_t)transfer_priv->IsochronousResultsArray;
681         if (!transfer_priv->IsochronousResultsArray) {
682                 usbi_err(ctx, "Allocation of isochronousResultsArray is failed, %s", windows_error_str(0));
683                 free(transfer_priv->IsochronousPacketsArray);
684                 return LIBUSB_ERROR_IO;
685         }
686
687         for (i = 0; i < transfer->num_iso_packets; i++)
688                 transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length;
689
690         transfer_priv->pollable_fd = INVALID_WINFD;
691
692         sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
693
694         wfd = usbi_create_fd(sysHandle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL);
695         // Always use the handle returned from usbi_create_fd (wfd.handle)
696         if (wfd.fd < 0) {
697                 free(transfer_priv->IsochronousPacketsArray);
698                 free(transfer_priv->IsochronousResultsArray);
699                 return LIBUSB_ERROR_NO_MEM;
700         }
701
702         if (IS_XFERIN(transfer))
703                 transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
704         else
705                 transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
706
707         switch (transferRes) {
708         case TransferSuccess:
709                 wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
710                 break;
711         case TransferSuccessAsync:
712                 break;
713         case TransferFailure:
714                 usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
715                 usbi_free_fd(&wfd);
716                 free(transfer_priv->IsochronousPacketsArray);
717                 free(transfer_priv->IsochronousResultsArray);
718                 return LIBUSB_ERROR_IO;
719         }
720
721         transfer_priv->pollable_fd = wfd;
722         usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, IS_XFERIN(transfer) ? POLLIN : POLLOUT);
723
724         return LIBUSB_SUCCESS;
725 }
726
727 static int usbdk_submit_transfer(struct usbi_transfer *itransfer)
728 {
729         struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
730
731         switch (transfer->type) {
732         case LIBUSB_TRANSFER_TYPE_CONTROL:
733                 return usbdk_do_control_transfer(itransfer);
734         case LIBUSB_TRANSFER_TYPE_BULK:
735         case LIBUSB_TRANSFER_TYPE_INTERRUPT:
736                 if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
737                         return LIBUSB_ERROR_NOT_SUPPORTED; //TODO: Check whether we can support this in UsbDk
738                 else
739                         return usbdk_do_bulk_transfer(itransfer);
740         case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
741                 return usbdk_do_iso_transfer(itransfer);
742         default:
743                 usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
744                 return LIBUSB_ERROR_INVALID_PARAM;
745         }
746 }
747
748 static int usbdk_abort_transfers(struct usbi_transfer *itransfer)
749 {
750         struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
751         struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
752         struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
753
754         if (!usbdk_helper.AbortPipe(priv->redirector_handle, transfer->endpoint)) {
755                 usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0));
756                 return LIBUSB_ERROR_NO_DEVICE;
757         }
758
759         return LIBUSB_SUCCESS;
760 }
761
762 static int usbdk_cancel_transfer(struct usbi_transfer *itransfer)
763 {
764         struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
765
766         switch (transfer->type) {
767         case LIBUSB_TRANSFER_TYPE_CONTROL:
768                 // Control transfers cancelled by IoCancelXXX() API
769                 // No special treatment needed
770                 return LIBUSB_SUCCESS;
771         case LIBUSB_TRANSFER_TYPE_BULK:
772         case LIBUSB_TRANSFER_TYPE_INTERRUPT:
773         case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
774                 return usbdk_abort_transfers(itransfer);
775         default:
776                 usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
777                 return LIBUSB_ERROR_INVALID_PARAM;
778         }
779 }
780
781 int windows_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
782 {
783         itransfer->transferred += io_size;
784         return LIBUSB_TRANSFER_COMPLETED;
785 }
786
787 struct winfd *windows_get_fd(struct usbi_transfer *transfer)
788 {
789         struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer);
790         return &transfer_priv->pollable_fd;
791 }
792
793 static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus)
794 {
795         if (USBD_SUCCESS(UsbdStatus))
796                 return NO_ERROR;
797
798         switch (UsbdStatus) {
799         case USBD_STATUS_TIMEOUT:
800                 return ERROR_SEM_TIMEOUT;
801         case USBD_STATUS_CANCELED:
802                 return ERROR_OPERATION_ABORTED;
803         default:
804                 return ERROR_GEN_FAILURE;
805         }
806 }
807
808 void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size)
809 {
810         if (HasOverlappedIoCompletedSync(pollable_fd->overlapped) // Handle async requests that completed synchronously first
811                         || GetOverlappedResult(pollable_fd->handle, pollable_fd->overlapped, io_size, false)) { // Regular async overlapped
812                 struct libusb_transfer *ltransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer);
813                 struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer);
814
815                 if (ltransfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
816                         int i;
817                         for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) {
818                                 struct libusb_iso_packet_descriptor *lib_desc = &ltransfer->iso_packet_desc[i];
819
820                                 switch (transfer_priv->IsochronousResultsArray[i].TransferResult) {
821                                 case STATUS_SUCCESS:
822                                 case STATUS_CANCELLED:
823                                 case STATUS_REQUEST_CANCELED:
824                                         lib_desc->status = LIBUSB_TRANSFER_COMPLETED; // == ERROR_SUCCESS
825                                         break;
826                                 default:
827                                         lib_desc->status = LIBUSB_TRANSFER_ERROR; // ERROR_UNKNOWN_EXCEPTION;
828                                         break;
829                                 }
830
831                                 lib_desc->actual_length = (unsigned int)transfer_priv->IsochronousResultsArray[i].ActualLength;
832                         }
833                 }
834
835                 *io_size = (DWORD) transfer_priv->request.Result.GenResult.BytesTransferred;
836                 *io_result = usbdk_translate_usbd_status((USBD_STATUS) transfer_priv->request.Result.GenResult.UsbdStatus);
837         }
838         else {
839                 *io_result = GetLastError();
840         }
841 }
842
843 static int usbdk_clock_gettime(int clk_id, struct timespec *tp)
844 {
845         return windows_clock_gettime(clk_id, tp);
846 }
847
848 const struct usbi_os_backend usbi_backend = {
849         "Windows",
850         USBI_CAP_HAS_HID_ACCESS,
851         usbdk_init,
852         usbdk_exit,
853
854         usbdk_get_device_list,
855         NULL,
856         usbdk_open,
857         usbdk_close,
858
859         usbdk_get_device_descriptor,
860         usbdk_get_active_config_descriptor,
861         usbdk_get_config_descriptor,
862         NULL,
863
864         usbdk_get_configuration,
865         usbdk_set_configuration,
866         usbdk_claim_interface,
867         usbdk_release_interface,
868
869         usbdk_set_interface_altsetting,
870         usbdk_clear_halt,
871         usbdk_reset_device,
872
873         NULL,
874         NULL,
875
876         NULL,   // dev_mem_alloc()
877         NULL,   // dev_mem_free()
878
879         usbdk_kernel_driver_active,
880         usbdk_detach_kernel_driver,
881         usbdk_attach_kernel_driver,
882
883         usbdk_destroy_device,
884
885         usbdk_submit_transfer,
886         usbdk_cancel_transfer,
887         windows_clear_transfer_priv,
888
889         windows_handle_events,
890         NULL,
891
892         usbdk_clock_gettime,
893 #if defined(USBI_TIMERFD_AVAILABLE)
894         NULL,
895 #endif
896         sizeof(struct usbdk_device_priv),
897         0,
898         sizeof(struct usbdk_transfer_priv),
899 };
900
901 #endif /* USE_USBDK */