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