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