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 struct {
47 HMODULE module;
48
49 USBDK_GET_DEVICES_LIST GetDevicesList;
50 USBDK_RELEASE_DEVICES_LIST ReleaseDevicesList;
51 USBDK_START_REDIRECT StartRedirect;
52 USBDK_STOP_REDIRECT StopRedirect;
53 USBDK_GET_CONFIGURATION_DESCRIPTOR GetConfigurationDescriptor;
54 USBDK_RELEASE_CONFIGURATION_DESCRIPTOR ReleaseConfigurationDescriptor;
55 USBDK_READ_PIPE ReadPipe;
56 USBDK_WRITE_PIPE WritePipe;
57 USBDK_ABORT_PIPE AbortPipe;
58 USBDK_RESET_PIPE ResetPipe;
59 USBDK_SET_ALTSETTING SetAltsetting;
60 USBDK_RESET_DEVICE ResetDevice;
61 USBDK_GET_REDIRECTOR_SYSTEM_HANDLE GetRedirectorSystemHandle;
62 } usbdk_helper;
63
get_usbdk_proc_addr(struct libusb_context * ctx,LPCSTR api_name)64 static FARPROC get_usbdk_proc_addr(struct libusb_context *ctx, LPCSTR api_name)
65 {
66 FARPROC api_ptr = GetProcAddress(usbdk_helper.module, api_name);
67
68 if (api_ptr == NULL)
69 usbi_err(ctx, "UsbDkHelper API %s not found: %s", api_name, windows_error_str(0));
70
71 return api_ptr;
72 }
73
unload_usbdk_helper_dll(void)74 static void unload_usbdk_helper_dll(void)
75 {
76 if (usbdk_helper.module != NULL) {
77 FreeLibrary(usbdk_helper.module);
78 usbdk_helper.module = NULL;
79 }
80 }
81
load_usbdk_helper_dll(struct libusb_context * ctx)82 static int load_usbdk_helper_dll(struct libusb_context *ctx)
83 {
84 usbdk_helper.module = load_system_library(ctx, "UsbDkHelper");
85 if (usbdk_helper.module == NULL) {
86 usbi_err(ctx, "Failed to load UsbDkHelper.dll: %s", windows_error_str(0));
87 return LIBUSB_ERROR_NOT_FOUND;
88 }
89
90 usbdk_helper.GetDevicesList = (USBDK_GET_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_GetDevicesList");
91 if (usbdk_helper.GetDevicesList == NULL)
92 goto error_unload;
93
94 usbdk_helper.ReleaseDevicesList = (USBDK_RELEASE_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseDevicesList");
95 if (usbdk_helper.ReleaseDevicesList == NULL)
96 goto error_unload;
97
98 usbdk_helper.StartRedirect = (USBDK_START_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StartRedirect");
99 if (usbdk_helper.StartRedirect == NULL)
100 goto error_unload;
101
102 usbdk_helper.StopRedirect = (USBDK_STOP_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StopRedirect");
103 if (usbdk_helper.StopRedirect == NULL)
104 goto error_unload;
105
106 usbdk_helper.GetConfigurationDescriptor = (USBDK_GET_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_GetConfigurationDescriptor");
107 if (usbdk_helper.GetConfigurationDescriptor == NULL)
108 goto error_unload;
109
110 usbdk_helper.ReleaseConfigurationDescriptor = (USBDK_RELEASE_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseConfigurationDescriptor");
111 if (usbdk_helper.ReleaseConfigurationDescriptor == NULL)
112 goto error_unload;
113
114 usbdk_helper.ReadPipe = (USBDK_READ_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ReadPipe");
115 if (usbdk_helper.ReadPipe == NULL)
116 goto error_unload;
117
118 usbdk_helper.WritePipe = (USBDK_WRITE_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_WritePipe");
119 if (usbdk_helper.WritePipe == NULL)
120 goto error_unload;
121
122 usbdk_helper.AbortPipe = (USBDK_ABORT_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_AbortPipe");
123 if (usbdk_helper.AbortPipe == NULL)
124 goto error_unload;
125
126 usbdk_helper.ResetPipe = (USBDK_RESET_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ResetPipe");
127 if (usbdk_helper.ResetPipe == NULL)
128 goto error_unload;
129
130 usbdk_helper.SetAltsetting = (USBDK_SET_ALTSETTING)get_usbdk_proc_addr(ctx, "UsbDk_SetAltsetting");
131 if (usbdk_helper.SetAltsetting == NULL)
132 goto error_unload;
133
134 usbdk_helper.ResetDevice = (USBDK_RESET_DEVICE)get_usbdk_proc_addr(ctx, "UsbDk_ResetDevice");
135 if (usbdk_helper.ResetDevice == NULL)
136 goto error_unload;
137
138 usbdk_helper.GetRedirectorSystemHandle = (USBDK_GET_REDIRECTOR_SYSTEM_HANDLE)get_usbdk_proc_addr(ctx, "UsbDk_GetRedirectorSystemHandle");
139 if (usbdk_helper.GetRedirectorSystemHandle == NULL)
140 goto error_unload;
141
142 return LIBUSB_SUCCESS;
143
144 error_unload:
145 FreeLibrary(usbdk_helper.module);
146 usbdk_helper.module = NULL;
147 return LIBUSB_ERROR_NOT_FOUND;
148 }
149
150 typedef SC_HANDLE (WINAPI *POPENSCMANAGERA)(LPCSTR, LPCSTR, DWORD);
151 typedef SC_HANDLE (WINAPI *POPENSERVICEA)(SC_HANDLE, LPCSTR, DWORD);
152 typedef BOOL (WINAPI *PCLOSESERVICEHANDLE)(SC_HANDLE);
153
usbdk_init(struct libusb_context * ctx)154 static int usbdk_init(struct libusb_context *ctx)
155 {
156 POPENSCMANAGERA pOpenSCManagerA;
157 POPENSERVICEA pOpenServiceA;
158 PCLOSESERVICEHANDLE pCloseServiceHandle;
159 SC_HANDLE managerHandle;
160 SC_HANDLE serviceHandle;
161 HMODULE h;
162
163 h = load_system_library(ctx, "Advapi32");
164 if (h == NULL) {
165 usbi_warn(ctx, "failed to open Advapi32\n");
166 return LIBUSB_ERROR_OTHER;
167 }
168
169 pOpenSCManagerA = (POPENSCMANAGERA)GetProcAddress(h, "OpenSCManagerA");
170 if (pOpenSCManagerA == NULL) {
171 usbi_warn(ctx, "failed to find %s in Advapi32\n", "OpenSCManagerA");
172 goto error_free_library;
173 }
174 pOpenServiceA = (POPENSERVICEA)GetProcAddress(h, "OpenServiceA");
175 if (pOpenServiceA == NULL) {
176 usbi_warn(ctx, "failed to find %s in Advapi32\n", "OpenServiceA");
177 goto error_free_library;
178 }
179 pCloseServiceHandle = (PCLOSESERVICEHANDLE)GetProcAddress(h, "CloseServiceHandle");
180 if (pCloseServiceHandle == NULL) {
181 usbi_warn(ctx, "failed to find %s in Advapi32\n", "CloseServiceHandle");
182 goto error_free_library;
183 }
184
185 managerHandle = pOpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
186 if (managerHandle == NULL) {
187 usbi_warn(ctx, "failed to open service control manager: %s", windows_error_str(0));
188 goto error_free_library;
189 }
190
191 serviceHandle = pOpenServiceA(managerHandle, "UsbDk", GENERIC_READ);
192 pCloseServiceHandle(managerHandle);
193
194 if (serviceHandle == NULL) {
195 if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
196 usbi_warn(ctx, "failed to open UsbDk service: %s", windows_error_str(0));
197 FreeLibrary(h);
198 return LIBUSB_ERROR_NOT_FOUND;
199 }
200
201 pCloseServiceHandle(serviceHandle);
202 FreeLibrary(h);
203
204 return load_usbdk_helper_dll(ctx);
205
206 error_free_library:
207 FreeLibrary(h);
208 return LIBUSB_ERROR_OTHER;
209 }
210
usbdk_exit(struct libusb_context * ctx)211 static void usbdk_exit(struct libusb_context *ctx)
212 {
213 UNUSED(ctx);
214 unload_usbdk_helper_dll();
215 }
216
usbdk_get_session_id_for_device(struct libusb_context * ctx,PUSB_DK_DEVICE_ID id,unsigned long * session_id)217 static int usbdk_get_session_id_for_device(struct libusb_context *ctx,
218 PUSB_DK_DEVICE_ID id, unsigned long *session_id)
219 {
220 char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID) + 1];
221
222 if (snprintf(dev_identity, sizeof(dev_identity), "%S%S", id->DeviceID, id->InstanceID) == -1) {
223 usbi_warn(ctx, "cannot form device identity");
224 return LIBUSB_ERROR_NOT_SUPPORTED;
225 }
226
227 *session_id = htab_hash(dev_identity);
228
229 return LIBUSB_SUCCESS;
230 }
231
usbdk_release_config_descriptors(struct usbdk_device_priv * priv,uint8_t count)232 static void usbdk_release_config_descriptors(struct usbdk_device_priv *priv, uint8_t count)
233 {
234 uint8_t i;
235
236 for (i = 0; i < count; i++)
237 usbdk_helper.ReleaseConfigurationDescriptor(priv->config_descriptors[i]);
238
239 free(priv->config_descriptors);
240 priv->config_descriptors = NULL;
241 }
242
usbdk_cache_config_descriptors(struct libusb_context * ctx,struct usbdk_device_priv * priv,PUSB_DK_DEVICE_INFO info)243 static int usbdk_cache_config_descriptors(struct libusb_context *ctx,
244 struct usbdk_device_priv *priv, PUSB_DK_DEVICE_INFO info)
245 {
246 uint8_t i;
247 USB_DK_CONFIG_DESCRIPTOR_REQUEST Request;
248 Request.ID = info->ID;
249
250 priv->config_descriptors = calloc(info->DeviceDescriptor.bNumConfigurations, sizeof(PUSB_CONFIGURATION_DESCRIPTOR));
251 if (priv->config_descriptors == NULL) {
252 usbi_err(ctx, "failed to allocate configuration descriptors holder");
253 return LIBUSB_ERROR_NO_MEM;
254 }
255
256 for (i = 0; i < info->DeviceDescriptor.bNumConfigurations; i++) {
257 ULONG Length;
258
259 Request.Index = i;
260 if (!usbdk_helper.GetConfigurationDescriptor(&Request, &priv->config_descriptors[i], &Length)) {
261 usbi_err(ctx, "failed to retrieve configuration descriptors");
262 usbdk_release_config_descriptors(priv, i);
263 return LIBUSB_ERROR_OTHER;
264 }
265 }
266
267 return LIBUSB_SUCCESS;
268 }
269
usbdk_device_priv_init(struct libusb_context * ctx,struct libusb_device * dev,PUSB_DK_DEVICE_INFO info)270 static inline int usbdk_device_priv_init(struct libusb_context *ctx, struct libusb_device *dev, PUSB_DK_DEVICE_INFO info)
271 {
272 struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
273
274 priv->ID = info->ID;
275 priv->active_configuration = 0;
276
277 return usbdk_cache_config_descriptors(ctx, priv, info);
278 }
279
usbdk_device_init(struct libusb_device * dev,PUSB_DK_DEVICE_INFO info)280 static void usbdk_device_init(struct libusb_device *dev, PUSB_DK_DEVICE_INFO info)
281 {
282 dev->bus_number = (uint8_t)info->FilterID;
283 dev->port_number = (uint8_t)info->Port;
284 dev->parent_dev = NULL;
285
286 // Addresses in libusb are 1-based
287 dev->device_address = (uint8_t)(info->Port + 1);
288
289 static_assert(sizeof(dev->device_descriptor) == sizeof(info->DeviceDescriptor),
290 "mismatch between libusb and OS device descriptor sizes");
291 memcpy(&dev->device_descriptor, &info->DeviceDescriptor, LIBUSB_DT_DEVICE_SIZE);
292 usbi_localize_device_descriptor(&dev->device_descriptor);
293
294 switch (info->Speed) {
295 case LowSpeed:
296 dev->speed = LIBUSB_SPEED_LOW;
297 break;
298 case FullSpeed:
299 dev->speed = LIBUSB_SPEED_FULL;
300 break;
301 case HighSpeed:
302 dev->speed = LIBUSB_SPEED_HIGH;
303 break;
304 case SuperSpeed:
305 dev->speed = LIBUSB_SPEED_SUPER;
306 break;
307 case NoSpeed:
308 default:
309 dev->speed = LIBUSB_SPEED_UNKNOWN;
310 break;
311 }
312 }
313
usbdk_get_device_list(struct libusb_context * ctx,struct discovered_devs ** _discdevs)314 static int usbdk_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
315 {
316 int r = LIBUSB_SUCCESS;
317 ULONG i;
318 struct discovered_devs *discdevs = NULL;
319 ULONG dev_number;
320 PUSB_DK_DEVICE_INFO devices;
321
322 if (!usbdk_helper.GetDevicesList(&devices, &dev_number))
323 return LIBUSB_ERROR_OTHER;
324
325 for (i = 0; i < dev_number; i++) {
326 unsigned long session_id;
327 struct libusb_device *dev = NULL;
328
329 if (usbdk_get_session_id_for_device(ctx, &devices[i].ID, &session_id))
330 continue;
331
332 dev = usbi_get_device_by_session_id(ctx, session_id);
333 if (dev == NULL) {
334 dev = usbi_alloc_device(ctx, session_id);
335 if (dev == NULL) {
336 usbi_err(ctx, "failed to allocate a new device structure");
337 continue;
338 }
339
340 usbdk_device_init(dev, &devices[i]);
341 if (usbdk_device_priv_init(ctx, dev, &devices[i]) != LIBUSB_SUCCESS) {
342 libusb_unref_device(dev);
343 continue;
344 }
345 }
346
347 discdevs = discovered_devs_append(*_discdevs, dev);
348 libusb_unref_device(dev);
349 if (!discdevs) {
350 usbi_err(ctx, "cannot append new device to list");
351 r = LIBUSB_ERROR_NO_MEM;
352 goto func_exit;
353 }
354
355 *_discdevs = discdevs;
356 }
357
358 func_exit:
359 usbdk_helper.ReleaseDevicesList(devices);
360 return r;
361 }
362
usbdk_get_config_descriptor(struct libusb_device * dev,uint8_t config_index,void * buffer,size_t len)363 static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, void *buffer, size_t len)
364 {
365 struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
366 PUSB_CONFIGURATION_DESCRIPTOR config_header;
367 size_t size;
368
369 config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptors[config_index];
370
371 size = min(config_header->wTotalLength, len);
372 memcpy(buffer, config_header, size);
373 return (int)size;
374 }
375
usbdk_get_config_descriptor_by_value(struct libusb_device * dev,uint8_t bConfigurationValue,void ** buffer)376 static int usbdk_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue,
377 void **buffer)
378 {
379 struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
380 PUSB_CONFIGURATION_DESCRIPTOR config_header;
381 uint8_t index;
382
383 for (index = 0; index < dev->device_descriptor.bNumConfigurations; index++) {
384 config_header = priv->config_descriptors[index];
385 if (config_header->bConfigurationValue == bConfigurationValue) {
386 *buffer = priv->config_descriptors[index];
387 return (int)config_header->wTotalLength;
388 }
389 }
390
391 return LIBUSB_ERROR_NOT_FOUND;
392 }
393
usbdk_get_active_config_descriptor(struct libusb_device * dev,void * buffer,size_t len)394 static int usbdk_get_active_config_descriptor(struct libusb_device *dev, void *buffer, size_t len)
395 {
396 struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
397
398 return usbdk_get_config_descriptor(dev, priv->active_configuration, buffer, len);
399 }
400
usbdk_open(struct libusb_device_handle * dev_handle)401 static int usbdk_open(struct libusb_device_handle *dev_handle)
402 {
403 struct libusb_device *dev = dev_handle->dev;
404 struct libusb_context *ctx = DEVICE_CTX(dev);
405 struct windows_context_priv *priv = usbi_get_context_priv(ctx);
406 struct usbdk_device_priv *device_priv = usbi_get_device_priv(dev);
407
408 device_priv->redirector_handle = usbdk_helper.StartRedirect(&device_priv->ID);
409 if (device_priv->redirector_handle == INVALID_HANDLE_VALUE) {
410 usbi_err(ctx, "Redirector startup failed");
411 device_priv->redirector_handle = NULL;
412 return LIBUSB_ERROR_OTHER;
413 }
414
415 device_priv->system_handle = usbdk_helper.GetRedirectorSystemHandle(device_priv->redirector_handle);
416
417 if (CreateIoCompletionPort(device_priv->system_handle, priv->completion_port, 0, 0) == NULL) {
418 usbi_err(ctx, "failed to associate handle to I/O completion port: %s", windows_error_str(0));
419 usbdk_helper.StopRedirect(device_priv->redirector_handle);
420 device_priv->system_handle = NULL;
421 device_priv->redirector_handle = NULL;
422 return LIBUSB_ERROR_OTHER;
423 }
424
425 return LIBUSB_SUCCESS;
426 }
427
usbdk_close(struct libusb_device_handle * dev_handle)428 static void usbdk_close(struct libusb_device_handle *dev_handle)
429 {
430 struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
431
432 if (!usbdk_helper.StopRedirect(priv->redirector_handle))
433 usbi_err(HANDLE_CTX(dev_handle), "Redirector shutdown failed");
434
435 priv->system_handle = NULL;
436 priv->redirector_handle = NULL;
437 }
438
usbdk_get_configuration(struct libusb_device_handle * dev_handle,uint8_t * config)439 static int usbdk_get_configuration(struct libusb_device_handle *dev_handle, uint8_t *config)
440 {
441 struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
442
443 *config = priv->active_configuration;
444
445 return LIBUSB_SUCCESS;
446 }
447
usbdk_set_configuration(struct libusb_device_handle * dev_handle,uint8_t config)448 static int usbdk_set_configuration(struct libusb_device_handle *dev_handle, uint8_t config)
449 {
450 UNUSED(dev_handle);
451 UNUSED(config);
452 return LIBUSB_SUCCESS;
453 }
454
usbdk_claim_interface(struct libusb_device_handle * dev_handle,uint8_t iface)455 static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, uint8_t iface)
456 {
457 UNUSED(dev_handle);
458 UNUSED(iface);
459 return LIBUSB_SUCCESS;
460 }
461
usbdk_set_interface_altsetting(struct libusb_device_handle * dev_handle,uint8_t iface,uint8_t altsetting)462 static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting)
463 {
464 struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
465
466 if (!usbdk_helper.SetAltsetting(priv->redirector_handle, iface, altsetting)) {
467 usbi_err(HANDLE_CTX(dev_handle), "SetAltsetting failed: %s", windows_error_str(0));
468 return LIBUSB_ERROR_NO_DEVICE;
469 }
470
471 return LIBUSB_SUCCESS;
472 }
473
usbdk_release_interface(struct libusb_device_handle * dev_handle,uint8_t iface)474 static int usbdk_release_interface(struct libusb_device_handle *dev_handle, uint8_t iface)
475 {
476 UNUSED(dev_handle);
477 UNUSED(iface);
478 return LIBUSB_SUCCESS;
479 }
480
usbdk_clear_halt(struct libusb_device_handle * dev_handle,unsigned char endpoint)481 static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
482 {
483 struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
484
485 if (!usbdk_helper.ResetPipe(priv->redirector_handle, endpoint)) {
486 usbi_err(HANDLE_CTX(dev_handle), "ResetPipe failed: %s", windows_error_str(0));
487 return LIBUSB_ERROR_NO_DEVICE;
488 }
489
490 return LIBUSB_SUCCESS;
491 }
492
usbdk_reset_device(struct libusb_device_handle * dev_handle)493 static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
494 {
495 struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
496
497 if (!usbdk_helper.ResetDevice(priv->redirector_handle)) {
498 usbi_err(HANDLE_CTX(dev_handle), "ResetDevice failed: %s", windows_error_str(0));
499 return LIBUSB_ERROR_NO_DEVICE;
500 }
501
502 return LIBUSB_SUCCESS;
503 }
504
usbdk_destroy_device(struct libusb_device * dev)505 static void usbdk_destroy_device(struct libusb_device *dev)
506 {
507 struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
508
509 if (priv->config_descriptors != NULL)
510 usbdk_release_config_descriptors(priv, dev->device_descriptor.bNumConfigurations);
511 }
512
usbdk_clear_transfer_priv(struct usbi_transfer * itransfer)513 static void usbdk_clear_transfer_priv(struct usbi_transfer *itransfer)
514 {
515 struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
516 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
517
518 if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
519 safe_free(transfer_priv->IsochronousPacketsArray);
520 safe_free(transfer_priv->IsochronousResultsArray);
521 }
522 }
523
usbdk_do_control_transfer(struct usbi_transfer * itransfer)524 static int usbdk_do_control_transfer(struct usbi_transfer *itransfer)
525 {
526 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
527 struct usbdk_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
528 struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
529 OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer);
530 TransferResult transResult;
531
532 transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
533 transfer_priv->request.BufferLength = transfer->length;
534 transfer_priv->request.TransferType = ControlTransferType;
535
536 set_transfer_priv_handle(itransfer, priv->system_handle);
537
538 if (transfer->buffer[0] & LIBUSB_ENDPOINT_IN)
539 transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
540 else
541 transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
542
543 switch (transResult) {
544 case TransferSuccess:
545 windows_force_sync_completion(itransfer, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
546 break;
547 case TransferSuccessAsync:
548 break;
549 case TransferFailure:
550 usbi_err(TRANSFER_CTX(transfer), "ControlTransfer failed: %s", windows_error_str(0));
551 return LIBUSB_ERROR_IO;
552 }
553
554 return LIBUSB_SUCCESS;
555 }
556
usbdk_do_bulk_transfer(struct usbi_transfer * itransfer)557 static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
558 {
559 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
560 struct usbdk_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
561 struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
562 OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer);
563 TransferResult transferRes;
564
565 transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
566 transfer_priv->request.BufferLength = transfer->length;
567 transfer_priv->request.EndpointAddress = transfer->endpoint;
568
569 switch (transfer->type) {
570 case LIBUSB_TRANSFER_TYPE_BULK:
571 transfer_priv->request.TransferType = BulkTransferType;
572 break;
573 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
574 transfer_priv->request.TransferType = InterruptTransferType;
575 break;
576 }
577
578 set_transfer_priv_handle(itransfer, priv->system_handle);
579
580 if (IS_XFERIN(transfer))
581 transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
582 else
583 transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
584
585 switch (transferRes) {
586 case TransferSuccess:
587 windows_force_sync_completion(itransfer, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
588 break;
589 case TransferSuccessAsync:
590 break;
591 case TransferFailure:
592 usbi_err(TRANSFER_CTX(transfer), "ReadPipe/WritePipe failed: %s", windows_error_str(0));
593 return LIBUSB_ERROR_IO;
594 }
595
596 return LIBUSB_SUCCESS;
597 }
598
usbdk_do_iso_transfer(struct usbi_transfer * itransfer)599 static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
600 {
601 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
602 struct usbdk_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
603 struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
604 OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer);
605 TransferResult transferRes;
606 int i;
607
608 transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
609 transfer_priv->request.BufferLength = transfer->length;
610 transfer_priv->request.EndpointAddress = transfer->endpoint;
611 transfer_priv->request.TransferType = IsochronousTransferType;
612 transfer_priv->request.IsochronousPacketsArraySize = transfer->num_iso_packets;
613 transfer_priv->IsochronousPacketsArray = malloc(transfer->num_iso_packets * sizeof(ULONG64));
614 transfer_priv->request.IsochronousPacketsArray = (PVOID64)transfer_priv->IsochronousPacketsArray;
615 if (!transfer_priv->IsochronousPacketsArray) {
616 usbi_err(TRANSFER_CTX(transfer), "Allocation of IsochronousPacketsArray failed");
617 return LIBUSB_ERROR_NO_MEM;
618 }
619
620 transfer_priv->IsochronousResultsArray = malloc(transfer->num_iso_packets * sizeof(USB_DK_ISO_TRANSFER_RESULT));
621 transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)transfer_priv->IsochronousResultsArray;
622 if (!transfer_priv->IsochronousResultsArray) {
623 usbi_err(TRANSFER_CTX(transfer), "Allocation of isochronousResultsArray failed");
624 return LIBUSB_ERROR_NO_MEM;
625 }
626
627 for (i = 0; i < transfer->num_iso_packets; i++)
628 transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length;
629
630 set_transfer_priv_handle(itransfer, priv->system_handle);
631
632 if (IS_XFERIN(transfer))
633 transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
634 else
635 transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
636
637 switch (transferRes) {
638 case TransferSuccess:
639 windows_force_sync_completion(itransfer, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
640 break;
641 case TransferSuccessAsync:
642 break;
643 case TransferFailure:
644 return LIBUSB_ERROR_IO;
645 }
646
647 return LIBUSB_SUCCESS;
648 }
649
usbdk_submit_transfer(struct usbi_transfer * itransfer)650 static int usbdk_submit_transfer(struct usbi_transfer *itransfer)
651 {
652 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
653
654 switch (transfer->type) {
655 case LIBUSB_TRANSFER_TYPE_CONTROL:
656 return usbdk_do_control_transfer(itransfer);
657 case LIBUSB_TRANSFER_TYPE_BULK:
658 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
659 if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
660 return LIBUSB_ERROR_NOT_SUPPORTED; //TODO: Check whether we can support this in UsbDk
661 return usbdk_do_bulk_transfer(itransfer);
662 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
663 return usbdk_do_iso_transfer(itransfer);
664 default:
665 // Should not get here since windows_submit_transfer() validates
666 // the transfer->type field
667 usbi_err(TRANSFER_CTX(transfer), "unsupported endpoint type %d", transfer->type);
668 return LIBUSB_ERROR_NOT_SUPPORTED;
669 }
670 }
671
usbdk_copy_transfer_data(struct usbi_transfer * itransfer,DWORD length)672 static enum libusb_transfer_status usbdk_copy_transfer_data(struct usbi_transfer *itransfer, DWORD length)
673 {
674 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
675 struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
676
677 UNUSED(length);
678
679 if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
680 ULONG64 i;
681
682 for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) {
683 struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i];
684
685 switch (transfer_priv->IsochronousResultsArray[i].TransferResult) {
686 case STATUS_SUCCESS:
687 case STATUS_CANCELLED:
688 case STATUS_REQUEST_CANCELED:
689 lib_desc->status = LIBUSB_TRANSFER_COMPLETED; // == ERROR_SUCCESS
690 break;
691 default:
692 lib_desc->status = LIBUSB_TRANSFER_ERROR; // ERROR_UNKNOWN_EXCEPTION;
693 break;
694 }
695
696 lib_desc->actual_length = (unsigned int)transfer_priv->IsochronousResultsArray[i].ActualLength;
697 }
698 }
699
700 itransfer->transferred += (int)transfer_priv->request.Result.GenResult.BytesTransferred;
701 return usbd_status_to_libusb_transfer_status((USBD_STATUS)transfer_priv->request.Result.GenResult.UsbdStatus);
702 }
703
704 const struct windows_backend usbdk_backend = {
705 usbdk_init,
706 usbdk_exit,
707 usbdk_get_device_list,
708 usbdk_open,
709 usbdk_close,
710 usbdk_get_active_config_descriptor,
711 usbdk_get_config_descriptor,
712 usbdk_get_config_descriptor_by_value,
713 usbdk_get_configuration,
714 usbdk_set_configuration,
715 usbdk_claim_interface,
716 usbdk_release_interface,
717 usbdk_set_interface_altsetting,
718 usbdk_clear_halt,
719 usbdk_reset_device,
720 usbdk_destroy_device,
721 usbdk_submit_transfer,
722 NULL, /* cancel_transfer */
723 usbdk_clear_transfer_priv,
724 usbdk_copy_transfer_data,
725 };
726