1ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/*
2ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Windows CE backend for libusbx 1.0
3ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Copyright © 2011-2013 RealVNC Ltd.
4ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Large portions taken from Windows backend, which is
5ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Copyright © 2009-2010 Pete Batard <pbatard@gmail.com>
6ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * With contributions from Michael Plante, Orin Eman et al.
7ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
8ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Major code testing contribution by Xiaofan Chen
9ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *
10ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * This library is free software; you can redistribute it and/or
11ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * modify it under the terms of the GNU Lesser General Public
12ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * License as published by the Free Software Foundation; either
13ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * version 2.1 of the License, or (at your option) any later version.
14ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *
15ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * This library is distributed in the hope that it will be useful,
16ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * but WITHOUT ANY WARRANTY; without even the implied warranty of
17ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Lesser General Public License for more details.
19ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *
20ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * You should have received a copy of the GNU Lesser General Public
21ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * License along with this library; if not, write to the Free Software
22ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch */
24ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
25ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include <libusbi.h>
26ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
27ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include <stdint.h>
28ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include <errno.h>
29ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include <inttypes.h>
30ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
31ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "wince_usb.h"
32ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
33ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Forward declares
34ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_clock_gettime(int clk_id, struct timespec *tp);
35ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochunsigned __stdcall wince_clock_gettime_threaded(void* param);
36ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
37ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Global variables
38ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochuint64_t hires_frequency, hires_ticks_to_ps;
39ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochint errno;
40ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochconst uint64_t epoch_time = UINT64_C(116444736000000000);       // 1970.01.01 00:00:000 in MS Filetime
41ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochenum windows_version windows_version = WINDOWS_CE;
42ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int concurrent_usage = -1;
43ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Timer thread
44ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// NB: index 0 is for monotonic and 1 is for the thread exit event
45ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochHANDLE timer_thread = NULL;
46ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochHANDLE timer_mutex = NULL;
47ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstruct timespec timer_tp;
48ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvolatile LONG request_count[2] = {0, 1};	// last one must be > 0
49ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochHANDLE timer_request[2] = { NULL, NULL };
50ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochHANDLE timer_response = NULL;
51ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochHANDLE driver_handle = INVALID_HANDLE_VALUE;
52ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
53ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/*
54ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Converts a windows error to human readable string
55ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * uses retval as errorcode, or, if 0, use GetLastError()
56ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch */
57ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#if defined(ENABLE_LOGGING)
58ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic char* windows_error_str(uint32_t retval)
59ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
60ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	static TCHAR wErr_string[ERR_BUFFER_SIZE];
61ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	static char err_string[ERR_BUFFER_SIZE];
62ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
63ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DWORD size;
64ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	size_t i;
65ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	uint32_t error_code, format_error;
66ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
67ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	error_code = retval?retval:GetLastError();
68ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
69ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	safe_stprintf(wErr_string, ERR_BUFFER_SIZE, _T("[%d] "), error_code);
70ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
71ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code,
72ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &wErr_string[safe_tcslen(wErr_string)],
73ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		ERR_BUFFER_SIZE - (DWORD)safe_tcslen(wErr_string), NULL);
74ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (size == 0) {
75ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		format_error = GetLastError();
76ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (format_error)
77ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			safe_stprintf(wErr_string, ERR_BUFFER_SIZE,
78ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				_T("Windows error code %u (FormatMessage error code %u)"), error_code, format_error);
79ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		else
80ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			safe_stprintf(wErr_string, ERR_BUFFER_SIZE, _T("Unknown error code %u"), error_code);
81ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} else {
82ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// Remove CR/LF terminators
83ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		for (i=safe_tcslen(wErr_string)-1; ((wErr_string[i]==0x0A) || (wErr_string[i]==0x0D)); i--) {
84ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			wErr_string[i] = 0;
85ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
86ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
87ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (WideCharToMultiByte(CP_ACP, 0, wErr_string, -1, err_string, ERR_BUFFER_SIZE, NULL, NULL) < 0)
88ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	{
89ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		strcpy(err_string, "Unable to convert error string");
90ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
91ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return err_string;
92ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
93ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#endif
94ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
95ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic struct wince_device_priv *_device_priv(struct libusb_device *dev)
96ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
97ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        return (struct wince_device_priv *) dev->os_priv;
98ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
99ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
100ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// ceusbkwrapper to libusb error code mapping
101ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int translate_driver_error(int error)
102ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
103ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	switch (error) {
104ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		case ERROR_INVALID_PARAMETER:
105ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_INVALID_PARAM;
106ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		case ERROR_CALL_NOT_IMPLEMENTED:
107ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		case ERROR_NOT_SUPPORTED:
108ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_NOT_SUPPORTED;
109ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		case ERROR_NOT_ENOUGH_MEMORY:
110ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_NO_MEM;
111ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		case ERROR_INVALID_HANDLE:
112ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_NO_DEVICE;
113ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		case ERROR_BUSY:
114ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_BUSY;
115ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
116ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// Error codes that are either unexpected, or have
117ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// no suitable LIBUSB_ERROR equivilant.
118ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		case ERROR_CANCELLED:
119ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		case ERROR_INTERNAL_ERROR:
120ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		default:
121ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_OTHER;
122ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
123ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
124ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
125ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int init_dllimports()
126ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
127ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwOpenDriver, TRUE);
128ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwGetDeviceList, TRUE);
129ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwReleaseDeviceList, TRUE);
130ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwGetDeviceAddress, TRUE);
131ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwGetDeviceDescriptor, TRUE);
132ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwGetConfigDescriptor, TRUE);
133ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwCloseDriver, TRUE);
134ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwCancelTransfer, TRUE);
135ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwIssueControlTransfer, TRUE);
136ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwClaimInterface, TRUE);
137ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwReleaseInterface, TRUE);
138ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwSetInterfaceAlternateSetting, TRUE);
139ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwClearHaltHost, TRUE);
140ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwClearHaltDevice, TRUE);
141ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwGetConfig, TRUE);
142ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwSetConfig, TRUE);
143ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwResetDevice, TRUE);
144ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwKernelDriverActive, TRUE);
145ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwAttachKernelDriver, TRUE);
146ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwDetachKernelDriver, TRUE);
147ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwIssueBulkTransfer, TRUE);
148ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DLL_LOAD(ceusbkwrapper.dll, UkwIsPipeHalted, TRUE);
149ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
150ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
151ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
152ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int init_device(struct libusb_device *dev, UKW_DEVICE drv_dev,
153ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					   unsigned char bus_addr, unsigned char dev_addr)
154ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
155ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(dev);
156ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int r = LIBUSB_SUCCESS;
157ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
158ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	dev->bus_number = bus_addr;
159ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	dev->device_address = dev_addr;
160ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	priv->dev = drv_dev;
161ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
162ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!UkwGetDeviceDescriptor(priv->dev, &(priv->desc))) {
163ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		r = translate_driver_error(GetLastError());
164ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
165ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return r;
166ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
167ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
168ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Internal API functions
169ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_init(struct libusb_context *ctx)
170ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
171ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int i, r = LIBUSB_ERROR_OTHER;
172ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	HANDLE semaphore;
173ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	TCHAR sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID)
174ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
175ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	_stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)GetCurrentProcessId()&0xFFFFFFFF);
176ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	semaphore = CreateSemaphore(NULL, 1, 1, sem_name);
177ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (semaphore == NULL) {
178ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0));
179ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_ERROR_NO_MEM;
180ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
181ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
182ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// A successful wait brings our semaphore count to 0 (unsignaled)
183ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// => any concurent wait stalls until the semaphore's release
184ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
185ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0));
186ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		CloseHandle(semaphore);
187ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_ERROR_NO_MEM;
188ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
189ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
190ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// NB: concurrent usage supposes that init calls are equally balanced with
191ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// exit calls. If init is called more than exit, we will not exit properly
192ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if ( ++concurrent_usage == 0 ) {	// First init?
193ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// Initialize pollable file descriptors
194ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		init_polling();
195ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
196ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// Load DLL imports
197ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (init_dllimports() != LIBUSB_SUCCESS) {
198ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_err(ctx, "could not resolve DLL functions");
199ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			r = LIBUSB_ERROR_NOT_SUPPORTED;
200ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			goto init_exit;
201ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
202ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
203ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// try to open a handle to the driver
204ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		driver_handle = UkwOpenDriver();
205ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (driver_handle == INVALID_HANDLE_VALUE) {
206ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_err(ctx, "could not connect to driver");
207ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			r = LIBUSB_ERROR_NOT_SUPPORTED;
208ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			goto init_exit;
209ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
210ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
211ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// Windows CE doesn't have a way of specifying thread affinity, so this code
212ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// just has  to hope QueryPerformanceCounter doesn't report different values when
213ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// running on different cores.
214ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		r = LIBUSB_ERROR_NO_MEM;
215ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		for (i = 0; i < 2; i++) {
216ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			timer_request[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
217ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			if (timer_request[i] == NULL) {
218ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				usbi_err(ctx, "could not create timer request event %d - aborting", i);
219ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				goto init_exit;
220ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			}
221ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
222ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		timer_response = CreateSemaphore(NULL, 0, MAX_TIMER_SEMAPHORES, NULL);
223ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (timer_response == NULL) {
224ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_err(ctx, "could not create timer response semaphore - aborting");
225ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			goto init_exit;
226ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
227ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		timer_mutex = CreateMutex(NULL, FALSE, NULL);
228ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (timer_mutex == NULL) {
229ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_err(ctx, "could not create timer mutex - aborting");
230ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			goto init_exit;
231ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
232ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		timer_thread = CreateThread(NULL, 0, wince_clock_gettime_threaded, NULL, 0, NULL);
233ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (timer_thread == NULL) {
234ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_err(ctx, "Unable to create timer thread - aborting");
235ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			goto init_exit;
236ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
23768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
23868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		// Wait for timer thread to init before continuing.
23968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		if (WaitForSingleObject(timer_response, INFINITE) != WAIT_OBJECT_0) {
24068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			usbi_err(ctx, "Failed to wait for timer thread to become ready - aborting");
24168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			goto init_exit;
24268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		}
243ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
244ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// At this stage, either we went through full init successfully, or didn't need to
245ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	r = LIBUSB_SUCCESS;
246ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
247ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochinit_exit: // Holds semaphore here.
248ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed?
249ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (driver_handle != INVALID_HANDLE_VALUE) {
250ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			UkwCloseDriver(driver_handle);
251ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			driver_handle = INVALID_HANDLE_VALUE;
252ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
253ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (timer_thread) {
254ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			SetEvent(timer_request[1]); // actually the signal to quit the thread.
255ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) {
256ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				usbi_warn(ctx, "could not wait for timer thread to quit");
257ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				TerminateThread(timer_thread, 1); // shouldn't happen, but we're destroying
258ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch												  // all objects it might have held anyway.
259ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			}
260ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			CloseHandle(timer_thread);
261ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			timer_thread = NULL;
262ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
263ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		for (i = 0; i < 2; i++) {
264ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			if (timer_request[i]) {
265ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				CloseHandle(timer_request[i]);
266ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				timer_request[i] = NULL;
267ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			}
268ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
269ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (timer_response) {
270ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			CloseHandle(timer_response);
271ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			timer_response = NULL;
272ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
273ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (timer_mutex) {
274ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			CloseHandle(timer_mutex);
275ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			timer_mutex = NULL;
276ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
277ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
278ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
279ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (r != LIBUSB_SUCCESS)
280ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		--concurrent_usage; // Not expected to call libusb_exit if we failed.
281ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
282ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	ReleaseSemaphore(semaphore, 1, NULL);	// increase count back to 1
283ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	CloseHandle(semaphore);
284ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return r;
285ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
286ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
287ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic void wince_exit(void)
288ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
289ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int i;
290ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	HANDLE semaphore;
291ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	TCHAR sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID)
292ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
293ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	_stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)GetCurrentProcessId()&0xFFFFFFFF);
294ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	semaphore = CreateSemaphore(NULL, 1, 1, sem_name);
295ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (semaphore == NULL) {
296ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return;
297ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
298ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
299ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// A successful wait brings our semaphore count to 0 (unsignaled)
300ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// => any concurent wait stalls until the semaphore release
301ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
302ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		CloseHandle(semaphore);
303ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return;
304ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
305ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
306ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// Only works if exits and inits are balanced exactly
307ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (--concurrent_usage < 0) {	// Last exit
308ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		exit_polling();
309ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
310ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (timer_thread) {
311ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			SetEvent(timer_request[1]); // actually the signal to quit the thread.
312ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) {
313ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				usbi_dbg("could not wait for timer thread to quit");
314ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				TerminateThread(timer_thread, 1);
315ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			}
316ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			CloseHandle(timer_thread);
317ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			timer_thread = NULL;
318ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
319ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		for (i = 0; i < 2; i++) {
320ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			if (timer_request[i]) {
321ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				CloseHandle(timer_request[i]);
322ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				timer_request[i] = NULL;
323ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			}
324ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
325ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (timer_response) {
326ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			CloseHandle(timer_response);
327ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			timer_response = NULL;
328ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
329ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (timer_mutex) {
330ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			CloseHandle(timer_mutex);
331ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			timer_mutex = NULL;
332ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
333ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (driver_handle != INVALID_HANDLE_VALUE) {
334ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			UkwCloseDriver(driver_handle);
335ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			driver_handle = INVALID_HANDLE_VALUE;
336ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
337ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
338ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
339ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	ReleaseSemaphore(semaphore, 1, NULL);	// increase count back to 1
340ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	CloseHandle(semaphore);
341ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
342ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
343ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_get_device_list(
344ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_context *ctx,
345ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct discovered_devs **discdevs)
346ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
347ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	UKW_DEVICE devices[MAX_DEVICE_COUNT];
348ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct discovered_devs * new_devices = *discdevs;
349ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DWORD count = 0, i;
350ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_device *dev = NULL;
351ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	unsigned char bus_addr, dev_addr;
352ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	unsigned long session_id;
353ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	BOOL success;
354ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DWORD release_list_offset = 0;
355ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int r = LIBUSB_SUCCESS;
356ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
357ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	success = UkwGetDeviceList(driver_handle, devices, MAX_DEVICE_COUNT, &count);
358ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!success) {
359ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		int libusbErr = translate_driver_error(GetLastError());
360ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_err(ctx, "could not get devices: %s", windows_error_str(0));
361ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return libusbErr;
362ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
363ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	for(i = 0; i < count; ++i) {
364ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		release_list_offset = i;
365ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		success = UkwGetDeviceAddress(devices[i], &bus_addr, &dev_addr, &session_id);
366ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (!success) {
367ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			r = translate_driver_error(GetLastError());
368ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_err(ctx, "could not get device address for %d: %s", i, windows_error_str(0));
369ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			goto err_out;
370ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
371ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		dev = usbi_get_device_by_session_id(ctx, session_id);
372ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (dev) {
373ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_dbg("using existing device for %d/%d (session %ld)",
374ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					bus_addr, dev_addr, session_id);
375ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			libusb_ref_device(dev);
376ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			// Release just this element in the device list (as we already hold a
377ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			// reference to it).
378ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			UkwReleaseDeviceList(driver_handle, &devices[i], 1);
379ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			release_list_offset++;
380ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		} else {
381ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_dbg("allocating new device for %d/%d (session %ld)",
382ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					bus_addr, dev_addr, session_id);
383ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			dev = usbi_alloc_device(ctx, session_id);
384ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			if (!dev) {
385ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				r = LIBUSB_ERROR_NO_MEM;
386ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				goto err_out;
387ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			}
388ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			r = init_device(dev, devices[i], bus_addr, dev_addr);
389ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			if (r < 0)
390ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				goto err_out;
391ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			r = usbi_sanitize_device(dev);
392ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			if (r < 0)
393ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				goto err_out;
394ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
395ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		new_devices = discovered_devs_append(new_devices, dev);
396ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (!discdevs) {
397ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			r = LIBUSB_ERROR_NO_MEM;
398ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			goto err_out;
399ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
400ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		safe_unref_device(dev);
401ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
402ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	*discdevs = new_devices;
403ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return r;
404ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdocherr_out:
405ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	*discdevs = new_devices;
406ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	safe_unref_device(dev);
407ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// Release the remainder of the unprocessed device list.
408ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// The devices added to new_devices already will still be passed up to libusb,
409ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// which can dispose of them at its leisure.
410ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	UkwReleaseDeviceList(driver_handle, &devices[release_list_offset], count - release_list_offset);
411ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return r;
412ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
413ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
414ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_open(struct libusb_device_handle *handle)
415ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
416ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// Nothing to do to open devices as a handle to it has
417ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// been retrieved by wince_get_device_list
418ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
419ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
420ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
421ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic void wince_close(struct libusb_device_handle *handle)
422ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
423ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// Nothing to do as wince_open does nothing.
424ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
425ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
426ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_get_device_descriptor(
427ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   struct libusb_device *device,
428ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   unsigned char *buffer, int *host_endian)
429ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
430ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(device);
431ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
432ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	*host_endian = 1;
433ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	memcpy(buffer, &priv->desc, DEVICE_DESC_LENGTH);
434ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
435ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
436ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
437ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_get_active_config_descriptor(
438ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_device *device,
439ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	unsigned char *buffer, size_t len, int *host_endian)
440ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
441ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(device);
442ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DWORD actualSize = len;
443ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	*host_endian = 0;
444ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!UkwGetConfigDescriptor(priv->dev, UKW_ACTIVE_CONFIGURATION, buffer, len, &actualSize)) {
445ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return translate_driver_error(GetLastError());
446ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
447ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return actualSize;
448ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
449ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
450ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_get_config_descriptor(
451ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_device *device,
452ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	uint8_t config_index,
453ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	unsigned char *buffer, size_t len, int *host_endian)
454ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
455ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(device);
456ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DWORD actualSize = len;
457ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	*host_endian = 0;
458ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!UkwGetConfigDescriptor(priv->dev, config_index, buffer, len, &actualSize)) {
459ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return translate_driver_error(GetLastError());
460ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
461ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return actualSize;
462ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
463ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
464ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_get_configuration(
465ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   struct libusb_device_handle *handle,
466ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   int *config)
467ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
468ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(handle->dev);
469ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	UCHAR cv = 0;
470ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!UkwGetConfig(priv->dev, &cv)) {
471ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return translate_driver_error(GetLastError());
472ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
473ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	(*config) = cv;
474ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
475ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
476ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
477ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_set_configuration(
478ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_device_handle *handle,
479ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int config)
480ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
481ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(handle->dev);
482ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// Setting configuration 0 places the device in Address state.
483ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// This should correspond to the "unconfigured state" required by
484ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// libusb when the specified configuration is -1.
485ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	UCHAR cv = (config < 0) ? 0 : config;
486ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!UkwSetConfig(priv->dev, cv)) {
487ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return translate_driver_error(GetLastError());
488ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
489ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
490ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
491ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
492ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_claim_interface(
493ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_device_handle *handle,
494ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int interface_number)
495ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
496ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(handle->dev);
497ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!UkwClaimInterface(priv->dev, interface_number)) {
498ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return translate_driver_error(GetLastError());
499ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
500ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
501ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
502ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
503ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_release_interface(
504ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_device_handle *handle,
505ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int interface_number)
506ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
507ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(handle->dev);
508ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, 0)) {
509ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return translate_driver_error(GetLastError());
510ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
511ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!UkwReleaseInterface(priv->dev, interface_number)) {
512ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return translate_driver_error(GetLastError());
513ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
514ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
515ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
516ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
517ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_set_interface_altsetting(
518ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_device_handle *handle,
519ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int interface_number, int altsetting)
520ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
521ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(handle->dev);
522ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, altsetting)) {
523ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return translate_driver_error(GetLastError());
524ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
525ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
526ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
527ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
528ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_clear_halt(
529ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_device_handle *handle,
530ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	unsigned char endpoint)
531ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
532ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(handle->dev);
533ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!UkwClearHaltHost(priv->dev, endpoint)) {
534ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return translate_driver_error(GetLastError());
535ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
536ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!UkwClearHaltDevice(priv->dev, endpoint)) {
537ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return translate_driver_error(GetLastError());
538ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
539ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
540ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
541ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
542ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_reset_device(
543ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_device_handle *handle)
544ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
545ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(handle->dev);
546ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!UkwResetDevice(priv->dev)) {
547ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return translate_driver_error(GetLastError());
548ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
549ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
550ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
551ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
552ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_kernel_driver_active(
553ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_device_handle *handle,
554ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int interface_number)
555ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
556ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(handle->dev);
557ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	BOOL result = FALSE;
558ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!UkwKernelDriverActive(priv->dev, interface_number, &result)) {
559ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return translate_driver_error(GetLastError());
560ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
561ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return result ? 1 : 0;
562ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
563ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
564ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_detach_kernel_driver(
565ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_device_handle *handle,
566ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int interface_number)
567ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
568ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(handle->dev);
569ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!UkwDetachKernelDriver(priv->dev, interface_number)) {
570ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return translate_driver_error(GetLastError());
571ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
572ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
573ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
574ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
575ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_attach_kernel_driver(
576ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_device_handle *handle,
577ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int interface_number)
578ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
579ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(handle->dev);
580ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!UkwAttachKernelDriver(priv->dev, interface_number)) {
581ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return translate_driver_error(GetLastError());
582ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
583ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
584ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
585ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
586ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic void wince_destroy_device(
587ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_device *dev)
588ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
589ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(dev);
590ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	UkwReleaseDeviceList(driver_handle, &priv->dev, 1);
591ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
592ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
593ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic void wince_clear_transfer_priv(
594ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct usbi_transfer *itransfer)
595ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
596ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
597ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct winfd wfd = fd_to_winfd(transfer_priv->pollable_fd.fd);
598ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// No need to cancel transfer as it is either complete or abandoned
599ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	wfd.itransfer = NULL;
600ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	CloseHandle(wfd.handle);
601ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_free_fd(&transfer_priv->pollable_fd);
602ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
603ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
604ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_cancel_transfer(
605ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct usbi_transfer *itransfer)
606ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
607ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
608ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
609ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
610ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
611ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!UkwCancelTransfer(priv->dev, transfer_priv->pollable_fd.overlapped, UKW_TF_NO_WAIT)) {
612ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return translate_driver_error(GetLastError());
613ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
614ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
615ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
616ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
617ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_submit_control_or_bulk_transfer(struct usbi_transfer *itransfer)
618ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
619ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
620ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
621ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
622ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
623ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	BOOL direction_in, ret;
624ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct winfd wfd;
625ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DWORD flags;
626ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	HANDLE eventHandle;
627ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	PUKW_CONTROL_HEADER setup = NULL;
628ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	const BOOL control_transfer = transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL;
629ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
630ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	transfer_priv->pollable_fd = INVALID_WINFD;
631ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (control_transfer) {
632ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		setup = (PUKW_CONTROL_HEADER) transfer->buffer;
633ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		direction_in = setup->bmRequestType & LIBUSB_ENDPOINT_IN;
634ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} else {
635ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN;
636ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
637ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	flags = direction_in ? UKW_TF_IN_TRANSFER : UKW_TF_OUT_TRANSFER;
638ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	flags |= UKW_TF_SHORT_TRANSFER_OK;
639ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
640ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	eventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
641ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (eventHandle == NULL) {
642ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_err(ctx, "Failed to create event for async transfer");
643ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_ERROR_NO_MEM;
644ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
645ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
646ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	wfd = usbi_create_fd(eventHandle, direction_in ? RW_READ : RW_WRITE, itransfer, &wince_cancel_transfer);
647ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (wfd.fd < 0) {
648ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		CloseHandle(eventHandle);
649ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_ERROR_NO_MEM;
650ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
651ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
652ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	transfer_priv->pollable_fd = wfd;
653ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (control_transfer) {
654ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// Split out control setup header and data buffer
655ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		DWORD bufLen = transfer->length - sizeof(UKW_CONTROL_HEADER);
656ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		PVOID buf = (PVOID) &transfer->buffer[sizeof(UKW_CONTROL_HEADER)];
657ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
658ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		ret = UkwIssueControlTransfer(priv->dev, flags, setup, buf, bufLen, &transfer->actual_length, wfd.overlapped);
659ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} else {
660ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		ret = UkwIssueBulkTransfer(priv->dev, flags, transfer->endpoint, transfer->buffer,
661ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			transfer->length, &transfer->actual_length, wfd.overlapped);
662ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
663ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!ret) {
664ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		int libusbErr = translate_driver_error(GetLastError());
665ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_err(ctx, "UkwIssue%sTransfer failed: error %d",
666ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			control_transfer ? "Control" : "Bulk", GetLastError());
667ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		wince_clear_transfer_priv(itransfer);
668ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return libusbErr;
669ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
670ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, direction_in ? POLLIN : POLLOUT);
671ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
672ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
673ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
674ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
675ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
676ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_submit_iso_transfer(struct usbi_transfer *itransfer)
677ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
678ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_ERROR_NOT_SUPPORTED;
679ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
680ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
681ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_submit_transfer(
682ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct usbi_transfer *itransfer)
683ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
684ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
685ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
686ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	switch (transfer->type) {
687ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	case LIBUSB_TRANSFER_TYPE_CONTROL:
688ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	case LIBUSB_TRANSFER_TYPE_BULK:
689ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
690ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return wince_submit_control_or_bulk_transfer(itransfer);
691ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
692ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return wince_submit_iso_transfer(itransfer);
693ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	default:
694ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
695ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_ERROR_INVALID_PARAM;
696ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
697ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
698ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
699ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic void wince_transfer_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
700ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
701ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
702ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
703ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
704ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int status;
705ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
706ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_dbg("handling I/O completion with errcode %d", io_result);
707ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
708ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (io_result == ERROR_NOT_SUPPORTED &&
709ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		transfer->type != LIBUSB_TRANSFER_TYPE_CONTROL) {
710ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* For functional stalls, the WinCE USB layer (and therefore the USB Kernel Wrapper
711ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 * Driver) will report USB_ERROR_STALL/ERROR_NOT_SUPPORTED in situations where the
712ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 * endpoint isn't actually stalled.
713ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 *
714ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 * One example of this is that some devices will occasionally fail to reply to an IN
715ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 * token. The WinCE USB layer carries on with the transaction until it is completed
716ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 * (or cancelled) but then completes it with USB_ERROR_STALL.
717ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 *
718ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 * This code therefore needs to confirm that there really is a stall error, by both
719ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 * checking the pipe status and requesting the endpoint status from the device.
720ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 */
721ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		BOOL halted = FALSE;
722ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_dbg("checking I/O completion with errcode ERROR_NOT_SUPPORTED is really a stall");
723ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (UkwIsPipeHalted(priv->dev, transfer->endpoint, &halted)) {
724ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			/* Pipe status retrieved, so now request endpoint status by sending a GET_STATUS
725ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			 * control request to the device. This is done synchronously, which is a bit
726ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			 * naughty, but this is a special corner case.
727ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			 */
728ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			WORD wStatus = 0;
729ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			DWORD written = 0;
730ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			UKW_CONTROL_HEADER ctrlHeader;
731ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			ctrlHeader.bmRequestType = LIBUSB_REQUEST_TYPE_STANDARD |
732ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_ENDPOINT;
733ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			ctrlHeader.bRequest = LIBUSB_REQUEST_GET_STATUS;
734ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			ctrlHeader.wValue = 0;
735ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			ctrlHeader.wIndex = transfer->endpoint;
736ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			ctrlHeader.wLength = sizeof(wStatus);
737ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			if (UkwIssueControlTransfer(priv->dev,
738ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					UKW_TF_IN_TRANSFER | UKW_TF_SEND_TO_ENDPOINT,
739ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					&ctrlHeader, &wStatus, sizeof(wStatus), &written, NULL)) {
740ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				if (written == sizeof(wStatus) &&
741ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch						(wStatus & STATUS_HALT_FLAG) == 0) {
742ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					if (!halted || UkwClearHaltHost(priv->dev, transfer->endpoint)) {
743ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch						usbi_dbg("Endpoint doesn't appear to be stalled, overriding error with success");
744ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch						io_result = ERROR_SUCCESS;
745ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					} else {
746ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch						usbi_dbg("Endpoint doesn't appear to be stalled, but the host is halted, changing error");
747ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch						io_result = ERROR_IO_DEVICE;
748ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					}
749ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				}
750ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			}
751ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
752ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
753ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
754ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	switch(io_result) {
755ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	case ERROR_SUCCESS:
756ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		itransfer->transferred += io_size;
757ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		status = LIBUSB_TRANSFER_COMPLETED;
758ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		break;
759ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	case ERROR_CANCELLED:
760ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_dbg("detected transfer cancel");
761ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		status = LIBUSB_TRANSFER_CANCELLED;
762ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		break;
763ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	case ERROR_NOT_SUPPORTED:
764ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	case ERROR_GEN_FAILURE:
765ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_dbg("detected endpoint stall");
766ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		status = LIBUSB_TRANSFER_STALL;
767ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		break;
768ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	case ERROR_SEM_TIMEOUT:
769ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_dbg("detected semaphore timeout");
770ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		status = LIBUSB_TRANSFER_TIMED_OUT;
771ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		break;
772ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	case ERROR_OPERATION_ABORTED:
773ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (itransfer->flags & USBI_TRANSFER_TIMED_OUT) {
774ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_dbg("detected timeout");
775ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			status = LIBUSB_TRANSFER_TIMED_OUT;
776ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		} else {
777ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_dbg("detected operation aborted");
778ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			status = LIBUSB_TRANSFER_CANCELLED;
779ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
780ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		break;
781ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	default:
782ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error: %s", windows_error_str(io_result));
783ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		status = LIBUSB_TRANSFER_ERROR;
784ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		break;
785ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
786ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	wince_clear_transfer_priv(itransfer);
787ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (status == LIBUSB_TRANSFER_CANCELLED) {
788ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_handle_transfer_cancellation(itransfer);
789ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} else {
790ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status);
791ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
792ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
793ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
794ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic void wince_handle_callback (struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
795ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
796ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
797ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
798ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	switch (transfer->type) {
799ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	case LIBUSB_TRANSFER_TYPE_CONTROL:
800ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	case LIBUSB_TRANSFER_TYPE_BULK:
801ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
802ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
803ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		wince_transfer_callback (itransfer, io_result, io_size);
804ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		break;
805ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	default:
806ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
807ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
808ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
809ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
810ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_handle_events(
811ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_context *ctx,
812ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready)
813ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
814ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct wince_transfer_priv* transfer_priv = NULL;
815ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	POLL_NFDS_TYPE i = 0;
816ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	BOOL found = FALSE;
817ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct usbi_transfer *transfer;
818ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DWORD io_size, io_result;
819ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
820ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_mutex_lock(&ctx->open_devs_lock);
821ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	for (i = 0; i < nfds && num_ready > 0; i++) {
822ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
823ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_dbg("checking fd %d with revents = %04x", fds[i].fd, fds[i].revents);
824ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
825ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (!fds[i].revents) {
826ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			continue;
827ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
828ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
829ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		num_ready--;
830ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
831ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// Because a Windows OVERLAPPED is used for poll emulation,
832ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// a pollable fd is created and stored with each transfer
833ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_mutex_lock(&ctx->flying_transfers_lock);
834ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
835ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			transfer_priv = usbi_transfer_get_os_priv(transfer);
836ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			if (transfer_priv->pollable_fd.fd == fds[i].fd) {
837ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				found = TRUE;
838ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				break;
839ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			}
840ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
841ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_mutex_unlock(&ctx->flying_transfers_lock);
842ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
843ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (found && HasOverlappedIoCompleted(transfer_priv->pollable_fd.overlapped)) {
844ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			io_result = (DWORD)transfer_priv->pollable_fd.overlapped->Internal;
845ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			io_size = (DWORD)transfer_priv->pollable_fd.overlapped->InternalHigh;
846ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_remove_pollfd(ctx, transfer_priv->pollable_fd.fd);
847ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			// let handle_callback free the event using the transfer wfd
848ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			// If you don't use the transfer wfd, you run a risk of trying to free a
849ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			// newly allocated wfd that took the place of the one from the transfer.
850ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			wince_handle_callback(transfer, io_result, io_size);
851ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		} else if (found) {
852ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_err(ctx, "matching transfer for fd %x has not completed", fds[i]);
853ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_OTHER;
854ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		} else {
855ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_err(ctx, "could not find a matching transfer for fd %x", fds[i]);
856ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_NOT_FOUND;
857ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
858ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
859ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
860ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_mutex_unlock(&ctx->open_devs_lock);
861ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
862ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
863ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
864ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/*
865ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Monotonic and real time functions
866ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch */
867ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochunsigned __stdcall wince_clock_gettime_threaded(void* param)
868ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
869ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	LARGE_INTEGER hires_counter, li_frequency;
870ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	LONG nb_responses;
871ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int timer_index;
872ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
873ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// Init - find out if we have access to a monotonic (hires) timer
874ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!QueryPerformanceFrequency(&li_frequency)) {
875ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_dbg("no hires timer available on this platform");
876ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		hires_frequency = 0;
877ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		hires_ticks_to_ps = UINT64_C(0);
878ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} else {
879ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		hires_frequency = li_frequency.QuadPart;
880ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// The hires frequency can go as high as 4 GHz, so we'll use a conversion
881ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// to picoseconds to compute the tv_nsecs part in clock_gettime
882ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency;
883ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency);
884ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
885ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
88668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	// Signal wince_init() that we're ready to service requests
88768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if (ReleaseSemaphore(timer_response, 1, NULL) == 0) {
88868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		usbi_dbg("unable to release timer semaphore: %s", windows_error_str(0));
88968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	}
89068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
891ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	// Main loop - wait for requests
892ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	while (1) {
893ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		timer_index = WaitForMultipleObjects(2, timer_request, FALSE, INFINITE) - WAIT_OBJECT_0;
894ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if ( (timer_index != 0) && (timer_index != 1) ) {
895ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_dbg("failure to wait on requests: %s", windows_error_str(0));
896ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			continue;
897ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
898ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (request_count[timer_index] == 0) {
899ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			// Request already handled
900ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			ResetEvent(timer_request[timer_index]);
901ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			// There's still a possiblity that a thread sends a request between the
902ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			// time we test request_count[] == 0 and we reset the event, in which case
903ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			// the request would be ignored. The simple solution to that is to test
904ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			// request_count again and process requests if non zero.
905ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			if (request_count[timer_index] == 0)
906ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				continue;
907ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
908ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		switch (timer_index) {
909ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		case 0:
910ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			WaitForSingleObject(timer_mutex, INFINITE);
911ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			// Requests to this thread are for hires always
912ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			if (QueryPerformanceCounter(&hires_counter) != 0) {
913ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				timer_tp.tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
914ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				timer_tp.tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency)/1000) * hires_ticks_to_ps);
915ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			} else {
916ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				// Fallback to real-time if we can't get monotonic value
917ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				// Note that real-time clock does not wait on the mutex or this thread.
918ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				wince_clock_gettime(USBI_CLOCK_REALTIME, &timer_tp);
919ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			}
920ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			ReleaseMutex(timer_mutex);
921ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
922ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			nb_responses = InterlockedExchange((LONG*)&request_count[0], 0);
923ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			if ( (nb_responses)
924ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			  && (ReleaseSemaphore(timer_response, nb_responses, NULL) == 0) ) {
92568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				usbi_dbg("unable to release timer semaphore: %s", windows_error_str(0));
926ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			}
927ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			continue;
928ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		case 1: // time to quit
929ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_dbg("timer thread quitting");
930ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return 0;
931ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
932ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
933ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_dbg("ERROR: broken timer thread");
934ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return 1;
935ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
936ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
937ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int wince_clock_gettime(int clk_id, struct timespec *tp)
938ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
939ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	FILETIME filetime;
940ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	ULARGE_INTEGER rtime;
941ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	DWORD r;
942ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	SYSTEMTIME st;
943ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	switch(clk_id) {
944ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	case USBI_CLOCK_MONOTONIC:
945ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (hires_frequency != 0) {
946ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			while (1) {
947ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				InterlockedIncrement((LONG*)&request_count[0]);
948ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				SetEvent(timer_request[0]);
949ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				r = WaitForSingleObject(timer_response, TIMER_REQUEST_RETRY_MS);
950ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				switch(r) {
951ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				case WAIT_OBJECT_0:
952ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					WaitForSingleObject(timer_mutex, INFINITE);
953ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					*tp = timer_tp;
954ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					ReleaseMutex(timer_mutex);
955ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					return LIBUSB_SUCCESS;
956ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				case WAIT_TIMEOUT:
957ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?");
958ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					break; // Retry until successful
959ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				default:
960ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					usbi_dbg("WaitForSingleObject failed: %s", windows_error_str(0));
961ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					return LIBUSB_ERROR_OTHER;
962ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				}
963ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			}
964ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
965ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// Fall through and return real-time if monotonic was not detected @ timer init
966ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	case USBI_CLOCK_REALTIME:
967ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// We follow http://msdn.microsoft.com/en-us/library/ms724928%28VS.85%29.aspx
968ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// with a predef epoch_time to have an epoch that starts at 1970.01.01 00:00
969ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// Note however that our resolution is bounded by the Windows system time
970ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		// functions and is at best of the order of 1 ms (or, usually, worse)
971ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		GetSystemTime(&st);
972ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		SystemTimeToFileTime(&st, &filetime);
973ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		rtime.LowPart = filetime.dwLowDateTime;
974ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		rtime.HighPart = filetime.dwHighDateTime;
975ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		rtime.QuadPart -= epoch_time;
976ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		tp->tv_sec = (long)(rtime.QuadPart / 10000000);
977ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		tp->tv_nsec = (long)((rtime.QuadPart % 10000000)*100);
978ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_SUCCESS;
979ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	default:
980ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_ERROR_INVALID_PARAM;
981ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
982ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
983ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
984ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochconst struct usbi_os_backend wince_backend = {
985ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        "Windows CE",
986ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        0,
987ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_init,
988ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_exit,
989ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
990ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_get_device_list,
991ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	NULL,				/* hotplug_poll */
992ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_open,
993ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_close,
994ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
995ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_get_device_descriptor,
996ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_get_active_config_descriptor,
997ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_get_config_descriptor,
998ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	NULL,				/* get_config_descriptor_by_value() */
999ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1000ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_get_configuration,
1001ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_set_configuration,
1002ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_claim_interface,
1003ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_release_interface,
1004ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1005ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_set_interface_altsetting,
1006ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_clear_halt,
1007ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_reset_device,
1008ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1009ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_kernel_driver_active,
1010ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_detach_kernel_driver,
1011ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_attach_kernel_driver,
1012ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1013ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_destroy_device,
1014ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1015ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_submit_transfer,
1016ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_cancel_transfer,
1017ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_clear_transfer_priv,
1018ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1019ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_handle_events,
1020ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1021ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        wince_clock_gettime,
1022ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        sizeof(struct wince_device_priv),
1023ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        sizeof(struct wince_device_handle_priv),
1024ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        sizeof(struct wince_transfer_priv),
1025ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        0,
1026ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch};
1027