|
Packit Service |
b0a153 |
/*
|
|
Packit Service |
b0a153 |
* windows backend for libusb 1.0
|
|
Packit Service |
b0a153 |
* Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
|
|
Packit Service |
b0a153 |
* With contributions from Michael Plante, Orin Eman et al.
|
|
Packit Service |
b0a153 |
* Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
|
|
Packit Service |
b0a153 |
* HID Reports IOCTLs inspired from HIDAPI by Alan Ott, Signal 11 Software
|
|
Packit Service |
b0a153 |
* Hash table functions adapted from glibc, by Ulrich Drepper et al.
|
|
Packit Service |
b0a153 |
* Major code testing contribution by Xiaofan Chen
|
|
Packit Service |
b0a153 |
*
|
|
Packit Service |
b0a153 |
* This library is free software; you can redistribute it and/or
|
|
Packit Service |
b0a153 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit Service |
b0a153 |
* License as published by the Free Software Foundation; either
|
|
Packit Service |
b0a153 |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit Service |
b0a153 |
*
|
|
Packit Service |
b0a153 |
* This library is distributed in the hope that it will be useful,
|
|
Packit Service |
b0a153 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
b0a153 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
b0a153 |
* Lesser General Public License for more details.
|
|
Packit Service |
b0a153 |
*
|
|
Packit Service |
b0a153 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
b0a153 |
* License along with this library; if not, write to the Free Software
|
|
Packit Service |
b0a153 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit Service |
b0a153 |
*/
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
#include <config.h>
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
#include <inttypes.h>
|
|
Packit Service |
b0a153 |
#include <process.h>
|
|
Packit Service |
b0a153 |
#include <stdio.h>
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
#include "libusbi.h"
|
|
Packit Service |
b0a153 |
#include "windows_common.h"
|
|
Packit Service |
b0a153 |
#include "windows_nt_common.h"
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Public
|
|
Packit Service |
b0a153 |
BOOL (WINAPI *pCancelIoEx)(HANDLE, LPOVERLAPPED);
|
|
Packit Service |
b0a153 |
enum windows_version windows_version = WINDOWS_UNDEFINED;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Global variables for init/exit
|
|
Packit Service |
b0a153 |
static unsigned int init_count = 0;
|
|
Packit Service |
b0a153 |
static bool usbdk_available = false;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Global variables for clock_gettime mechanism
|
|
Packit Service |
b0a153 |
static uint64_t hires_ticks_to_ps;
|
|
Packit Service |
b0a153 |
static uint64_t hires_frequency;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
#define TIMER_REQUEST_RETRY_MS 100
|
|
Packit Service |
b0a153 |
#define WM_TIMER_REQUEST (WM_USER + 1)
|
|
Packit Service |
b0a153 |
#define WM_TIMER_EXIT (WM_USER + 2)
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// used for monotonic clock_gettime()
|
|
Packit Service |
b0a153 |
struct timer_request {
|
|
Packit Service |
b0a153 |
struct timespec *tp;
|
|
Packit Service |
b0a153 |
HANDLE event;
|
|
Packit Service |
b0a153 |
};
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Timer thread
|
|
Packit Service |
b0a153 |
static HANDLE timer_thread = NULL;
|
|
Packit Service |
b0a153 |
static DWORD timer_thread_id = 0;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
/* Kernel32 dependencies */
|
|
Packit Service |
b0a153 |
DLL_DECLARE_HANDLE(Kernel32);
|
|
Packit Service |
b0a153 |
/* This call is only available from XP SP2 */
|
|
Packit Service |
b0a153 |
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, IsWow64Process, (HANDLE, PBOOL));
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
/* User32 dependencies */
|
|
Packit Service |
b0a153 |
DLL_DECLARE_HANDLE(User32);
|
|
Packit Service |
b0a153 |
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, GetMessageA, (LPMSG, HWND, UINT, UINT));
|
|
Packit Service |
b0a153 |
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, PeekMessageA, (LPMSG, HWND, UINT, UINT, UINT));
|
|
Packit Service |
b0a153 |
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, PostThreadMessageA, (DWORD, UINT, WPARAM, LPARAM));
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static unsigned __stdcall windows_clock_gettime_threaded(void *param);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
/*
|
|
Packit Service |
b0a153 |
* Converts a windows error to human readable string
|
|
Packit Service |
b0a153 |
* uses retval as errorcode, or, if 0, use GetLastError()
|
|
Packit Service |
b0a153 |
*/
|
|
Packit Service |
b0a153 |
#if defined(ENABLE_LOGGING)
|
|
Packit Service |
b0a153 |
const char *windows_error_str(DWORD error_code)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
static char err_string[ERR_BUFFER_SIZE];
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
DWORD size;
|
|
Packit Service |
b0a153 |
int len;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if (error_code == 0)
|
|
Packit Service |
b0a153 |
error_code = GetLastError();
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
len = sprintf(err_string, "[%u] ", (unsigned int)error_code);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Translate codes returned by SetupAPI. The ones we are dealing with are either
|
|
Packit Service |
b0a153 |
// in 0x0000xxxx or 0xE000xxxx and can be distinguished from standard error codes.
|
|
Packit Service |
b0a153 |
// See http://msdn.microsoft.com/en-us/library/windows/hardware/ff545011.aspx
|
|
Packit Service |
b0a153 |
switch (error_code & 0xE0000000) {
|
|
Packit Service |
b0a153 |
case 0:
|
|
Packit Service |
b0a153 |
error_code = HRESULT_FROM_WIN32(error_code); // Still leaves ERROR_SUCCESS unmodified
|
|
Packit Service |
b0a153 |
break;
|
|
Packit Service |
b0a153 |
case 0xE0000000:
|
|
Packit Service |
b0a153 |
error_code = 0x80000000 | (FACILITY_SETUPAPI << 16) | (error_code & 0x0000FFFF);
|
|
Packit Service |
b0a153 |
break;
|
|
Packit Service |
b0a153 |
default:
|
|
Packit Service |
b0a153 |
break;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
size = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
Packit Service |
b0a153 |
NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
Packit Service |
b0a153 |
&err_string[len], ERR_BUFFER_SIZE - len, NULL);
|
|
Packit Service |
b0a153 |
if (size == 0) {
|
|
Packit Service |
b0a153 |
DWORD format_error = GetLastError();
|
|
Packit Service |
b0a153 |
if (format_error)
|
|
Packit Service |
b0a153 |
snprintf(err_string, ERR_BUFFER_SIZE,
|
|
Packit Service |
b0a153 |
"Windows error code %u (FormatMessage error code %u)",
|
|
Packit Service |
b0a153 |
(unsigned int)error_code, (unsigned int)format_error);
|
|
Packit Service |
b0a153 |
else
|
|
Packit Service |
b0a153 |
snprintf(err_string, ERR_BUFFER_SIZE, "Unknown error code %u", (unsigned int)error_code);
|
|
Packit Service |
b0a153 |
} else {
|
|
Packit Service |
b0a153 |
// Remove CRLF from end of message, if present
|
|
Packit Service |
b0a153 |
size_t pos = len + size - 2;
|
|
Packit Service |
b0a153 |
if (err_string[pos] == '\r')
|
|
Packit Service |
b0a153 |
err_string[pos] = '\0';
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
return err_string;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
#endif
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static inline struct windows_context_priv *_context_priv(struct libusb_context *ctx)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
return (struct windows_context_priv *)ctx->os_priv;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
/* Hash table functions - modified From glibc 2.3.2:
|
|
Packit Service |
b0a153 |
[Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
|
|
Packit Service |
b0a153 |
[Knuth] The Art of Computer Programming, part 3 (6.4) */
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
#define HTAB_SIZE 1021UL // *MUST* be a prime number!!
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
typedef struct htab_entry {
|
|
Packit Service |
b0a153 |
unsigned long used;
|
|
Packit Service |
b0a153 |
char *str;
|
|
Packit Service |
b0a153 |
} htab_entry;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static htab_entry *htab_table = NULL;
|
|
Packit Service |
b0a153 |
static usbi_mutex_t htab_mutex;
|
|
Packit Service |
b0a153 |
static unsigned long htab_filled;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
/* Before using the hash table we must allocate memory for it.
|
|
Packit Service |
b0a153 |
We allocate one element more as the found prime number says.
|
|
Packit Service |
b0a153 |
This is done for more effective indexing as explained in the
|
|
Packit Service |
b0a153 |
comment for the hash function. */
|
|
Packit Service |
b0a153 |
static bool htab_create(struct libusb_context *ctx)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
if (htab_table != NULL) {
|
|
Packit Service |
b0a153 |
usbi_err(ctx, "hash table already allocated");
|
|
Packit Service |
b0a153 |
return true;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Create a mutex
|
|
Packit Service |
b0a153 |
usbi_mutex_init(&htab_mutex);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
usbi_dbg("using %lu entries hash table", HTAB_SIZE);
|
|
Packit Service |
b0a153 |
htab_filled = 0;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// allocate memory and zero out.
|
|
Packit Service |
b0a153 |
htab_table = calloc(HTAB_SIZE + 1, sizeof(htab_entry));
|
|
Packit Service |
b0a153 |
if (htab_table == NULL) {
|
|
Packit Service |
b0a153 |
usbi_err(ctx, "could not allocate space for hash table");
|
|
Packit Service |
b0a153 |
return false;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
return true;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
/* After using the hash table it has to be destroyed. */
|
|
Packit Service |
b0a153 |
static void htab_destroy(void)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
unsigned long i;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if (htab_table == NULL)
|
|
Packit Service |
b0a153 |
return;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
for (i = 0; i < HTAB_SIZE; i++)
|
|
Packit Service |
b0a153 |
free(htab_table[i].str);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
safe_free(htab_table);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
usbi_mutex_destroy(&htab_mutex);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
/* This is the search function. It uses double hashing with open addressing.
|
|
Packit Service |
b0a153 |
We use a trick to speed up the lookup. The table is created with one
|
|
Packit Service |
b0a153 |
more element available. This enables us to use the index zero special.
|
|
Packit Service |
b0a153 |
This index will never be used because we store the first hash index in
|
|
Packit Service |
b0a153 |
the field used where zero means not used. Every other value means used.
|
|
Packit Service |
b0a153 |
The used field can be used as a first fast comparison for equality of
|
|
Packit Service |
b0a153 |
the stored and the parameter value. This helps to prevent unnecessary
|
|
Packit Service |
b0a153 |
expensive calls of strcmp. */
|
|
Packit Service |
b0a153 |
unsigned long htab_hash(const char *str)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
unsigned long hval, hval2;
|
|
Packit Service |
b0a153 |
unsigned long idx;
|
|
Packit Service |
b0a153 |
unsigned long r = 5381;
|
|
Packit Service |
b0a153 |
int c;
|
|
Packit Service |
b0a153 |
const char *sz = str;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if (str == NULL)
|
|
Packit Service |
b0a153 |
return 0;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Compute main hash value (algorithm suggested by Nokia)
|
|
Packit Service |
b0a153 |
while ((c = *sz++) != 0)
|
|
Packit Service |
b0a153 |
r = ((r << 5) + r) + c;
|
|
Packit Service |
b0a153 |
if (r == 0)
|
|
Packit Service |
b0a153 |
++r;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// compute table hash: simply take the modulus
|
|
Packit Service |
b0a153 |
hval = r % HTAB_SIZE;
|
|
Packit Service |
b0a153 |
if (hval == 0)
|
|
Packit Service |
b0a153 |
++hval;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Try the first index
|
|
Packit Service |
b0a153 |
idx = hval;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Mutually exclusive access (R/W lock would be better)
|
|
Packit Service |
b0a153 |
usbi_mutex_lock(&htab_mutex);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if (htab_table[idx].used) {
|
|
Packit Service |
b0a153 |
if ((htab_table[idx].used == hval) && (strcmp(str, htab_table[idx].str) == 0))
|
|
Packit Service |
b0a153 |
goto out_unlock; // existing hash
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
usbi_dbg("hash collision ('%s' vs '%s')", str, htab_table[idx].str);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Second hash function, as suggested in [Knuth]
|
|
Packit Service |
b0a153 |
hval2 = 1 + hval % (HTAB_SIZE - 2);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
do {
|
|
Packit Service |
b0a153 |
// Because size is prime this guarantees to step through all available indexes
|
|
Packit Service |
b0a153 |
if (idx <= hval2)
|
|
Packit Service |
b0a153 |
idx = HTAB_SIZE + idx - hval2;
|
|
Packit Service |
b0a153 |
else
|
|
Packit Service |
b0a153 |
idx -= hval2;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// If we visited all entries leave the loop unsuccessfully
|
|
Packit Service |
b0a153 |
if (idx == hval)
|
|
Packit Service |
b0a153 |
break;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// If entry is found use it.
|
|
Packit Service |
b0a153 |
if ((htab_table[idx].used == hval) && (strcmp(str, htab_table[idx].str) == 0))
|
|
Packit Service |
b0a153 |
goto out_unlock;
|
|
Packit Service |
b0a153 |
} while (htab_table[idx].used);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Not found => New entry
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// If the table is full return an error
|
|
Packit Service |
b0a153 |
if (htab_filled >= HTAB_SIZE) {
|
|
Packit Service |
b0a153 |
usbi_err(NULL, "hash table is full (%lu entries)", HTAB_SIZE);
|
|
Packit Service |
b0a153 |
idx = 0;
|
|
Packit Service |
b0a153 |
goto out_unlock;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
htab_table[idx].str = _strdup(str);
|
|
Packit Service |
b0a153 |
if (htab_table[idx].str == NULL) {
|
|
Packit Service |
b0a153 |
usbi_err(NULL, "could not duplicate string for hash table");
|
|
Packit Service |
b0a153 |
idx = 0;
|
|
Packit Service |
b0a153 |
goto out_unlock;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
htab_table[idx].used = hval;
|
|
Packit Service |
b0a153 |
++htab_filled;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
out_unlock:
|
|
Packit Service |
b0a153 |
usbi_mutex_unlock(&htab_mutex);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
return idx;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
/*
|
|
Packit Service |
b0a153 |
* Make a transfer complete synchronously
|
|
Packit Service |
b0a153 |
*/
|
|
Packit Service |
b0a153 |
void windows_force_sync_completion(OVERLAPPED *overlapped, ULONG size)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
|
|
Packit Service |
b0a153 |
overlapped->InternalHigh = size;
|
|
Packit Service |
b0a153 |
SetEvent(overlapped->hEvent);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static BOOL windows_init_dlls(void)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
DLL_GET_HANDLE(Kernel32);
|
|
Packit Service |
b0a153 |
DLL_LOAD_FUNC_PREFIXED(Kernel32, p, IsWow64Process, FALSE);
|
|
Packit Service |
b0a153 |
pCancelIoEx = (BOOL (WINAPI *)(HANDLE, LPOVERLAPPED))
|
|
Packit Service |
b0a153 |
GetProcAddress(DLL_HANDLE_NAME(Kernel32), "CancelIoEx");
|
|
Packit Service |
b0a153 |
usbi_dbg("Will use CancelIo%s for I/O cancellation", pCancelIoEx ? "Ex" : "");
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
DLL_GET_HANDLE(User32);
|
|
Packit Service |
b0a153 |
DLL_LOAD_FUNC_PREFIXED(User32, p, GetMessageA, TRUE);
|
|
Packit Service |
b0a153 |
DLL_LOAD_FUNC_PREFIXED(User32, p, PeekMessageA, TRUE);
|
|
Packit Service |
b0a153 |
DLL_LOAD_FUNC_PREFIXED(User32, p, PostThreadMessageA, TRUE);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
return TRUE;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static void windows_exit_dlls(void)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
DLL_FREE_HANDLE(Kernel32);
|
|
Packit Service |
b0a153 |
DLL_FREE_HANDLE(User32);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static bool windows_init_clock(struct libusb_context *ctx)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
DWORD_PTR affinity, dummy;
|
|
Packit Service |
b0a153 |
HANDLE event;
|
|
Packit Service |
b0a153 |
LARGE_INTEGER li_frequency;
|
|
Packit Service |
b0a153 |
int i;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if (QueryPerformanceFrequency(&li_frequency)) {
|
|
Packit Service |
b0a153 |
// The hires frequency can go as high as 4 GHz, so we'll use a conversion
|
|
Packit Service |
b0a153 |
// to picoseconds to compute the tv_nsecs part in clock_gettime
|
|
Packit Service |
b0a153 |
hires_frequency = li_frequency.QuadPart;
|
|
Packit Service |
b0a153 |
hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency;
|
|
Packit Service |
b0a153 |
usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Because QueryPerformanceCounter might report different values when
|
|
Packit Service |
b0a153 |
// running on different cores, we create a separate thread for the timer
|
|
Packit Service |
b0a153 |
// calls, which we glue to the first available core always to prevent timing discrepancies.
|
|
Packit Service |
b0a153 |
if (!GetProcessAffinityMask(GetCurrentProcess(), &affinity, &dummy) || (affinity == 0)) {
|
|
Packit Service |
b0a153 |
usbi_err(ctx, "could not get process affinity: %s", windows_error_str(0));
|
|
Packit Service |
b0a153 |
return false;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// The process affinity mask is a bitmask where each set bit represents a core on
|
|
Packit Service |
b0a153 |
// which this process is allowed to run, so we find the first set bit
|
|
Packit Service |
b0a153 |
for (i = 0; !(affinity & (DWORD_PTR)(1 << i)); i++);
|
|
Packit Service |
b0a153 |
affinity = (DWORD_PTR)(1 << i);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
usbi_dbg("timer thread will run on core #%d", i);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
Packit Service |
b0a153 |
if (event == NULL) {
|
|
Packit Service |
b0a153 |
usbi_err(ctx, "could not create event: %s", windows_error_str(0));
|
|
Packit Service |
b0a153 |
return false;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
timer_thread = (HANDLE)_beginthreadex(NULL, 0, windows_clock_gettime_threaded, (void *)event,
|
|
Packit Service |
b0a153 |
0, (unsigned int *)&timer_thread_id);
|
|
Packit Service |
b0a153 |
if (timer_thread == NULL) {
|
|
Packit Service |
b0a153 |
usbi_err(ctx, "unable to create timer thread - aborting");
|
|
Packit Service |
b0a153 |
CloseHandle(event);
|
|
Packit Service |
b0a153 |
return false;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if (!SetThreadAffinityMask(timer_thread, affinity))
|
|
Packit Service |
b0a153 |
usbi_warn(ctx, "unable to set timer thread affinity, timer discrepancies may arise");
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Wait for timer thread to init before continuing.
|
|
Packit Service |
b0a153 |
if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) {
|
|
Packit Service |
b0a153 |
usbi_err(ctx, "failed to wait for timer thread to become ready - aborting");
|
|
Packit Service |
b0a153 |
CloseHandle(event);
|
|
Packit Service |
b0a153 |
return false;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
CloseHandle(event);
|
|
Packit Service |
b0a153 |
} else {
|
|
Packit Service |
b0a153 |
usbi_dbg("no hires timer available on this platform");
|
|
Packit Service |
b0a153 |
hires_frequency = 0;
|
|
Packit Service |
b0a153 |
hires_ticks_to_ps = UINT64_C(0);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
return true;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static void windows_destroy_clock(void)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
if (timer_thread) {
|
|
Packit Service |
b0a153 |
// actually the signal to quit the thread.
|
|
Packit Service |
b0a153 |
if (!pPostThreadMessageA(timer_thread_id, WM_TIMER_EXIT, 0, 0)
|
|
Packit Service |
b0a153 |
|| (WaitForSingleObject(timer_thread, INFINITE) != WAIT_OBJECT_0)) {
|
|
Packit Service |
b0a153 |
usbi_dbg("could not wait for timer thread to quit");
|
|
Packit Service |
b0a153 |
TerminateThread(timer_thread, 1);
|
|
Packit Service |
b0a153 |
// shouldn't happen, but we're destroying
|
|
Packit Service |
b0a153 |
// all objects it might have held anyway.
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
CloseHandle(timer_thread);
|
|
Packit Service |
b0a153 |
timer_thread = NULL;
|
|
Packit Service |
b0a153 |
timer_thread_id = 0;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
/* Windows version detection */
|
|
Packit Service |
b0a153 |
static BOOL is_x64(void)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
BOOL ret = FALSE;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Detect if we're running a 32 or 64 bit system
|
|
Packit Service |
b0a153 |
if (sizeof(uintptr_t) < 8) {
|
|
Packit Service |
b0a153 |
if (pIsWow64Process != NULL)
|
|
Packit Service |
b0a153 |
pIsWow64Process(GetCurrentProcess(), &ret;;
|
|
Packit Service |
b0a153 |
} else {
|
|
Packit Service |
b0a153 |
ret = TRUE;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
return ret;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static void get_windows_version(void)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
OSVERSIONINFOEXA vi, vi2;
|
|
Packit Service |
b0a153 |
const char *arch, *w = NULL;
|
|
Packit Service |
b0a153 |
unsigned major, minor, version;
|
|
Packit Service |
b0a153 |
ULONGLONG major_equal, minor_equal;
|
|
Packit Service |
b0a153 |
BOOL ws;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
windows_version = WINDOWS_UNDEFINED;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
memset(&vi, 0, sizeof(vi));
|
|
Packit Service |
b0a153 |
vi.dwOSVersionInfoSize = sizeof(vi);
|
|
Packit Service |
b0a153 |
if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
|
|
Packit Service |
b0a153 |
memset(&vi, 0, sizeof(vi));
|
|
Packit Service |
b0a153 |
vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
|
|
Packit Service |
b0a153 |
if (!GetVersionExA((OSVERSIONINFOA *)&vi))
|
|
Packit Service |
b0a153 |
return;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT)
|
|
Packit Service |
b0a153 |
return;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if ((vi.dwMajorVersion > 6) || ((vi.dwMajorVersion == 6) && (vi.dwMinorVersion >= 2))) {
|
|
Packit Service |
b0a153 |
// Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the actual OS version
|
|
Packit Service |
b0a153 |
// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
|
|
Packit Service |
b0a153 |
for (major = vi.dwMajorVersion; major <= 9; major++) {
|
|
Packit Service |
b0a153 |
memset(&vi2, 0, sizeof(vi2));
|
|
Packit Service |
b0a153 |
vi2.dwOSVersionInfoSize = sizeof(vi2);
|
|
Packit Service |
b0a153 |
vi2.dwMajorVersion = major;
|
|
Packit Service |
b0a153 |
if (!VerifyVersionInfoA(&vi2, VER_MAJORVERSION, major_equal))
|
|
Packit Service |
b0a153 |
continue;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if (vi.dwMajorVersion < major) {
|
|
Packit Service |
b0a153 |
vi.dwMajorVersion = major;
|
|
Packit Service |
b0a153 |
vi.dwMinorVersion = 0;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL);
|
|
Packit Service |
b0a153 |
for (minor = vi.dwMinorVersion; minor <= 9; minor++) {
|
|
Packit Service |
b0a153 |
memset(&vi2, 0, sizeof(vi2));
|
|
Packit Service |
b0a153 |
vi2.dwOSVersionInfoSize = sizeof(vi2);
|
|
Packit Service |
b0a153 |
vi2.dwMinorVersion = minor;
|
|
Packit Service |
b0a153 |
if (!VerifyVersionInfoA(&vi2, VER_MINORVERSION, minor_equal))
|
|
Packit Service |
b0a153 |
continue;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
vi.dwMinorVersion = minor;
|
|
Packit Service |
b0a153 |
break;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
break;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if ((vi.dwMajorVersion > 0xf) || (vi.dwMinorVersion > 0xf))
|
|
Packit Service |
b0a153 |
return;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
ws = (vi.wProductType <= VER_NT_WORKSTATION);
|
|
Packit Service |
b0a153 |
version = vi.dwMajorVersion << 4 | vi.dwMinorVersion;
|
|
Packit Service |
b0a153 |
switch (version) {
|
|
Packit Service |
b0a153 |
case 0x50: windows_version = WINDOWS_2000; w = "2000"; break;
|
|
Packit Service |
b0a153 |
case 0x51: windows_version = WINDOWS_XP; w = "XP"; break;
|
|
Packit Service |
b0a153 |
case 0x52: windows_version = WINDOWS_2003; w = "2003"; break;
|
|
Packit Service |
b0a153 |
case 0x60: windows_version = WINDOWS_VISTA; w = (ws ? "Vista" : "2008"); break;
|
|
Packit Service |
b0a153 |
case 0x61: windows_version = WINDOWS_7; w = (ws ? "7" : "2008_R2"); break;
|
|
Packit Service |
b0a153 |
case 0x62: windows_version = WINDOWS_8; w = (ws ? "8" : "2012"); break;
|
|
Packit Service |
b0a153 |
case 0x63: windows_version = WINDOWS_8_1; w = (ws ? "8.1" : "2012_R2"); break;
|
|
Packit Service |
b0a153 |
case 0x64: // Early Windows 10 Insider Previews and Windows Server 2017 Technical Preview 1 used version 6.4
|
|
Packit Service |
b0a153 |
case 0xA0: windows_version = WINDOWS_10; w = (ws ? "10" : "2016"); break;
|
|
Packit Service |
b0a153 |
default:
|
|
Packit Service |
b0a153 |
if (version < 0x50) {
|
|
Packit Service |
b0a153 |
return;
|
|
Packit Service |
b0a153 |
} else {
|
|
Packit Service |
b0a153 |
windows_version = WINDOWS_11_OR_LATER;
|
|
Packit Service |
b0a153 |
w = "11 or later";
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
arch = is_x64() ? "64-bit" : "32-bit";
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if (vi.wServicePackMinor)
|
|
Packit Service |
b0a153 |
usbi_dbg("Windows %s SP%u.%u %s", w, vi.wServicePackMajor, vi.wServicePackMinor, arch);
|
|
Packit Service |
b0a153 |
else if (vi.wServicePackMajor)
|
|
Packit Service |
b0a153 |
usbi_dbg("Windows %s SP%u %s", w, vi.wServicePackMajor, arch);
|
|
Packit Service |
b0a153 |
else
|
|
Packit Service |
b0a153 |
usbi_dbg("Windows %s %s", w, arch);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
/*
|
|
Packit Service |
b0a153 |
* Monotonic and real time functions
|
|
Packit Service |
b0a153 |
*/
|
|
Packit Service |
b0a153 |
static unsigned __stdcall windows_clock_gettime_threaded(void *param)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct timer_request *request;
|
|
Packit Service |
b0a153 |
LARGE_INTEGER hires_counter;
|
|
Packit Service |
b0a153 |
MSG msg;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// The following call will create this thread's message queue
|
|
Packit Service |
b0a153 |
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms644946.aspx
|
|
Packit Service |
b0a153 |
pPeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Signal windows_init_clock() that we're ready to service requests
|
|
Packit Service |
b0a153 |
if (!SetEvent((HANDLE)param))
|
|
Packit Service |
b0a153 |
usbi_dbg("SetEvent failed for timer init event: %s", windows_error_str(0));
|
|
Packit Service |
b0a153 |
param = NULL;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Main loop - wait for requests
|
|
Packit Service |
b0a153 |
while (1) {
|
|
Packit Service |
b0a153 |
if (pGetMessageA(&msg, NULL, WM_TIMER_REQUEST, WM_TIMER_EXIT) == -1) {
|
|
Packit Service |
b0a153 |
usbi_err(NULL, "GetMessage failed for timer thread: %s", windows_error_str(0));
|
|
Packit Service |
b0a153 |
return 1;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
switch (msg.message) {
|
|
Packit Service |
b0a153 |
case WM_TIMER_REQUEST:
|
|
Packit Service |
b0a153 |
// Requests to this thread are for hires always
|
|
Packit Service |
b0a153 |
// Microsoft says that this function always succeeds on XP and later
|
|
Packit Service |
b0a153 |
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms644904.aspx
|
|
Packit Service |
b0a153 |
request = (struct timer_request *)msg.lParam;
|
|
Packit Service |
b0a153 |
QueryPerformanceCounter(&hires_counter);
|
|
Packit Service |
b0a153 |
request->tp->tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
|
|
Packit Service |
b0a153 |
request->tp->tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency) / 1000) * hires_ticks_to_ps);
|
|
Packit Service |
b0a153 |
if (!SetEvent(request->event))
|
|
Packit Service |
b0a153 |
usbi_err(NULL, "SetEvent failed for timer request: %s", windows_error_str(0));
|
|
Packit Service |
b0a153 |
break;
|
|
Packit Service |
b0a153 |
case WM_TIMER_EXIT:
|
|
Packit Service |
b0a153 |
usbi_dbg("timer thread quitting");
|
|
Packit Service |
b0a153 |
return 0;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static void windows_transfer_callback(const struct windows_backend *backend,
|
|
Packit Service |
b0a153 |
struct usbi_transfer *itransfer, DWORD io_result, DWORD io_size)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
int status, istatus;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
usbi_dbg("handling I/O completion with errcode %u, size %u", (unsigned int)io_result, (unsigned int)io_size);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
switch (io_result) {
|
|
Packit Service |
b0a153 |
case NO_ERROR:
|
|
Packit Service |
b0a153 |
status = backend->copy_transfer_data(itransfer, (uint32_t)io_size);
|
|
Packit Service |
b0a153 |
break;
|
|
Packit Service |
b0a153 |
case ERROR_GEN_FAILURE:
|
|
Packit Service |
b0a153 |
usbi_dbg("detected endpoint stall");
|
|
Packit Service |
b0a153 |
status = LIBUSB_TRANSFER_STALL;
|
|
Packit Service |
b0a153 |
break;
|
|
Packit Service |
b0a153 |
case ERROR_SEM_TIMEOUT:
|
|
Packit Service |
b0a153 |
usbi_dbg("detected semaphore timeout");
|
|
Packit Service |
b0a153 |
status = LIBUSB_TRANSFER_TIMED_OUT;
|
|
Packit Service |
b0a153 |
break;
|
|
Packit Service |
b0a153 |
case ERROR_OPERATION_ABORTED:
|
|
Packit Service |
b0a153 |
istatus = backend->copy_transfer_data(itransfer, (uint32_t)io_size);
|
|
Packit Service |
b0a153 |
if (istatus != LIBUSB_TRANSFER_COMPLETED)
|
|
Packit Service |
b0a153 |
usbi_dbg("Failed to copy partial data in aborted operation: %d", istatus);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
usbi_dbg("detected operation aborted");
|
|
Packit Service |
b0a153 |
status = LIBUSB_TRANSFER_CANCELLED;
|
|
Packit Service |
b0a153 |
break;
|
|
Packit Service |
b0a153 |
case ERROR_FILE_NOT_FOUND:
|
|
Packit Service |
b0a153 |
usbi_dbg("detected device removed");
|
|
Packit Service |
b0a153 |
status = LIBUSB_TRANSFER_NO_DEVICE;
|
|
Packit Service |
b0a153 |
break;
|
|
Packit Service |
b0a153 |
default:
|
|
Packit Service |
b0a153 |
usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error %u: %s", (unsigned int)io_result, windows_error_str(io_result));
|
|
Packit Service |
b0a153 |
status = LIBUSB_TRANSFER_ERROR;
|
|
Packit Service |
b0a153 |
break;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
backend->clear_transfer_priv(itransfer); // Cancel polling
|
|
Packit Service |
b0a153 |
if (status == LIBUSB_TRANSFER_CANCELLED)
|
|
Packit Service |
b0a153 |
usbi_handle_transfer_cancellation(itransfer);
|
|
Packit Service |
b0a153 |
else
|
|
Packit Service |
b0a153 |
usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static void windows_handle_callback(const struct windows_backend *backend,
|
|
Packit Service |
b0a153 |
struct usbi_transfer *itransfer, DWORD io_result, DWORD io_size)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
switch (transfer->type) {
|
|
Packit Service |
b0a153 |
case LIBUSB_TRANSFER_TYPE_CONTROL:
|
|
Packit Service |
b0a153 |
case LIBUSB_TRANSFER_TYPE_BULK:
|
|
Packit Service |
b0a153 |
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
|
|
Packit Service |
b0a153 |
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
|
|
Packit Service |
b0a153 |
windows_transfer_callback(backend, itransfer, io_result, io_size);
|
|
Packit Service |
b0a153 |
break;
|
|
Packit Service |
b0a153 |
case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
|
|
Packit Service |
b0a153 |
usbi_warn(ITRANSFER_CTX(itransfer), "bulk stream transfers are not yet supported on this platform");
|
|
Packit Service |
b0a153 |
break;
|
|
Packit Service |
b0a153 |
default:
|
|
Packit Service |
b0a153 |
usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_init(struct libusb_context *ctx)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(ctx);
|
|
Packit Service |
b0a153 |
HANDLE semaphore;
|
|
Packit Service |
b0a153 |
char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
|
|
Packit Service |
b0a153 |
int r = LIBUSB_ERROR_OTHER;
|
|
Packit Service |
b0a153 |
bool winusb_backend_init = false;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF));
|
|
Packit Service |
b0a153 |
semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name);
|
|
Packit Service |
b0a153 |
if (semaphore == NULL) {
|
|
Packit Service |
b0a153 |
usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0));
|
|
Packit Service |
b0a153 |
return LIBUSB_ERROR_NO_MEM;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// A successful wait brings our semaphore count to 0 (unsignaled)
|
|
Packit Service |
b0a153 |
// => any concurent wait stalls until the semaphore's release
|
|
Packit Service |
b0a153 |
if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
|
|
Packit Service |
b0a153 |
usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0));
|
|
Packit Service |
b0a153 |
CloseHandle(semaphore);
|
|
Packit Service |
b0a153 |
return LIBUSB_ERROR_NO_MEM;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// NB: concurrent usage supposes that init calls are equally balanced with
|
|
Packit Service |
b0a153 |
// exit calls. If init is called more than exit, we will not exit properly
|
|
Packit Service |
b0a153 |
if (++init_count == 1) { // First init?
|
|
Packit Service |
b0a153 |
// Load DLL imports
|
|
Packit Service |
b0a153 |
if (!windows_init_dlls()) {
|
|
Packit Service |
b0a153 |
usbi_err(ctx, "could not resolve DLL functions");
|
|
Packit Service |
b0a153 |
goto init_exit;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
get_windows_version();
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if (windows_version == WINDOWS_UNDEFINED) {
|
|
Packit Service |
b0a153 |
usbi_err(ctx, "failed to detect Windows version");
|
|
Packit Service |
b0a153 |
r = LIBUSB_ERROR_NOT_SUPPORTED;
|
|
Packit Service |
b0a153 |
goto init_exit;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if (!windows_init_clock(ctx))
|
|
Packit Service |
b0a153 |
goto init_exit;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if (!htab_create(ctx))
|
|
Packit Service |
b0a153 |
goto init_exit;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
r = winusb_backend.init(ctx);
|
|
Packit Service |
b0a153 |
if (r != LIBUSB_SUCCESS)
|
|
Packit Service |
b0a153 |
goto init_exit;
|
|
Packit Service |
b0a153 |
winusb_backend_init = true;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
r = usbdk_backend.init(ctx);
|
|
Packit Service |
b0a153 |
if (r == LIBUSB_SUCCESS) {
|
|
Packit Service |
b0a153 |
usbi_dbg("UsbDk backend is available");
|
|
Packit Service |
b0a153 |
usbdk_available = true;
|
|
Packit Service |
b0a153 |
} else {
|
|
Packit Service |
b0a153 |
usbi_info(ctx, "UsbDk backend is not available");
|
|
Packit Service |
b0a153 |
// Do not report this as an error
|
|
Packit Service |
b0a153 |
r = LIBUSB_SUCCESS;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// By default, new contexts will use the WinUSB backend
|
|
Packit Service |
b0a153 |
priv->backend = &winusb_backend;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
r = LIBUSB_SUCCESS;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
init_exit: // Holds semaphore here
|
|
Packit Service |
b0a153 |
if ((init_count == 1) && (r != LIBUSB_SUCCESS)) { // First init failed?
|
|
Packit Service |
b0a153 |
if (winusb_backend_init)
|
|
Packit Service |
b0a153 |
winusb_backend.exit(ctx);
|
|
Packit Service |
b0a153 |
htab_destroy();
|
|
Packit Service |
b0a153 |
windows_destroy_clock();
|
|
Packit Service |
b0a153 |
windows_exit_dlls();
|
|
Packit Service |
b0a153 |
--init_count;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
|
|
Packit Service |
b0a153 |
CloseHandle(semaphore);
|
|
Packit Service |
b0a153 |
return r;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static void windows_exit(struct libusb_context *ctx)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
HANDLE semaphore;
|
|
Packit Service |
b0a153 |
char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
|
|
Packit Service |
b0a153 |
UNUSED(ctx);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF));
|
|
Packit Service |
b0a153 |
semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name);
|
|
Packit Service |
b0a153 |
if (semaphore == NULL)
|
|
Packit Service |
b0a153 |
return;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// A successful wait brings our semaphore count to 0 (unsignaled)
|
|
Packit Service |
b0a153 |
// => any concurent wait stalls until the semaphore release
|
|
Packit Service |
b0a153 |
if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
|
|
Packit Service |
b0a153 |
CloseHandle(semaphore);
|
|
Packit Service |
b0a153 |
return;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Only works if exits and inits are balanced exactly
|
|
Packit Service |
b0a153 |
if (--init_count == 0) { // Last exit
|
|
Packit Service |
b0a153 |
if (usbdk_available) {
|
|
Packit Service |
b0a153 |
usbdk_backend.exit(ctx);
|
|
Packit Service |
b0a153 |
usbdk_available = false;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
winusb_backend.exit(ctx);
|
|
Packit Service |
b0a153 |
htab_destroy();
|
|
Packit Service |
b0a153 |
windows_destroy_clock();
|
|
Packit Service |
b0a153 |
windows_exit_dlls();
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
|
|
Packit Service |
b0a153 |
CloseHandle(semaphore);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_set_option(struct libusb_context *ctx, enum libusb_option option, va_list ap)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(ctx);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
UNUSED(ap);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
switch (option) {
|
|
Packit Service |
b0a153 |
case LIBUSB_OPTION_USE_USBDK:
|
|
Packit Service |
b0a153 |
if (usbdk_available) {
|
|
Packit Service |
b0a153 |
usbi_dbg("switching context %p to use UsbDk backend", ctx);
|
|
Packit Service |
b0a153 |
priv->backend = &usbdk_backend;
|
|
Packit Service |
b0a153 |
} else {
|
|
Packit Service |
b0a153 |
usbi_err(ctx, "UsbDk backend not available");
|
|
Packit Service |
b0a153 |
return LIBUSB_ERROR_NOT_FOUND;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
return LIBUSB_SUCCESS;
|
|
Packit Service |
b0a153 |
default:
|
|
Packit Service |
b0a153 |
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **discdevs)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(ctx);
|
|
Packit Service |
b0a153 |
return priv->backend->get_device_list(ctx, discdevs);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_open(struct libusb_device_handle *dev_handle)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
|
|
Packit Service |
b0a153 |
return priv->backend->open(dev_handle);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static void windows_close(struct libusb_device_handle *dev_handle)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
|
|
Packit Service |
b0a153 |
priv->backend->close(dev_handle);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_get_device_descriptor(struct libusb_device *dev,
|
|
Packit Service |
b0a153 |
unsigned char *buffer, int *host_endian)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
|
|
Packit Service |
b0a153 |
*host_endian = 0;
|
|
Packit Service |
b0a153 |
return priv->backend->get_device_descriptor(dev, buffer);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_get_active_config_descriptor(struct libusb_device *dev,
|
|
Packit Service |
b0a153 |
unsigned char *buffer, size_t len, int *host_endian)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
|
|
Packit Service |
b0a153 |
*host_endian = 0;
|
|
Packit Service |
b0a153 |
return priv->backend->get_active_config_descriptor(dev, buffer, len);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_get_config_descriptor(struct libusb_device *dev,
|
|
Packit Service |
b0a153 |
uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
|
|
Packit Service |
b0a153 |
*host_endian = 0;
|
|
Packit Service |
b0a153 |
return priv->backend->get_config_descriptor(dev, config_index, buffer, len);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_get_config_descriptor_by_value(struct libusb_device *dev,
|
|
Packit Service |
b0a153 |
uint8_t bConfigurationValue, unsigned char **buffer, int *host_endian)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
|
|
Packit Service |
b0a153 |
*host_endian = 0;
|
|
Packit Service |
b0a153 |
return priv->backend->get_config_descriptor_by_value(dev, bConfigurationValue, buffer);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_get_configuration(struct libusb_device_handle *dev_handle, int *config)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
|
|
Packit Service |
b0a153 |
return priv->backend->get_configuration(dev_handle, config);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_set_configuration(struct libusb_device_handle *dev_handle, int config)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
|
|
Packit Service |
b0a153 |
return priv->backend->set_configuration(dev_handle, config);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_claim_interface(struct libusb_device_handle *dev_handle, int interface_number)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
|
|
Packit Service |
b0a153 |
return priv->backend->claim_interface(dev_handle, interface_number);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_release_interface(struct libusb_device_handle *dev_handle, int interface_number)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
|
|
Packit Service |
b0a153 |
return priv->backend->release_interface(dev_handle, interface_number);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle,
|
|
Packit Service |
b0a153 |
int interface_number, int altsetting)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
|
|
Packit Service |
b0a153 |
return priv->backend->set_interface_altsetting(dev_handle, interface_number, altsetting);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
|
|
Packit Service |
b0a153 |
return priv->backend->clear_halt(dev_handle, endpoint);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_reset_device(struct libusb_device_handle *dev_handle)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
|
|
Packit Service |
b0a153 |
return priv->backend->reset_device(dev_handle);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static void windows_destroy_device(struct libusb_device *dev)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
|
|
Packit Service |
b0a153 |
priv->backend->destroy_device(dev);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_submit_transfer(struct usbi_transfer *itransfer)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer));
|
|
Packit Service |
b0a153 |
return priv->backend->submit_transfer(itransfer);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_cancel_transfer(struct usbi_transfer *itransfer)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer));
|
|
Packit Service |
b0a153 |
return priv->backend->cancel_transfer(itransfer);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static void windows_clear_transfer_priv(struct usbi_transfer *itransfer)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer));
|
|
Packit Service |
b0a153 |
priv->backend->clear_transfer_priv(itransfer);
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct windows_context_priv *priv = _context_priv(ctx);
|
|
Packit Service |
b0a153 |
struct usbi_transfer *itransfer;
|
|
Packit Service |
b0a153 |
DWORD io_size, io_result;
|
|
Packit Service |
b0a153 |
POLL_NFDS_TYPE i;
|
|
Packit Service |
b0a153 |
bool found;
|
|
Packit Service |
b0a153 |
int transfer_fd;
|
|
Packit Service |
b0a153 |
int r = LIBUSB_SUCCESS;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
usbi_mutex_lock(&ctx->open_devs_lock);
|
|
Packit Service |
b0a153 |
for (i = 0; i < nfds && num_ready > 0; i++) {
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
usbi_dbg("checking fd %d with revents = %04x", fds[i].fd, fds[i].revents);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if (!fds[i].revents)
|
|
Packit Service |
b0a153 |
continue;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
num_ready--;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// Because a Windows OVERLAPPED is used for poll emulation,
|
|
Packit Service |
b0a153 |
// a pollable fd is created and stored with each transfer
|
|
Packit Service |
b0a153 |
found = false;
|
|
Packit Service |
b0a153 |
transfer_fd = -1;
|
|
Packit Service |
b0a153 |
usbi_mutex_lock(&ctx->flying_transfers_lock);
|
|
Packit Service |
b0a153 |
list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) {
|
|
Packit Service |
b0a153 |
transfer_fd = priv->backend->get_transfer_fd(itransfer);
|
|
Packit Service |
b0a153 |
if (transfer_fd == fds[i].fd) {
|
|
Packit Service |
b0a153 |
found = true;
|
|
Packit Service |
b0a153 |
break;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
usbi_mutex_unlock(&ctx->flying_transfers_lock);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if (found) {
|
|
Packit Service |
b0a153 |
priv->backend->get_overlapped_result(itransfer, &io_result, &io_size);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
usbi_remove_pollfd(ctx, transfer_fd);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// let handle_callback free the event using the transfer wfd
|
|
Packit Service |
b0a153 |
// If you don't use the transfer wfd, you run a risk of trying to free a
|
|
Packit Service |
b0a153 |
// newly allocated wfd that took the place of the one from the transfer.
|
|
Packit Service |
b0a153 |
windows_handle_callback(priv->backend, itransfer, io_result, io_size);
|
|
Packit Service |
b0a153 |
} else {
|
|
Packit Service |
b0a153 |
usbi_err(ctx, "could not find a matching transfer for fd %d", fds[i].fd);
|
|
Packit Service |
b0a153 |
r = LIBUSB_ERROR_NOT_FOUND;
|
|
Packit Service |
b0a153 |
break;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
usbi_mutex_unlock(&ctx->open_devs_lock);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
return r;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
static int windows_clock_gettime(int clk_id, struct timespec *tp)
|
|
Packit Service |
b0a153 |
{
|
|
Packit Service |
b0a153 |
struct timer_request request;
|
|
Packit Service |
b0a153 |
#if !defined(_MSC_VER) || (_MSC_VER < 1900)
|
|
Packit Service |
b0a153 |
FILETIME filetime;
|
|
Packit Service |
b0a153 |
ULARGE_INTEGER rtime;
|
|
Packit Service |
b0a153 |
#endif
|
|
Packit Service |
b0a153 |
DWORD r;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
switch (clk_id) {
|
|
Packit Service |
b0a153 |
case USBI_CLOCK_MONOTONIC:
|
|
Packit Service |
b0a153 |
if (timer_thread) {
|
|
Packit Service |
b0a153 |
request.tp = tp;
|
|
Packit Service |
b0a153 |
request.event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
Packit Service |
b0a153 |
if (request.event == NULL)
|
|
Packit Service |
b0a153 |
return LIBUSB_ERROR_NO_MEM;
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if (!pPostThreadMessageA(timer_thread_id, WM_TIMER_REQUEST, 0, (LPARAM)&request)) {
|
|
Packit Service |
b0a153 |
usbi_err(NULL, "PostThreadMessage failed for timer thread: %s", windows_error_str(0));
|
|
Packit Service |
b0a153 |
CloseHandle(request.event);
|
|
Packit Service |
b0a153 |
return LIBUSB_ERROR_OTHER;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
do {
|
|
Packit Service |
b0a153 |
r = WaitForSingleObject(request.event, TIMER_REQUEST_RETRY_MS);
|
|
Packit Service |
b0a153 |
if (r == WAIT_TIMEOUT)
|
|
Packit Service |
b0a153 |
usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?");
|
|
Packit Service |
b0a153 |
else if (r == WAIT_FAILED)
|
|
Packit Service |
b0a153 |
usbi_err(NULL, "WaitForSingleObject failed: %s", windows_error_str(0));
|
|
Packit Service |
b0a153 |
} while (r == WAIT_TIMEOUT);
|
|
Packit Service |
b0a153 |
CloseHandle(request.event);
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
if (r == WAIT_OBJECT_0)
|
|
Packit Service |
b0a153 |
return LIBUSB_SUCCESS;
|
|
Packit Service |
b0a153 |
else
|
|
Packit Service |
b0a153 |
return LIBUSB_ERROR_OTHER;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
// Fall through and return real-time if monotonic was not detected @ timer init
|
|
Packit Service |
b0a153 |
case USBI_CLOCK_REALTIME:
|
|
Packit Service |
b0a153 |
#if defined(_MSC_VER) && (_MSC_VER >= 1900)
|
|
Packit Service |
b0a153 |
timespec_get(tp, TIME_UTC);
|
|
Packit Service |
b0a153 |
#else
|
|
Packit Service |
b0a153 |
// We follow http://msdn.microsoft.com/en-us/library/ms724928%28VS.85%29.aspx
|
|
Packit Service |
b0a153 |
// with a predef epoch time to have an epoch that starts at 1970.01.01 00:00
|
|
Packit Service |
b0a153 |
// Note however that our resolution is bounded by the Windows system time
|
|
Packit Service |
b0a153 |
// functions and is at best of the order of 1 ms (or, usually, worse)
|
|
Packit Service |
b0a153 |
GetSystemTimeAsFileTime(&filetime);
|
|
Packit Service |
b0a153 |
rtime.LowPart = filetime.dwLowDateTime;
|
|
Packit Service |
b0a153 |
rtime.HighPart = filetime.dwHighDateTime;
|
|
Packit Service |
b0a153 |
rtime.QuadPart -= EPOCH_TIME;
|
|
Packit Service |
b0a153 |
tp->tv_sec = (long)(rtime.QuadPart / 10000000);
|
|
Packit Service |
b0a153 |
tp->tv_nsec = (long)((rtime.QuadPart % 10000000) * 100);
|
|
Packit Service |
b0a153 |
#endif
|
|
Packit Service |
b0a153 |
return LIBUSB_SUCCESS;
|
|
Packit Service |
b0a153 |
default:
|
|
Packit Service |
b0a153 |
return LIBUSB_ERROR_INVALID_PARAM;
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
}
|
|
Packit Service |
b0a153 |
|
|
Packit Service |
b0a153 |
// NB: MSVC6 does not support named initializers.
|
|
Packit Service |
b0a153 |
const struct usbi_os_backend usbi_backend = {
|
|
Packit Service |
b0a153 |
"Windows",
|
|
Packit Service |
b0a153 |
USBI_CAP_HAS_HID_ACCESS,
|
|
Packit Service |
b0a153 |
windows_init,
|
|
Packit Service |
b0a153 |
windows_exit,
|
|
Packit Service |
b0a153 |
windows_set_option,
|
|
Packit Service |
b0a153 |
windows_get_device_list,
|
|
Packit Service |
b0a153 |
NULL, /* hotplug_poll */
|
|
Packit Service |
b0a153 |
NULL, /* wrap_sys_device */
|
|
Packit Service |
b0a153 |
windows_open,
|
|
Packit Service |
b0a153 |
windows_close,
|
|
Packit Service |
b0a153 |
windows_get_device_descriptor,
|
|
Packit Service |
b0a153 |
windows_get_active_config_descriptor,
|
|
Packit Service |
b0a153 |
windows_get_config_descriptor,
|
|
Packit Service |
b0a153 |
windows_get_config_descriptor_by_value,
|
|
Packit Service |
b0a153 |
windows_get_configuration,
|
|
Packit Service |
b0a153 |
windows_set_configuration,
|
|
Packit Service |
b0a153 |
windows_claim_interface,
|
|
Packit Service |
b0a153 |
windows_release_interface,
|
|
Packit Service |
b0a153 |
windows_set_interface_altsetting,
|
|
Packit Service |
b0a153 |
windows_clear_halt,
|
|
Packit Service |
b0a153 |
windows_reset_device,
|
|
Packit Service |
b0a153 |
NULL, /* alloc_streams */
|
|
Packit Service |
b0a153 |
NULL, /* free_streams */
|
|
Packit Service |
b0a153 |
NULL, /* dev_mem_alloc */
|
|
Packit Service |
b0a153 |
NULL, /* dev_mem_free */
|
|
Packit Service |
b0a153 |
NULL, /* kernel_driver_active */
|
|
Packit Service |
b0a153 |
NULL, /* detach_kernel_driver */
|
|
Packit Service |
b0a153 |
NULL, /* attach_kernel_driver */
|
|
Packit Service |
b0a153 |
windows_destroy_device,
|
|
Packit Service |
b0a153 |
windows_submit_transfer,
|
|
Packit Service |
b0a153 |
windows_cancel_transfer,
|
|
Packit Service |
b0a153 |
windows_clear_transfer_priv,
|
|
Packit Service |
b0a153 |
windows_handle_events,
|
|
Packit Service |
b0a153 |
NULL, /* handle_transfer_completion */
|
|
Packit Service |
b0a153 |
windows_clock_gettime,
|
|
Packit Service |
b0a153 |
sizeof(struct windows_context_priv),
|
|
Packit Service |
b0a153 |
sizeof(union windows_device_priv),
|
|
Packit Service |
b0a153 |
sizeof(union windows_device_handle_priv),
|
|
Packit Service |
b0a153 |
sizeof(union windows_transfer_priv),
|
|
Packit Service |
b0a153 |
};
|