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