xref: /aosp_15_r20/external/libusb/libusb/os/windows_usbdk.c (revision 86b64dcb59b3a0b37502ecd56e119234366a6f7e)
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