2 * windows backend for libusb 1.0
3 * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
4 * With contributions from Michael Plante, Orin Eman et al.
5 * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
6 * HID Reports IOCTLs inspired from HIDAPI by Alan Ott, Signal 11 Software
7 * Hash table functions adapted from glibc, by Ulrich Drepper et al.
8 * Major code testing contribution by Xiaofan Chen
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
32 #include "windows_common.h"
34 #define EPOCH_TIME UINT64_C(116444736000000000) // 1970.01.01 00:00:000 in MS Filetime
37 enum windows_version windows_version = WINDOWS_UNDEFINED;
39 // Global variables for init/exit
40 static unsigned int init_count = 0;
41 static bool usbdk_available = false;
43 // Global variables for clock_gettime mechanism
44 static uint64_t hires_ticks_to_ps;
45 static uint64_t hires_frequency;
48 * Converts a windows error to human readable string
49 * uses retval as errorcode, or, if 0, use GetLastError()
51 #if defined(ENABLE_LOGGING)
52 const char *windows_error_str(DWORD error_code)
54 static char err_string[256];
60 error_code = GetLastError();
62 len = sprintf(err_string, "[%lu] ", error_code);
64 // Translate codes returned by SetupAPI. The ones we are dealing with are either
65 // in 0x0000xxxx or 0xE000xxxx and can be distinguished from standard error codes.
66 // See http://msdn.microsoft.com/en-us/library/windows/hardware/ff545011.aspx
67 switch (error_code & 0xE0000000) {
69 error_code = HRESULT_FROM_WIN32(error_code); // Still leaves ERROR_SUCCESS unmodified
72 error_code = 0x80000000 | (FACILITY_SETUPAPI << 16) | (error_code & 0x0000FFFF);
78 size = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
79 NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
80 &err_string[len], sizeof(err_string) - len, NULL);
82 DWORD format_error = GetLastError();
84 snprintf(err_string, sizeof(err_string),
85 "Windows error code %lu (FormatMessage error code %lu)",
86 error_code, format_error);
88 snprintf(err_string, sizeof(err_string), "Unknown error code %lu", error_code);
90 // Remove CRLF from end of message, if present
91 size_t pos = len + size - 2;
92 if (err_string[pos] == '\r')
93 err_string[pos] = '\0';
100 static inline struct windows_context_priv *_context_priv(struct libusb_context *ctx)
102 return (struct windows_context_priv *)ctx->os_priv;
105 /* Hash table functions - modified From glibc 2.3.2:
106 [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
107 [Knuth] The Art of Computer Programming, part 3 (6.4) */
109 #define HTAB_SIZE 1021UL // *MUST* be a prime number!!
111 typedef struct htab_entry {
116 static htab_entry *htab_table = NULL;
117 static usbi_mutex_t htab_mutex;
118 static unsigned long htab_filled;
120 /* Before using the hash table we must allocate memory for it.
121 We allocate one element more as the found prime number says.
122 This is done for more effective indexing as explained in the
123 comment for the hash function. */
124 static bool htab_create(struct libusb_context *ctx)
126 if (htab_table != NULL) {
127 usbi_err(ctx, "hash table already allocated");
132 usbi_mutex_init(&htab_mutex);
134 usbi_dbg("using %lu entries hash table", HTAB_SIZE);
137 // allocate memory and zero out.
138 htab_table = calloc(HTAB_SIZE + 1, sizeof(htab_entry));
139 if (htab_table == NULL) {
140 usbi_err(ctx, "could not allocate space for hash table");
147 /* After using the hash table it has to be destroyed. */
148 static void htab_destroy(void)
152 if (htab_table == NULL)
155 for (i = 0; i < HTAB_SIZE; i++)
156 free(htab_table[i].str);
158 safe_free(htab_table);
160 usbi_mutex_destroy(&htab_mutex);
163 /* This is the search function. It uses double hashing with open addressing.
164 We use a trick to speed up the lookup. The table is created with one
165 more element available. This enables us to use the index zero special.
166 This index will never be used because we store the first hash index in
167 the field used where zero means not used. Every other value means used.
168 The used field can be used as a first fast comparison for equality of
169 the stored and the parameter value. This helps to prevent unnecessary
170 expensive calls of strcmp. */
171 unsigned long htab_hash(const char *str)
173 unsigned long hval, hval2;
175 unsigned long r = 5381;
177 const char *sz = str;
182 // Compute main hash value (algorithm suggested by Nokia)
183 while ((c = *sz++) != 0)
184 r = ((r << 5) + r) + c;
188 // compute table hash: simply take the modulus
189 hval = r % HTAB_SIZE;
193 // Try the first index
196 // Mutually exclusive access (R/W lock would be better)
197 usbi_mutex_lock(&htab_mutex);
199 if (htab_table[idx].used) {
200 if ((htab_table[idx].used == hval) && (strcmp(str, htab_table[idx].str) == 0))
201 goto out_unlock; // existing hash
203 usbi_dbg("hash collision ('%s' vs '%s')", str, htab_table[idx].str);
205 // Second hash function, as suggested in [Knuth]
206 hval2 = 1 + hval % (HTAB_SIZE - 2);
209 // Because size is prime this guarantees to step through all available indexes
211 idx = HTAB_SIZE + idx - hval2;
215 // If we visited all entries leave the loop unsuccessfully
219 // If entry is found use it.
220 if ((htab_table[idx].used == hval) && (strcmp(str, htab_table[idx].str) == 0))
222 } while (htab_table[idx].used);
225 // Not found => New entry
227 // If the table is full return an error
228 if (htab_filled >= HTAB_SIZE) {
229 usbi_err(NULL, "hash table is full (%lu entries)", HTAB_SIZE);
234 htab_table[idx].str = _strdup(str);
235 if (htab_table[idx].str == NULL) {
236 usbi_err(NULL, "could not duplicate string for hash table");
241 htab_table[idx].used = hval;
245 usbi_mutex_unlock(&htab_mutex);
251 * Make a transfer complete synchronously
253 void windows_force_sync_completion(OVERLAPPED *overlapped, ULONG size)
255 overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
256 overlapped->InternalHigh = size;
257 SetEvent(overlapped->hEvent);
260 static void windows_init_clock(void)
262 LARGE_INTEGER li_frequency;
264 // Microsoft says that the QueryPerformanceFrequency() and
265 // QueryPerformanceCounter() functions always succeed on XP and later
266 QueryPerformanceFrequency(&li_frequency);
268 // The hires frequency can go as high as 4 GHz, so we'll use a conversion
269 // to picoseconds to compute the tv_nsecs part in clock_gettime
270 hires_frequency = li_frequency.QuadPart;
271 hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency;
272 usbi_dbg("hires timer frequency: %"PRIu64" Hz", hires_frequency);
275 /* Windows version detection */
276 static BOOL is_x64(void)
280 // Detect if we're running a 32 or 64 bit system
281 if (sizeof(uintptr_t) < 8) {
282 IsWow64Process(GetCurrentProcess(), &ret);
290 static void get_windows_version(void)
292 OSVERSIONINFOEXA vi, vi2;
293 const char *arch, *w = NULL;
294 unsigned major, minor, version;
295 ULONGLONG major_equal, minor_equal;
298 windows_version = WINDOWS_UNDEFINED;
300 memset(&vi, 0, sizeof(vi));
301 vi.dwOSVersionInfoSize = sizeof(vi);
302 if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
303 memset(&vi, 0, sizeof(vi));
304 vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
305 if (!GetVersionExA((OSVERSIONINFOA *)&vi))
309 if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT)
312 if ((vi.dwMajorVersion > 6) || ((vi.dwMajorVersion == 6) && (vi.dwMinorVersion >= 2))) {
313 // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the actual OS version
314 // See: http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
316 major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
317 for (major = vi.dwMajorVersion; major <= 9; major++) {
318 memset(&vi2, 0, sizeof(vi2));
319 vi2.dwOSVersionInfoSize = sizeof(vi2);
320 vi2.dwMajorVersion = major;
321 if (!VerifyVersionInfoA(&vi2, VER_MAJORVERSION, major_equal))
324 if (vi.dwMajorVersion < major) {
325 vi.dwMajorVersion = major;
326 vi.dwMinorVersion = 0;
329 minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL);
330 for (minor = vi.dwMinorVersion; minor <= 9; minor++) {
331 memset(&vi2, 0, sizeof(vi2));
332 vi2.dwOSVersionInfoSize = sizeof(vi2);
333 vi2.dwMinorVersion = minor;
334 if (!VerifyVersionInfoA(&vi2, VER_MINORVERSION, minor_equal))
337 vi.dwMinorVersion = minor;
345 if ((vi.dwMajorVersion > 0xf) || (vi.dwMinorVersion > 0xf))
348 ws = (vi.wProductType <= VER_NT_WORKSTATION);
349 version = vi.dwMajorVersion << 4 | vi.dwMinorVersion;
351 case 0x50: windows_version = WINDOWS_2000; w = "2000"; break;
352 case 0x51: windows_version = WINDOWS_XP; w = "XP"; break;
353 case 0x52: windows_version = WINDOWS_2003; w = "2003"; break;
354 case 0x60: windows_version = WINDOWS_VISTA; w = (ws ? "Vista" : "2008"); break;
355 case 0x61: windows_version = WINDOWS_7; w = (ws ? "7" : "2008_R2"); break;
356 case 0x62: windows_version = WINDOWS_8; w = (ws ? "8" : "2012"); break;
357 case 0x63: windows_version = WINDOWS_8_1; w = (ws ? "8.1" : "2012_R2"); break;
358 case 0x64: // Early Windows 10 Insider Previews and Windows Server 2017 Technical Preview 1 used version 6.4
359 case 0xA0: windows_version = WINDOWS_10; w = (ws ? "10" : "2016"); break;
361 if (version < 0x50) {
364 windows_version = WINDOWS_11_OR_LATER;
369 arch = is_x64() ? "64-bit" : "32-bit";
371 if (vi.wServicePackMinor)
372 usbi_dbg("Windows %s SP%u.%u %s", w, vi.wServicePackMajor, vi.wServicePackMinor, arch);
373 else if (vi.wServicePackMajor)
374 usbi_dbg("Windows %s SP%u %s", w, vi.wServicePackMajor, arch);
376 usbi_dbg("Windows %s %s", w, arch);
379 static void windows_transfer_callback(const struct windows_backend *backend,
380 struct usbi_transfer *itransfer, DWORD io_result, DWORD io_size)
384 usbi_dbg("handling I/O completion with errcode %lu, size %lu", io_result, io_size);
388 status = backend->copy_transfer_data(itransfer, (uint32_t)io_size);
390 case ERROR_GEN_FAILURE:
391 usbi_dbg("detected endpoint stall");
392 status = LIBUSB_TRANSFER_STALL;
394 case ERROR_SEM_TIMEOUT:
395 usbi_dbg("detected semaphore timeout");
396 status = LIBUSB_TRANSFER_TIMED_OUT;
398 case ERROR_OPERATION_ABORTED:
399 istatus = backend->copy_transfer_data(itransfer, (uint32_t)io_size);
400 if (istatus != LIBUSB_TRANSFER_COMPLETED)
401 usbi_dbg("Failed to copy partial data in aborted operation: %d", istatus);
403 usbi_dbg("detected operation aborted");
404 status = LIBUSB_TRANSFER_CANCELLED;
406 case ERROR_FILE_NOT_FOUND:
407 case ERROR_DEVICE_NOT_CONNECTED:
408 usbi_dbg("detected device removed");
409 status = LIBUSB_TRANSFER_NO_DEVICE;
412 usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error %lu: %s", io_result, windows_error_str(io_result));
413 status = LIBUSB_TRANSFER_ERROR;
416 backend->clear_transfer_priv(itransfer); // Cancel polling
417 if (status == LIBUSB_TRANSFER_CANCELLED)
418 usbi_handle_transfer_cancellation(itransfer);
420 usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status);
423 static void windows_handle_callback(const struct windows_backend *backend,
424 struct usbi_transfer *itransfer, DWORD io_result, DWORD io_size)
426 struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
428 switch (transfer->type) {
429 case LIBUSB_TRANSFER_TYPE_CONTROL:
430 case LIBUSB_TRANSFER_TYPE_BULK:
431 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
432 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
433 windows_transfer_callback(backend, itransfer, io_result, io_size);
435 case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
436 usbi_warn(ITRANSFER_CTX(itransfer), "bulk stream transfers are not yet supported on this platform");
439 usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
443 static int windows_init(struct libusb_context *ctx)
445 struct windows_context_priv *priv = _context_priv(ctx);
447 char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
448 int r = LIBUSB_ERROR_OTHER;
449 bool winusb_backend_init = false;
451 sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF));
452 semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name);
453 if (semaphore == NULL) {
454 usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0));
455 return LIBUSB_ERROR_NO_MEM;
458 // A successful wait brings our semaphore count to 0 (unsignaled)
459 // => any concurent wait stalls until the semaphore's release
460 if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
461 usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0));
462 CloseHandle(semaphore);
463 return LIBUSB_ERROR_NO_MEM;
466 // NB: concurrent usage supposes that init calls are equally balanced with
467 // exit calls. If init is called more than exit, we will not exit properly
468 if (++init_count == 1) { // First init?
469 get_windows_version();
471 if (windows_version == WINDOWS_UNDEFINED) {
472 usbi_err(ctx, "failed to detect Windows version");
473 r = LIBUSB_ERROR_NOT_SUPPORTED;
477 windows_init_clock();
479 if (!htab_create(ctx))
482 r = winusb_backend.init(ctx);
483 if (r != LIBUSB_SUCCESS)
485 winusb_backend_init = true;
487 r = usbdk_backend.init(ctx);
488 if (r == LIBUSB_SUCCESS) {
489 usbi_dbg("UsbDk backend is available");
490 usbdk_available = true;
492 usbi_info(ctx, "UsbDk backend is not available");
493 // Do not report this as an error
498 // By default, new contexts will use the WinUSB backend
499 priv->backend = &winusb_backend;
503 init_exit: // Holds semaphore here
504 if ((init_count == 1) && (r != LIBUSB_SUCCESS)) { // First init failed?
505 if (winusb_backend_init)
506 winusb_backend.exit(ctx);
511 ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
512 CloseHandle(semaphore);
516 static void windows_exit(struct libusb_context *ctx)
519 char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
522 sprintf(sem_name, "libusb_init%08lX", (GetCurrentProcessId() & 0xFFFFFFFFUL));
523 semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name);
524 if (semaphore == NULL)
527 // A successful wait brings our semaphore count to 0 (unsignaled)
528 // => any concurent wait stalls until the semaphore release
529 if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
530 CloseHandle(semaphore);
534 // Only works if exits and inits are balanced exactly
535 if (--init_count == 0) { // Last exit
536 if (usbdk_available) {
537 usbdk_backend.exit(ctx);
538 usbdk_available = false;
540 winusb_backend.exit(ctx);
544 ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
545 CloseHandle(semaphore);
548 static int windows_set_option(struct libusb_context *ctx, enum libusb_option option, va_list ap)
550 struct windows_context_priv *priv = _context_priv(ctx);
555 case LIBUSB_OPTION_USE_USBDK:
556 if (usbdk_available) {
557 usbi_dbg("switching context %p to use UsbDk backend", ctx);
558 priv->backend = &usbdk_backend;
560 usbi_err(ctx, "UsbDk backend not available");
561 return LIBUSB_ERROR_NOT_FOUND;
563 return LIBUSB_SUCCESS;
565 return LIBUSB_ERROR_NOT_SUPPORTED;
570 static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **discdevs)
572 struct windows_context_priv *priv = _context_priv(ctx);
573 return priv->backend->get_device_list(ctx, discdevs);
576 static int windows_open(struct libusb_device_handle *dev_handle)
578 struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
579 return priv->backend->open(dev_handle);
582 static void windows_close(struct libusb_device_handle *dev_handle)
584 struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
585 priv->backend->close(dev_handle);
588 static int windows_get_device_descriptor(struct libusb_device *dev,
589 unsigned char *buffer, int *host_endian)
591 struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
593 return priv->backend->get_device_descriptor(dev, buffer);
596 static int windows_get_active_config_descriptor(struct libusb_device *dev,
597 unsigned char *buffer, size_t len, int *host_endian)
599 struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
601 return priv->backend->get_active_config_descriptor(dev, buffer, len);
604 static int windows_get_config_descriptor(struct libusb_device *dev,
605 uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
607 struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
609 return priv->backend->get_config_descriptor(dev, config_index, buffer, len);
612 static int windows_get_config_descriptor_by_value(struct libusb_device *dev,
613 uint8_t bConfigurationValue, unsigned char **buffer, int *host_endian)
615 struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
617 return priv->backend->get_config_descriptor_by_value(dev, bConfigurationValue, buffer);
620 static int windows_get_configuration(struct libusb_device_handle *dev_handle, int *config)
622 struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
623 return priv->backend->get_configuration(dev_handle, config);
626 static int windows_set_configuration(struct libusb_device_handle *dev_handle, int config)
628 struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
629 return priv->backend->set_configuration(dev_handle, config);
632 static int windows_claim_interface(struct libusb_device_handle *dev_handle, int interface_number)
634 struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
635 return priv->backend->claim_interface(dev_handle, interface_number);
638 static int windows_release_interface(struct libusb_device_handle *dev_handle, int interface_number)
640 struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
641 return priv->backend->release_interface(dev_handle, interface_number);
644 static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle,
645 int interface_number, int altsetting)
647 struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
648 return priv->backend->set_interface_altsetting(dev_handle, interface_number, altsetting);
651 static int windows_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
653 struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
654 return priv->backend->clear_halt(dev_handle, endpoint);
657 static int windows_reset_device(struct libusb_device_handle *dev_handle)
659 struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
660 return priv->backend->reset_device(dev_handle);
663 static void windows_destroy_device(struct libusb_device *dev)
665 struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
666 priv->backend->destroy_device(dev);
669 static int windows_submit_transfer(struct usbi_transfer *itransfer)
671 struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer));
672 return priv->backend->submit_transfer(itransfer);
675 static int windows_cancel_transfer(struct usbi_transfer *itransfer)
677 struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer));
678 return priv->backend->cancel_transfer(itransfer);
681 static void windows_clear_transfer_priv(struct usbi_transfer *itransfer)
683 struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer));
684 priv->backend->clear_transfer_priv(itransfer);
687 static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready)
689 struct windows_context_priv *priv = _context_priv(ctx);
690 struct usbi_transfer *itransfer;
691 DWORD io_size, io_result;
695 int r = LIBUSB_SUCCESS;
697 usbi_mutex_lock(&ctx->open_devs_lock);
698 for (i = 0; i < nfds && num_ready > 0; i++) {
700 usbi_dbg("checking fd %d with revents = %04x", fds[i].fd, fds[i].revents);
707 // Because a Windows OVERLAPPED is used for poll emulation,
708 // a pollable fd is created and stored with each transfer
711 usbi_mutex_lock(&ctx->flying_transfers_lock);
712 list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) {
713 transfer_fd = priv->backend->get_transfer_fd(itransfer);
714 if (transfer_fd == fds[i].fd) {
719 usbi_mutex_unlock(&ctx->flying_transfers_lock);
722 priv->backend->get_overlapped_result(itransfer, &io_result, &io_size);
724 usbi_remove_pollfd(ctx, transfer_fd);
726 // let handle_callback free the event using the transfer wfd
727 // If you don't use the transfer wfd, you run a risk of trying to free a
728 // newly allocated wfd that took the place of the one from the transfer.
729 windows_handle_callback(priv->backend, itransfer, io_result, io_size);
731 usbi_err(ctx, "could not find a matching transfer for fd %d", fds[i].fd);
732 r = LIBUSB_ERROR_NOT_FOUND;
736 usbi_mutex_unlock(&ctx->open_devs_lock);
741 static int windows_clock_gettime(int clk_id, struct timespec *tp)
743 LARGE_INTEGER hires_counter;
744 #if !defined(_MSC_VER) || (_MSC_VER < 1900)
746 ULARGE_INTEGER rtime;
750 case USBI_CLOCK_MONOTONIC:
751 if (hires_frequency) {
752 QueryPerformanceCounter(&hires_counter);
753 tp->tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
754 tp->tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency) * hires_ticks_to_ps) / UINT64_C(1000));
755 return LIBUSB_SUCCESS;
757 // Fall through and return real-time if monotonic was not detected @ timer init
758 case USBI_CLOCK_REALTIME:
759 #if defined(_MSC_VER) && (_MSC_VER >= 1900)
760 if (!timespec_get(tp, TIME_UTC))
761 return LIBUSB_ERROR_OTHER;
763 // We follow http://msdn.microsoft.com/en-us/library/ms724928%28VS.85%29.aspx
764 // with a predef epoch time to have an epoch that starts at 1970.01.01 00:00
765 // Note however that our resolution is bounded by the Windows system time
766 // functions and is at best of the order of 1 ms (or, usually, worse)
767 GetSystemTimeAsFileTime(&filetime);
768 rtime.LowPart = filetime.dwLowDateTime;
769 rtime.HighPart = filetime.dwHighDateTime;
770 rtime.QuadPart -= EPOCH_TIME;
771 tp->tv_sec = (long)(rtime.QuadPart / 10000000);
772 tp->tv_nsec = (long)((rtime.QuadPart % 10000000) * 100);
774 return LIBUSB_SUCCESS;
776 return LIBUSB_ERROR_INVALID_PARAM;
780 // NB: MSVC6 does not support named initializers.
781 const struct usbi_os_backend usbi_backend = {
783 USBI_CAP_HAS_HID_ACCESS,
787 windows_get_device_list,
788 NULL, /* hotplug_poll */
789 NULL, /* wrap_sys_device */
792 windows_get_device_descriptor,
793 windows_get_active_config_descriptor,
794 windows_get_config_descriptor,
795 windows_get_config_descriptor_by_value,
796 windows_get_configuration,
797 windows_set_configuration,
798 windows_claim_interface,
799 windows_release_interface,
800 windows_set_interface_altsetting,
802 windows_reset_device,
803 NULL, /* alloc_streams */
804 NULL, /* free_streams */
805 NULL, /* dev_mem_alloc */
806 NULL, /* dev_mem_free */
807 NULL, /* kernel_driver_active */
808 NULL, /* detach_kernel_driver */
809 NULL, /* attach_kernel_driver */
810 windows_destroy_device,
811 windows_submit_transfer,
812 windows_cancel_transfer,
813 windows_clear_transfer_priv,
814 windows_handle_events,
815 NULL, /* handle_transfer_completion */
816 windows_clock_gettime,
817 sizeof(struct windows_context_priv),
818 sizeof(union windows_device_priv),
819 sizeof(union windows_device_handle_priv),
820 sizeof(union windows_transfer_priv),