Discussion:
[libusb] [PATCH 0/3] Introduce UsbDk support for Windows backend
Dmitry Fleytman
2015-03-02 17:59:33 UTC
Permalink
Hello libusb-devel,

This series contains patches that extend Windows backend to support UsbDk.
Switch between UsbDk and WinUSB/LibusbK/Libusb0 is done at compile time
with --enable-usbdk configuration option (off by default).

UsbDk (USB Development Kit) is a set of software components meant to provide
Windows user mode applications with direct and exclusive access to USB devices.

Some distinctive UsbDk properties are:

1. UsbDk supports all types of devices and interfaces - bulk, isochronous,
composite, HID etc.
2. Device capture process is totally dynamic, i.e. no inf files and
self-signing needed, any device can be captured.
3. UsbDk co-exists with original device driver, when the device is not
captured original driver is loaded by the system automatically.
4. If user mode client terminates unexpectedly for any reason system reverts
to original device driver immediately.
5. Being USB filter driver UsbDk doesn't require WHQL-ing
as per Microsoft requirements.

UsbDk supports all Windows OS versions staring from Windows XP,
i.e. XP/Vista/7/8/8.1/2003/2008/2008R2/2012/2012R2.
Both 32 and 64 bit architectures are supported.

UsbDk is fully open source and distributed under Apache 2.0 license.

UsbDk project is hosted at spice-space.org, source code repository available at:
http://cgit.freedesktop.org/spice/win32/usbdk

Latest source tarball is at: http://www.spice-space.org/download/windows/usbdk/spice-usbdk-win-1.0-2-sources.zip

UsbDk releases come with precompiled and signed by Red Hat binaries:
1. 32 bit: http://www.spice-space.org/download/windows/usbdk/UsbDk_1.0.2_x86.msi
2. 64 bit: http://www.spice-space.org/download/windows/usbdk/UsbDk_1.0.2_x64.msi

UsbDk documentation:
1. Short presentation: http://www.spice-space.org/docs/usbdk/UsbDk_at_a_Glance.pdf
2. SDM: http://www.spice-space.org/docs/usbdk/UsbDk_Software_Development_Manual.pdf
3. UsbDk architecture specificatin (part of source tree):
http://cgit.freedesktop.org/spice/win32/usbdk/tree/ARCHITECTURE

UsbDk is maintained by Dmitry Fleytman (***@redhat.com) and
Kirill Moizik (***@redhat.com) we'll be glad to answer your questions sent
to us directly or via this mailing list.

What do you think about this series?
We will be glad to have it accepted into libusb upstream.

Best Regards,
Dmitry

Dmitry Fleytman (3):
windows: Move common definitions to a separate file
usbdk: Introduce usbdk backend
build: Integrate usbdk backend

configure.ac | 9 +
libusb/Makefile.am | 14 +-
libusb/core.c | 6 +
libusb/libusbi.h | 1 +
libusb/os/UsbDk/UsbDkData.h | 100 +++++
libusb/os/UsbDk/UsbDkHelper.h | 239 ++++++++++++
libusb/os/windows_nt_common.c | 572 +++++++++++++++++++++++++++
libusb/os/windows_nt_common.h | 67 ++++
libusb/os/windows_usb.c | 556 ++------------------------
libusb/os/windows_usb.h | 14 +-
libusb/os/windows_usbdk.c | 890 ++++++++++++++++++++++++++++++++++++++++++
libusb/os/windows_usbdk.h | 24 ++
12 files changed, 1944 insertions(+), 548 deletions(-)
create mode 100644 libusb/os/UsbDk/UsbDkData.h
create mode 100644 libusb/os/UsbDk/UsbDkHelper.h
create mode 100644 libusb/os/windows_nt_common.c
create mode 100644 libusb/os/windows_nt_common.h
create mode 100755 libusb/os/windows_usbdk.c
create mode 100644 libusb/os/windows_usbdk.h
--
2.1.0
Dmitry Fleytman
2015-03-02 17:59:36 UTC
Permalink
Signed-off-by: Dmitry Fleytman <***@redhat.com>
---
configure.ac | 9 +++++++++
libusb/Makefile.am | 10 ++++++++--
2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/configure.ac b/configure.ac
index aeafcdc..79c7c5b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -172,6 +172,14 @@ windows)
LTLDFLAGS="${LTLDFLAGS} -avoid-version -Wl,--add-stdcall-alias"
AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[type of second poll() argument])
AC_DEFINE([WINVER], 0x0501, [Oldest Windows version supported])
+
+ AC_ARG_ENABLE([usbdk],
+ [AC_HELP_STRING([--enable-usbdk], [use UsbDk Windows backend [default=no]])],
+ [], [enable_usbdk="no"])
+ if test "x$enable_usbdk" = "xyes" ; then
+ AC_DEFINE(USE_USBDK, 1, [Use UsbDk Windows backend])
+ fi
+ AC_SUBST(USE_USBDK)
;;
haiku)
AC_DEFINE(OS_HAIKU, 1, [Haiku backend])
@@ -193,6 +201,7 @@ AM_CONDITIONAL(OS_HAIKU, test "x$backend" = xhaiku)
AM_CONDITIONAL(THREADS_POSIX, test "x$threads" = xposix)
AM_CONDITIONAL(CREATE_IMPORT_LIB, test "x$create_import_lib" = "xyes")
AM_CONDITIONAL(USE_UDEV, test "x$enable_udev" = xyes)
+AM_CONDITIONAL(USE_USBDK, test "x$enable_usbdk" = xyes)
if test "$threads" = posix; then
AC_DEFINE(THREADS_POSIX, 1, [Use POSIX Threads])
fi
diff --git a/libusb/Makefile.am b/libusb/Makefile.am
index fe9f649..4a1fd9a 100644
--- a/libusb/Makefile.am
+++ b/libusb/Makefile.am
@@ -11,12 +11,13 @@ OPENBSD_USB_SRC = os/openbsd_usb.c
NETBSD_USB_SRC = os/netbsd_usb.c
COMMON_WINDOWS_SRC = os/poll_windows.c os/windows_nt_common.c libusb-1.0.rc libusb-1.0.def
WINDOWS_USB_SRC = os/windows_usb.c $(COMMON_WINDOWS_SRC)
+WINDOWS_USBDK_SRC = os/windows_usbdk.c $(COMMON_WINDOWS_SRC)
WINCE_USB_SRC = os/wince_usb.c os/wince_usb.h

DIST_SUBDIRS =

EXTRA_DIST = $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) $(OPENBSD_USB_SRC) \
- $(NETBSD_USB_SRC) $(WINDOWS_USB_SRC) $(WINCE_USB_SRC) \
+ $(NETBSD_USB_SRC) $(WINDOWS_USB_SRC) $(WINDOWS_USBDK_SRC) $(WINCE_USB_SRC) \
$(POSIX_POLL_SRC) \
os/threads_posix.c os/threads_windows.c \
os/linux_udev.c os/linux_netlink.c
@@ -55,7 +56,12 @@ SUBDIRS = os/haiku
endif

if OS_WINDOWS
+
+if USE_USBDK
+OS_SRC = $(WINDOWS_USBDK_SRC)
+else
OS_SRC = $(WINDOWS_USB_SRC)
+endif

.rc.lo:
$(AM_V_GEN)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --tag=RC --mode=compile $(RC) $(RCFLAGS) -i $< -o $@
@@ -79,7 +85,7 @@ libusb_1_0_la_CFLAGS = $(AM_CFLAGS)
libusb_1_0_la_LDFLAGS = $(LTLDFLAGS)
libusb_1_0_la_SOURCES = libusbi.h core.c descriptor.c io.c strerror.c sync.c \
os/linux_usbfs.h os/darwin_usb.h os/windows_usb.h os/windows_common.h \
- os/windows_nt_common.h hotplug.h hotplug.c \
+ os/windows_nt_common.h os/windows_usbdk.h hotplug.h hotplug.c \
$(THREADS_SRC) $(OS_SRC) \
os/poll_posix.h os/poll_windows.h
--
2.1.0
Dmitry Fleytman
2015-03-02 17:59:35 UTC
Permalink
From: Dmitry Fleytman <***@redhat.com>

Signed-off-by: Pavel Gurvich <***@daynix.com>
Signed-off-by: Dmitry Fleytman <***@redhat.com>
---
libusb/core.c | 6 +
libusb/libusbi.h | 1 +
libusb/os/UsbDk/UsbDkData.h | 100 +++++
libusb/os/UsbDk/UsbDkHelper.h | 239 ++++++++++++
libusb/os/windows_usbdk.c | 890 ++++++++++++++++++++++++++++++++++++++++++
libusb/os/windows_usbdk.h | 24 ++
6 files changed, 1260 insertions(+)
create mode 100644 libusb/os/UsbDk/UsbDkData.h
create mode 100644 libusb/os/UsbDk/UsbDkHelper.h
create mode 100755 libusb/os/windows_usbdk.c
create mode 100644 libusb/os/windows_usbdk.h

diff --git a/libusb/core.c b/libusb/core.c
index 951e85d..db2eb4d 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -53,7 +53,13 @@ const struct usbi_os_backend * const usbi_backend = &openbsd_backend;
#elif defined(OS_NETBSD)
const struct usbi_os_backend * const usbi_backend = &netbsd_backend;
#elif defined(OS_WINDOWS)
+
+#if defined(USE_USBDK)
+const struct usbi_os_backend * const usbi_backend = &usbdk_backend;
+#else
const struct usbi_os_backend * const usbi_backend = &windows_backend;
+#endif
+
#elif defined(OS_WINCE)
const struct usbi_os_backend * const usbi_backend = &wince_backend;
#elif defined(OS_HAIKU)
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index 560e1ea..900c757 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -1092,6 +1092,7 @@ extern const struct usbi_os_backend darwin_backend;
extern const struct usbi_os_backend openbsd_backend;
extern const struct usbi_os_backend netbsd_backend;
extern const struct usbi_os_backend windows_backend;
+extern const struct usbi_os_backend usbdk_backend;
extern const struct usbi_os_backend wince_backend;
extern const struct usbi_os_backend haiku_usb_raw_backend;

diff --git a/libusb/os/UsbDk/UsbDkData.h b/libusb/os/UsbDk/UsbDkData.h
new file mode 100644
index 0000000..8cd3ea5
--- /dev/null
+++ b/libusb/os/UsbDk/UsbDkData.h
@@ -0,0 +1,100 @@
+/**********************************************************************
+* Copyright (c) 2013-2014 Red Hat, Inc.
+*
+* Developed by Daynix Computing LTD.
+*
+* Authors:
+* Dmitry Fleytman <***@daynix.com>
+* Pavel Gurvich <***@daynix.com>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+**********************************************************************/
+
+#pragma once
+
+typedef struct tag_USB_DK_DEVICE_ID
+{
+ WCHAR DeviceID[MAX_DEVICE_ID_LEN];
+ WCHAR InstanceID[MAX_DEVICE_ID_LEN];
+} USB_DK_DEVICE_ID, *PUSB_DK_DEVICE_ID;
+
+static inline
+void UsbDkFillIDStruct(USB_DK_DEVICE_ID *ID, PCWCHAR DeviceID, PCWCHAR InstanceID)
+{
+ wcsncpy_s(ID->DeviceID, DeviceID, MAX_DEVICE_ID_LEN);
+ wcsncpy_s(ID->InstanceID, InstanceID, MAX_DEVICE_ID_LEN);
+}
+
+typedef struct tag_USB_DK_DEVICE_INFO
+{
+ USB_DK_DEVICE_ID ID;
+ ULONG64 FilterID;
+ ULONG64 Port;
+ ULONG64 Speed;
+ USB_DEVICE_DESCRIPTOR DeviceDescriptor;
+} USB_DK_DEVICE_INFO, *PUSB_DK_DEVICE_INFO;
+
+typedef struct tag_USB_DK_CONFIG_DESCRIPTOR_REQUEST
+{
+ USB_DK_DEVICE_ID ID;
+ ULONG64 Index;
+} USB_DK_CONFIG_DESCRIPTOR_REQUEST, *PUSB_DK_CONFIG_DESCRIPTOR_REQUEST;
+
+typedef struct tag_USB_DK_ISO_TARNSFER_RESULT
+{
+ ULONG64 actualLength;
+ ULONG64 transferResult;
+} USB_DK_ISO_TRANSFER_RESULT, *PUSB_DK_ISO_TRANSFER_RESULT;
+
+typedef struct tag_USB_DK_TRANSFER_RESULT
+{
+ ULONG64 bytesTransferred;
+ PVOID64 isochronousResultsArray; // array of USB_DK_ISO_TRANSFER_RESULT
+} USB_DK_TRANSFER_RESULT, *PUSB_DK_TRANSFER_RESULT;
+
+typedef struct tag_USB_DK_TRANSFER_REQUEST
+{
+ ULONG64 endpointAddress;
+ PVOID64 buffer;
+ ULONG64 bufferLength;
+ ULONG64 transferType;
+ ULONG64 IsochronousPacketsArraySize;
+ PVOID64 IsochronousPacketsArray;
+
+ USB_DK_TRANSFER_RESULT Result;
+} USB_DK_TRANSFER_REQUEST, *PUSB_DK_TRANSFER_REQUEST;
+
+typedef enum
+{
+ TransferFailure = 0,
+ TransferSuccess,
+ TransferSuccessAsync
+} TransferResult;
+
+typedef enum
+{
+ NoSpeed = 0,
+ LowSpeed,
+ FullSpeed,
+ HighSpeed,
+ SuperSpeed
+} USB_DK_DEVICE_SPEED;
+
+typedef enum
+{
+ ControlTransferType,
+ BulkTransferType,
+ IntertuptTransferType,
+ IsochronousTransferType
+} USB_DK_TRANSFER_TYPE;
diff --git a/libusb/os/UsbDk/UsbDkHelper.h b/libusb/os/UsbDk/UsbDkHelper.h
new file mode 100644
index 0000000..f1f94cf
--- /dev/null
+++ b/libusb/os/UsbDk/UsbDkHelper.h
@@ -0,0 +1,239 @@
+/**********************************************************************
+* Copyright (c) 2013-2014 Red Hat, Inc.
+*
+* Developed by Daynix Computing LTD.
+*
+* Authors:
+* Dmitry Fleytman <***@daynix.com>
+* Pavel Gurvich <***@daynix.com>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+**********************************************************************/
+
+#pragma once
+
+// UsbDkHelper C-interface
+
+#ifdef BUILD_DLL
+#define DLL __declspec(dllexport)
+#else
+#ifdef _MSC_VER
+#define DLL __declspec(dllimport)
+#else
+#define DLL
+#endif
+#endif
+
+#include "UsbDkData.h"
+
+typedef enum
+{
+ InstallFailure,
+ InstallSuccessNeedReboot,
+ InstallSuccess
+} InstallResult;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /* Install UsbDk Driver on the system
+ * Requires usbdk.inf , usbdk.sys, usbdkHelper.dll and wdfcoinstaller01009.dll files to exist in current directory
+ *
+ *
+ * @params
+ * None
+ *
+ * @return
+ * installation status
+ *
+ */
+ DLL InstallResult UsbDk_InstallDriver(void);
+
+ /* Uninstall UsbDk Driver from the system
+ *
+ *
+ * @params
+ * None
+ *
+ * @return
+ * TRUE if uninstall succeeds
+ *
+ */
+ DLL BOOL UsbDk_UninstallDriver(void);
+
+ /* Returning all USB devices enumerated in the system
+ *
+ * @params
+ * IN - None
+ * OUT - DevicesArray pointer to array where devices will be stored
+ NumberDevices amount of returned devices
+ *
+ * @return
+ * TRUE if function succeeds
+ * @note
+ * It is caller's responsibility to release device list by
+ * using UsbDk_ReleaseDevicesList
+ *
+ */
+ DLL BOOL UsbDk_GetDevicesList(PUSB_DK_DEVICE_INFO *DevicesArray, PULONG NumberDevices);
+
+ /* Release deviceArray list returned by UsbDk_GetDevicesList
+ *
+ * @params
+ * IN - DevicesArray pointer to device list to be released
+ * OUT - None
+ *
+ * @return
+ * None
+ *
+ */
+ DLL void UsbDk_ReleaseDevicesList(PUSB_DK_DEVICE_INFO DevicesArray);
+
+ /* Retrieve USB device configuration descriptor
+ *
+ * @params
+ * IN - Request pointer to descriptor request
+ * OUT - Descriptor pointer where configuration descriptor header will be stored
+ * - Length length of full descriptor
+ *
+ *
+ * @return
+ * TRUE if function succeeds
+ *
+ */
+ DLL BOOL UsbDk_GetConfigurationDescriptor(PUSB_DK_CONFIG_DESCRIPTOR_REQUEST Request,
+ PUSB_CONFIGURATION_DESCRIPTOR *Descriptor,
+ PULONG Length);
+
+ /* Release configuration descriptor returned by UsbDk_GetConfigurationDescriptor
+ *
+ * @params
+ * IN - Descriptor - pointer to descriptor to be released
+ * OUT - None
+ *
+ * @return
+ * None
+ *
+ */
+ DLL void UsbDk_ReleaseConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR Descriptor);
+
+ /* Detach USB device from Windows and acquire it for exclusive access
+ *
+ * @params
+ * IN - DeviceID id of device to be acquired
+ * OUT - None
+ *
+ * @return
+ * Handle to acquired device
+ *
+ * @note
+ * Device returned to system automatically when handle is closed
+ *
+ */
+ DLL HANDLE UsbDk_StartRedirect(PUSB_DK_DEVICE_ID DeviceID);
+
+ /* Return USB device to system
+ *
+ * @params
+ * IN - DeviceHandle handle of acquired device
+ * OUT - None
+ *
+ * @return
+ * TRUE if function succeeds
+ *
+ */
+ DLL BOOL UsbDk_StopRedirect(HANDLE DeviceHandle);
+
+ /* Write to USB device pipe
+ *
+ * @params
+ * IN - DeviceHandle - handle of target USB device
+ * - Request - write request
+ * - Overlapped - asynchronous I/O definition
+ * OUT - None
+ *
+ * @return
+ * Status of transfer
+ *
+ */
+ DLL TransferResult UsbDk_WritePipe(HANDLE DeviceHandle, PUSB_DK_TRANSFER_REQUEST Request, LPOVERLAPPED Overlapped);
+
+ /* Read from USB device pipe
+ *
+ * @params
+ * IN - DeviceHandle - handle of target USB device
+ * - Request - read request
+ * - Overlapped - asynchronous I/O definition
+ * OUT - None
+ *
+ * @return
+ * Status of transfer
+ *
+ */
+ DLL TransferResult UsbDk_ReadPipe(HANDLE DeviceHandle, PUSB_DK_TRANSFER_REQUEST Request, LPOVERLAPPED Overlapped);
+
+ /* Issue an USB abort pipe request
+ *
+ * @params
+ * IN - DeviceHandle - handle of target USB device
+ * - PipeAddress - address of pipe to be aborted
+ * OUT - None
+ *
+ * @return
+ * TRUE if function succeeds
+ *
+ */
+ DLL BOOL UsbDk_AbortPipe(HANDLE DeviceHandle, ULONG64 PipeAddress);
+
+ /* Set active alternative settings for USB device
+ *
+ * @params
+ * IN - DeviceHandle - handle of target USB device
+ * - InterfaceIdx - interface index
+ * - AltSettingIdx - alternative settings index
+ * OUT - None
+ *
+ * @return
+ * TRUE if function succeeds
+ *
+ */
+ DLL BOOL UsbDk_SetAltsetting(HANDLE DeviceHandle, ULONG64 InterfaceIdx, ULONG64 AltSettingIdx);
+
+ /* Reset USB device
+ *
+ * @params
+ * IN - DeviceHandle - handle of target USB device
+ * OUT - None
+ *
+ * @return
+ * TRUE if function succeeds
+ *
+ */
+ DLL BOOL UsbDk_ResetDevice(HANDLE DeviceHandle);
+
+ /* Get system handle for asynchronous I/O cancellation requests
+ *
+ * @params
+ * IN - DeviceHandle - handle of target USB device
+ * OUT - None
+ *
+ * @return
+ * handle
+ *
+ */
+ DLL HANDLE UsbDk_GetRedirectorSystemHandle(HANDLE DeviceHandle);
+#ifdef __cplusplus
+}
+#endif
diff --git a/libusb/os/windows_usbdk.c b/libusb/os/windows_usbdk.c
new file mode 100755
index 0000000..f5ff6cc
--- /dev/null
+++ b/libusb/os/windows_usbdk.c
@@ -0,0 +1,890 @@
+/*
+ * windows UsbDk backend for libusb 1.0
+ * Copyright © 2014 Red Hat, Inc.
+
+ * Authors:
+ * Dmitry Fleytman <***@daynix.com>
+ * Pavel Gurvich <***@daynix.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include "ntstatus.h"
+
+#include "libusbi.h"
+#include "windows_usbdk.h"
+#include "cfgmgr32.h"
+#include "windows_common.h"
+#include "windows_nt_common.h"
+
+#define ULONG64 uint64_t
+#define PVOID64 uint64_t
+
+typedef CONST WCHAR *PCWCHAR;
+#define wcsncpy_s wcsncpy
+
+#include "UsbDk/UsbDkHelper.h"
+
+static int concurrent_usage = -1;
+
+struct usbdk_device_priv {
+ USB_DK_DEVICE_INFO info;
+ PUSB_CONFIGURATION_DESCRIPTOR *config_descriptors;
+ HANDLE redirector_handle;
+ uint8_t active_configuration;
+};
+
+struct usbdk_device_handle_priv {
+};
+
+struct usbdk_transfer_priv {
+ USB_DK_TRANSFER_REQUEST request;
+ struct winfd pollable_fd;
+ PULONG64 IsochronousPacketsArray;
+ PUSB_DK_ISO_TRANSFER_RESULT IsochronousResultsArray;
+};
+
+static inline struct usbdk_device_priv *_usbdk_device_priv(struct libusb_device *dev)
+{
+ return (struct usbdk_device_priv*) dev->os_priv;
+}
+
+static inline struct usbdk_transfer_priv *_usbdk_transfer_priv(struct usbi_transfer *itransfer)
+{
+ return (struct usbdk_transfer_priv*) usbi_transfer_get_os_priv(itransfer);
+}
+
+typedef BOOL (__cdecl *USBDK_GET_DEVICES_LIST) (PUSB_DK_DEVICE_INFO *, PULONG);
+typedef void (__cdecl *USBDK_RELEASE_DEVICES_LIST) (PUSB_DK_DEVICE_INFO);
+
+typedef HANDLE (__cdecl *USBDK_START_REDIRECT) (PUSB_DK_DEVICE_ID);
+typedef BOOL (__cdecl *USBDK_STOP_REDIRECT) (HANDLE);
+
+typedef BOOL (__cdecl *USBDK_GET_CONFIGURATION_DESCRIPTOR) (PUSB_DK_CONFIG_DESCRIPTOR_REQUEST Request,
+ PUSB_CONFIGURATION_DESCRIPTOR *Descriptor,
+ PULONG Length);
+typedef void (__cdecl *USBDK_RELEASE_CONFIGURATION_DESCRIPTOR) (PUSB_CONFIGURATION_DESCRIPTOR Descriptor);
+
+typedef TransferResult (__cdecl *USBDK_WRITE_PIPE) (HANDLE DeviceHandle, PUSB_DK_TRANSFER_REQUEST Request, LPOVERLAPPED lpOverlapped);
+typedef TransferResult (__cdecl *USBDK_READ_PIPE) (HANDLE DeviceHandle, PUSB_DK_TRANSFER_REQUEST Request, LPOVERLAPPED lpOverlapped);
+typedef BOOL (__cdecl *USBDK_ABORT_PIPE) (HANDLE DeviceHandle, ULONG64 PipeAddress);
+typedef BOOL (__cdecl *USBDK_SET_ALTSETTING) (HANDLE DeviceHandle, ULONG64 InterfaceIdx, ULONG64 AltSettingIdx);
+typedef BOOL (__cdecl *USBDK_RESET_DEVICE) (HANDLE DeviceHandle);
+
+typedef HANDLE (__cdecl *USBDK_GET_REDIRECTOR_SYSTEM_HANDLE) (HANDLE DeviceHandle);
+
+static struct {
+ HMODULE module;
+
+ USBDK_GET_DEVICES_LIST GetDevicesList;
+ USBDK_RELEASE_DEVICES_LIST ReleaseDevicesList;
+ USBDK_START_REDIRECT StartRedirect;
+ USBDK_STOP_REDIRECT StopRedirect;
+ USBDK_GET_CONFIGURATION_DESCRIPTOR GetConfigurationDescriptor;
+ USBDK_RELEASE_CONFIGURATION_DESCRIPTOR ReleaseConfigurationDescriptor;
+ USBDK_READ_PIPE ReadPipe;
+ USBDK_WRITE_PIPE WritePipe;
+ USBDK_ABORT_PIPE AbortPipe;
+ USBDK_SET_ALTSETTING SetAltsetting;
+ USBDK_RESET_DEVICE ResetDevice;
+ USBDK_GET_REDIRECTOR_SYSTEM_HANDLE GetRedirectorSystemHandle;
+} usbdk_helper;
+
+static PVOID get_usbdk_proc_addr(struct libusb_context *ctx, LPCSTR api_name)
+{
+ PVOID api_ptr = GetProcAddress(usbdk_helper.module, api_name);
+ if (api_ptr == NULL) {
+ DWORD err = GetLastError();
+ usbi_err(ctx, "UsbDkHelper API %s not found, error %d", api_name, err);
+ }
+
+ return api_ptr;
+}
+
+static void unload_usbdk_helper_dll(void)
+{
+ FreeLibrary(usbdk_helper.module);
+}
+
+static int load_usbdk_helper_dll(struct libusb_context *ctx)
+{
+ usbdk_helper.module = LoadLibraryA("UsbDkHelper");
+ if (usbdk_helper.module == NULL) {
+ DWORD err = GetLastError();
+ usbi_err(ctx, "Failed to load UsbDkHelper.dll, error %d", err);
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ usbdk_helper.GetDevicesList = (USBDK_GET_DEVICES_LIST) get_usbdk_proc_addr(ctx, "UsbDk_GetDevicesList");
+ if (usbdk_helper.GetDevicesList == NULL) {
+ goto error_unload;
+ }
+
+ usbdk_helper.ReleaseDevicesList = (USBDK_RELEASE_DEVICES_LIST) get_usbdk_proc_addr(ctx, "UsbDk_ReleaseDevicesList");
+ if (usbdk_helper.ReleaseDevicesList == NULL) {
+ goto error_unload;
+ }
+
+ usbdk_helper.StartRedirect = (USBDK_START_REDIRECT) get_usbdk_proc_addr(ctx, "UsbDk_StartRedirect");
+ if (usbdk_helper.StartRedirect == NULL) {
+ goto error_unload;
+ }
+
+ usbdk_helper.StopRedirect = (USBDK_STOP_REDIRECT) get_usbdk_proc_addr(ctx, "UsbDk_StopRedirect");
+ if (usbdk_helper.StopRedirect == NULL) {
+ goto error_unload;
+ }
+
+ usbdk_helper.GetConfigurationDescriptor = (USBDK_GET_CONFIGURATION_DESCRIPTOR) get_usbdk_proc_addr(ctx, "UsbDk_GetConfigurationDescriptor");
+ if (usbdk_helper.GetConfigurationDescriptor == NULL) {
+ goto error_unload;
+ }
+
+ usbdk_helper.ReleaseConfigurationDescriptor = (USBDK_RELEASE_CONFIGURATION_DESCRIPTOR) get_usbdk_proc_addr(ctx, "UsbDk_ReleaseConfigurationDescriptor");
+ if (usbdk_helper.ReleaseConfigurationDescriptor == NULL) {
+ goto error_unload;
+ }
+
+ usbdk_helper.ReadPipe = (USBDK_READ_PIPE) get_usbdk_proc_addr(ctx, "UsbDk_ReadPipe");
+ if (usbdk_helper.ReadPipe == NULL) {
+ goto error_unload;
+ }
+
+ usbdk_helper.WritePipe = (USBDK_WRITE_PIPE) get_usbdk_proc_addr(ctx, "UsbDk_WritePipe");
+ if (usbdk_helper.WritePipe == NULL) {
+ goto error_unload;
+ }
+
+ usbdk_helper.AbortPipe = (USBDK_ABORT_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_AbortPipe");
+ if (usbdk_helper.AbortPipe == NULL) {
+ goto error_unload;
+ }
+
+ usbdk_helper.SetAltsetting = (USBDK_SET_ALTSETTING)get_usbdk_proc_addr(ctx, "UsbDk_SetAltsetting");
+ if (usbdk_helper.SetAltsetting == NULL) {
+ goto error_unload;
+ }
+
+ usbdk_helper.ResetDevice = (USBDK_RESET_DEVICE)get_usbdk_proc_addr(ctx, "UsbDk_ResetDevice");
+ if (usbdk_helper.ResetDevice == NULL) {
+ goto error_unload;
+ }
+
+ usbdk_helper.GetRedirectorSystemHandle = (USBDK_GET_REDIRECTOR_SYSTEM_HANDLE)get_usbdk_proc_addr(ctx, "UsbDk_GetRedirectorSystemHandle");
+ if (usbdk_helper.GetRedirectorSystemHandle == NULL) {
+ goto error_unload;
+ }
+
+ return LIBUSB_SUCCESS;
+
+error_unload:
+ FreeLibrary(usbdk_helper.module);
+ return LIBUSB_ERROR_NOT_FOUND;
+}
+
+static int usbdk_init(struct libusb_context *ctx)
+{
+ int r;
+
+ if (++concurrent_usage == 0) {
+ r = load_usbdk_helper_dll(ctx);
+ if (r) {
+ return r;
+ }
+
+ init_polling();
+
+ r = LIBUSB_ERROR_NO_MEM;
+ if (!win_nt_init_clock(ctx)){
+ goto error_roll_back;
+ }
+
+ if (!htab_create(ctx, HTAB_SIZE)) {
+ r = LIBUSB_ERROR_NO_MEM;
+ goto error_roll_back;
+ }
+ }
+
+ return LIBUSB_SUCCESS;
+
+error_roll_back:
+ htab_destroy();
+ win_nt_destroy_clock();
+ unload_usbdk_helper_dll();
+ return r;
+}
+
+static int usbdk_get_session_id_for_device(struct libusb_context *ctx,
+ PUSB_DK_DEVICE_ID id,
+ unsigned long* session_id)
+{
+ char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID)];
+
+ if (sprintf(dev_identity, "%S%S", id->DeviceID, id->InstanceID) == -1) {
+ usbi_warn(ctx, "cannot form device identity", id->DeviceID);
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+ }
+
+ *session_id = htab_hash(dev_identity);
+
+ return LIBUSB_SUCCESS;
+}
+
+static void usbdk_release_config_descriptors(struct usbdk_device_priv* p, uint8_t count)
+{
+ uint8_t i;
+ for (i = 0; i < count; i++) {
+ usbdk_helper.ReleaseConfigurationDescriptor(p->config_descriptors[i]);
+ }
+ free(p->config_descriptors);
+ p->config_descriptors = NULL;
+}
+
+static int usbdk_cache_config_descriptors(struct libusb_context *ctx,
+ struct usbdk_device_priv* p,
+ PUSB_DK_DEVICE_INFO info)
+{
+ uint8_t i;
+ USB_DK_CONFIG_DESCRIPTOR_REQUEST Request;
+ Request.ID = info->ID;
+
+ p->config_descriptors = calloc(info->DeviceDescriptor.bNumConfigurations,
+ sizeof(PUSB_CONFIGURATION_DESCRIPTOR));
+ if (p->config_descriptors == NULL) {
+ usbi_err(ctx, "failed to allocate configuration descriptors holder");
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ for (i = 0; i < info->DeviceDescriptor.bNumConfigurations; i++) {
+ ULONG Length;
+
+ Request.Index = i;
+ if (!usbdk_helper.GetConfigurationDescriptor(&Request,
+ &p->config_descriptors[i],
+ &Length)) {
+ usbi_err(ctx, "failed to retrieve configuration descriptors");
+ usbdk_release_config_descriptors(p, i);
+ return LIBUSB_ERROR_OTHER;
+ }
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+static inline int usbdk_device_priv_init(struct libusb_context *ctx, libusb_device* dev, PUSB_DK_DEVICE_INFO info)
+{
+ struct usbdk_device_priv* p = _usbdk_device_priv(dev);
+ p->info = *info;
+ p->active_configuration = 0;
+ return usbdk_cache_config_descriptors(ctx, p, info);
+}
+
+static void usbdk_device_init(libusb_device* dev, PUSB_DK_DEVICE_INFO info)
+{
+ dev->bus_number = info->FilterID;
+ dev->port_number = info->Port;
+ dev->parent_dev = NULL;
+
+ //Addresses in libusb are 1-based
+ dev->device_address = info->Port + 1;
+
+ dev->num_configurations = info->DeviceDescriptor.bNumConfigurations;
+ dev->device_descriptor = info->DeviceDescriptor;
+
+ switch (info->Speed)
+ {
+ case LowSpeed:
+ dev->speed = LIBUSB_SPEED_LOW;
+ break;
+ case FullSpeed:
+ dev->speed = LIBUSB_SPEED_FULL;
+ break;
+ case HighSpeed:
+ dev->speed = LIBUSB_SPEED_HIGH;
+ break;
+ case SuperSpeed:
+ dev->speed = LIBUSB_SPEED_SUPER;
+ break;
+ case NoSpeed:
+ default:
+ dev->speed = LIBUSB_SPEED_UNKNOWN;
+ break;
+ }
+}
+
+static int usbdk_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
+{
+ int r = LIBUSB_SUCCESS;
+
+ struct discovered_devs *discdevs = NULL;
+ ULONG dev_number;
+ PUSB_DK_DEVICE_INFO devices;
+
+ if(!usbdk_helper.GetDevicesList(&devices, &dev_number)) {
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ for (ULONG i = 0; i < dev_number; ++i) {
+ unsigned long session_id;
+ struct libusb_device *dev = NULL;
+
+ if (usbdk_get_session_id_for_device(ctx, &devices[i].ID, &session_id)) {
+ continue;
+ }
+
+ dev = usbi_get_device_by_session_id(ctx, session_id);
+ if (dev == NULL) {
+ dev = usbi_alloc_device(ctx, session_id);
+ if (dev == NULL) {
+ usbi_err(ctx, "failed to allocate a new device structure");
+ continue;
+ }
+
+ usbdk_device_init(dev, &devices[i]);
+ if (usbdk_device_priv_init(ctx, dev, &devices[i]) != LIBUSB_SUCCESS) {
+ libusb_unref_device(dev);
+ continue;
+ }
+ }
+
+ discdevs = discovered_devs_append(*_discdevs, dev);
+
+ libusb_unref_device(dev);
+
+ if (!discdevs)
+ {
+ usbi_err(ctx, "cannot append new device to list");
+ r = LIBUSB_ERROR_NO_MEM;
+ goto func_exit;
+ }
+ *_discdevs = discdevs;
+ }
+
+func_exit:
+ usbdk_helper.ReleaseDevicesList(devices);
+ return r;
+}
+
+static void usbdk_exit(void)
+{
+ if (--concurrent_usage < 0) {
+ htab_destroy();
+ win_nt_destroy_clock();
+ exit_polling();
+ unload_usbdk_helper_dll();
+ }
+}
+
+static int usbdk_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian)
+{
+ struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
+
+ memcpy(buffer, &priv->info.DeviceDescriptor, DEVICE_DESC_LENGTH);
+ *host_endian = 0;
+
+ return LIBUSB_SUCCESS;
+}
+
+static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
+{
+ struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
+ PUSB_CONFIGURATION_DESCRIPTOR config_header;
+ size_t size;
+
+ if (config_index >= dev->num_configurations)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ config_header = (PUSB_CONFIGURATION_DESCRIPTOR) priv->config_descriptors[config_index];
+
+ size = min(config_header->wTotalLength, len);
+ memcpy(buffer, config_header, size);
+ *host_endian = 0;
+
+ return (int)size;
+}
+
+static inline int usbdk_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian)
+{
+ return usbdk_get_config_descriptor(dev, _usbdk_device_priv(dev)->active_configuration,
+ buffer, len, host_endian);
+}
+
+static int usbdk_open(struct libusb_device_handle *dev_handle)
+{
+ struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
+
+ priv->redirector_handle = usbdk_helper.StartRedirect(&priv->info.ID);
+ if (priv->redirector_handle == INVALID_HANDLE_VALUE)
+ {
+ usbi_err(DEVICE_CTX(dev_handle->dev), "Redirector startup failed");
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+static void usbdk_close(struct libusb_device_handle *dev_handle)
+{
+ struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
+
+ if (!usbdk_helper.StopRedirect(priv->redirector_handle))
+ {
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ usbi_err(ctx, "Redirector shutdown failed");
+ }
+}
+
+static int usbdk_get_configuration(struct libusb_device_handle *dev_handle, int *config)
+{
+ *config = _usbdk_device_priv(dev_handle->dev)->active_configuration;
+ return LIBUSB_SUCCESS;
+}
+
+static int usbdk_set_configuration(struct libusb_device_handle *dev_handle, int config)
+{
+ return LIBUSB_SUCCESS;
+}
+
+static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ return LIBUSB_SUCCESS;
+}
+
+static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
+
+ if (!usbdk_helper.SetAltsetting(priv->redirector_handle, iface, altsetting)) {
+ usbi_err(ctx, "SetAltsetting failed: %s", windows_error_str(0));
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+static int usbdk_release_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ return LIBUSB_SUCCESS;
+}
+
+static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
+{
+ return LIBUSB_SUCCESS;
+}
+
+static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
+
+ if (!usbdk_helper.ResetDevice(priv->redirector_handle)) {
+ usbi_err(ctx, "ResetDevice failed: %s", windows_error_str(0));
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+static int usbdk_kernel_driver_active(struct libusb_device_handle *dev_handle, int iface)
+{
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+static int usbdk_attach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
+{
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+static int usbdk_detach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
+{
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+static void usbdk_destroy_device(struct libusb_device *dev)
+{
+ struct usbdk_device_priv* p = _usbdk_device_priv(dev);
+
+ if (p->config_descriptors != NULL)
+ {
+ usbdk_release_config_descriptors(p, p->info.DeviceDescriptor.bNumConfigurations);
+ }
+}
+
+void win_backend_clear_transfer_priv(struct usbi_transfer *itransfer)
+{
+ struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
+ usbi_free_fd(&transfer_priv->pollable_fd);
+
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS){
+ safe_free(transfer_priv->IsochronousPacketsArray);
+ safe_free(transfer_priv->IsochronousResultsArray);
+ }
+}
+
+static int usbdk_do_control_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
+ struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+
+ HANDLE sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
+
+ struct winfd wfd = usbi_create_fd(sysHandle, RW_READ, NULL, NULL);
+ // Always use the handle returned from usbi_create_fd (wfd.handle)
+ if (wfd.fd < 0) {
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ transfer_priv->request.buffer = (PVOID64)(uintptr_t)transfer->buffer;
+ transfer_priv->request.bufferLength = transfer->length;
+ transfer_priv->request.transferType = ControlTransferType;
+ transfer_priv->pollable_fd = INVALID_WINFD;
+ ULONG Length = (ULONG)transfer->length;
+
+ TransferResult transResult;
+ if (IS_XFERIN(transfer)) {
+ transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
+ }
+ else {
+ transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
+ }
+
+
+ switch (transResult)
+ {
+ case TransferSuccess:
+ wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
+ wfd.overlapped->InternalHigh = (DWORD)Length;
+ break;
+ case TransferSuccessAsync:
+ break;
+ case TransferFailure:
+ {
+ usbi_err(ctx, "ControlTransfer failed: %s", windows_error_str(0));
+ usbi_free_fd(&wfd);
+ return LIBUSB_ERROR_IO;
+ }
+ }
+
+ // Use priv_transfer to store data needed for async polling
+ transfer_priv->pollable_fd = wfd;
+ usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN);
+ return LIBUSB_SUCCESS;
+}
+
+static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
+ struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct winfd wfd;
+ TransferResult transferRes;
+
+ transfer_priv->request.buffer = (PVOID64) (uintptr_t) transfer->buffer;
+ transfer_priv->request.bufferLength = transfer->length;
+ transfer_priv->request.endpointAddress = transfer->endpoint;
+
+ switch (transfer->type)
+ {
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ transfer_priv->request.transferType = BulkTransferType;
+ break;
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ transfer_priv->request.transferType = IntertuptTransferType;
+ break;
+ default:
+ usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer. %s", transfer->type, windows_error_str(0));
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+
+ transfer_priv->pollable_fd = INVALID_WINFD;
+
+ HANDLE sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
+
+ wfd = usbi_create_fd(sysHandle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL);
+ // Always use the handle returned from usbi_create_fd (wfd.handle)
+ if (wfd.fd < 0) {
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ if (IS_XFERIN(transfer)) {
+ transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
+ }
+ else {
+ transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
+ }
+
+ switch (transferRes)
+ {
+ case TransferSuccess:
+ wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
+ break;
+ case TransferSuccessAsync:
+ break;
+ case TransferFailure:
+ {
+ usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
+ usbi_free_fd(&wfd);
+ return LIBUSB_ERROR_IO;
+ }
+ }
+
+ transfer_priv->pollable_fd = wfd;
+ usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
+ return LIBUSB_SUCCESS;
+}
+
+static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
+ struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct winfd wfd;
+ TransferResult transferRes;
+ int i;
+
+ transfer_priv->request.buffer = (PVOID64)(uintptr_t)transfer->buffer;
+ transfer_priv->request.bufferLength = transfer->length;
+ transfer_priv->request.endpointAddress = transfer->endpoint;
+ transfer_priv->request.transferType = IsochronousTransferType;
+ transfer_priv->request.IsochronousPacketsArraySize = transfer->num_iso_packets;
+ transfer_priv->IsochronousPacketsArray = malloc(transfer->num_iso_packets * sizeof(ULONG64));
+ transfer_priv->request.IsochronousPacketsArray = (PVOID64)(uintptr_t)transfer_priv->IsochronousPacketsArray;
+ if (!transfer_priv->IsochronousPacketsArray){
+ usbi_err(ctx, "Allocation of IsochronousPacketsArray is failed, %s", windows_error_str(0));
+ return LIBUSB_ERROR_IO;
+ }
+
+ transfer_priv->IsochronousResultsArray = malloc(transfer->num_iso_packets * sizeof(USB_DK_ISO_TRANSFER_RESULT));
+ transfer_priv->request.Result.isochronousResultsArray = (PVOID64)(uintptr_t)transfer_priv->IsochronousResultsArray;
+ if (!transfer_priv->IsochronousResultsArray){
+ usbi_err(ctx, "Allocation of isochronousResultsArray is failed, %s", windows_error_str(0));
+ free(transfer_priv->IsochronousPacketsArray);
+ return LIBUSB_ERROR_IO;
+ }
+
+ for (i = 0; i < transfer->num_iso_packets; i++){
+ transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length;
+ }
+
+ transfer_priv->pollable_fd = INVALID_WINFD;
+
+ HANDLE sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
+
+ wfd = usbi_create_fd(sysHandle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL);
+ // Always use the handle returned from usbi_create_fd (wfd.handle)
+ if (wfd.fd < 0) {
+ free(transfer_priv->IsochronousPacketsArray);
+ free(transfer_priv->IsochronousResultsArray);
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ if (IS_XFERIN(transfer)) {
+ transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
+ }
+ else {
+ transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
+ }
+
+ switch (transferRes){
+ case TransferSuccess:
+ wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
+ break;
+ case TransferSuccessAsync:
+ break;
+ case TransferFailure:
+ {
+ usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
+ usbi_free_fd(&wfd);
+ free(transfer_priv->IsochronousPacketsArray);
+ free(transfer_priv->IsochronousResultsArray);
+ return LIBUSB_ERROR_IO;
+ }
+ }
+
+ transfer_priv->pollable_fd = wfd;
+ usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
+
+ return LIBUSB_SUCCESS;
+}
+
+static int usbdk_submit_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+
+ switch (transfer->type) {
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ return usbdk_do_control_transfer(itransfer);
+
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ if (IS_XFEROUT(transfer) && transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
+ //TODO: Check whether we can support this in UsbDk
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+ } else {
+ return usbdk_do_bulk_transfer(itransfer);
+ }
+
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ return usbdk_do_iso_transfer(itransfer);
+ default:
+ usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+ return LIBUSB_SUCCESS;
+}
+
+static int usbdk_abort_transfers(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
+
+ if (!usbdk_helper.AbortPipe(priv->redirector_handle, transfer->endpoint)) {
+ usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0));
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+static int usbdk_cancel_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+
+ switch (transfer->type) {
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ // Control transfers cancelled by IoCancelXXX() API
+ // No special treatment needed
+ return LIBUSB_SUCCESS;
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ return usbdk_abort_transfers(itransfer);
+ default:
+ usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+}
+
+int win_backend_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
+{
+ itransfer->transferred += io_size;
+ return LIBUSB_TRANSFER_COMPLETED;
+}
+
+struct winfd *win_backend_get_fd(struct usbi_transfer *transfer)
+{
+ struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer);
+ return &transfer_priv->pollable_fd;
+}
+
+void win_backend_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size)
+{
+ if (HasOverlappedIoCompletedSync(pollable_fd->overlapped) || // Handle async requests that completed synchronously first
+ GetOverlappedResult(pollable_fd->handle, pollable_fd->overlapped, io_size, false)) { // Regular async overlapped
+ struct libusb_transfer *ltransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer);
+ struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer);
+
+ if (ltransfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS){
+ int i;
+ for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) {
+ struct libusb_iso_packet_descriptor *lib_desc = &ltransfer->iso_packet_desc[i];
+
+ switch (transfer_priv->IsochronousResultsArray[i].transferResult){
+ case STATUS_SUCCESS:
+ case STATUS_CANCELLED:
+ case STATUS_REQUEST_CANCELED:
+ lib_desc->status = LIBUSB_TRANSFER_COMPLETED; // == ERROR_SUCCESS
+ break;
+ default:
+ lib_desc->status = LIBUSB_TRANSFER_ERROR; // ERROR_UNKNOWN_EXCEPTION;
+ break;
+ }
+
+ lib_desc->actual_length = transfer_priv->IsochronousResultsArray[i].actualLength;
+ }
+ }
+
+ *io_size = transfer_priv->request.Result.bytesTransferred;
+ *io_result = NO_ERROR;
+ }
+ else {
+ *io_result = GetLastError();
+ }
+}
+
+static int usbdk_clock_gettime(int clk_id, struct timespec *tp)
+{
+ return win_nt_clock_gettime(clk_id, tp);
+}
+
+const struct usbi_os_backend usbdk_backend = {
+ "Windows",
+ USBI_CAP_HAS_HID_ACCESS,
+ usbdk_init,
+ usbdk_exit,
+
+ usbdk_get_device_list,
+ NULL,
+ usbdk_open,
+ usbdk_close,
+
+ usbdk_get_device_descriptor,
+ usbdk_get_active_config_descriptor,
+ usbdk_get_config_descriptor,
+ NULL,
+
+ usbdk_get_configuration,
+ usbdk_set_configuration,
+ usbdk_claim_interface,
+ usbdk_release_interface,
+
+ usbdk_set_interface_altsetting,
+ usbdk_clear_halt,
+ usbdk_reset_device,
+
+ NULL,
+ NULL,
+
+ usbdk_kernel_driver_active,
+ usbdk_detach_kernel_driver,
+ usbdk_attach_kernel_driver,
+
+ usbdk_destroy_device,
+
+ usbdk_submit_transfer,
+ usbdk_cancel_transfer,
+ win_backend_clear_transfer_priv,
+
+ win_nt_handle_events,
+ NULL,
+
+ usbdk_clock_gettime,
+#if defined(USBI_TIMERFD_AVAILABLE)
+ NULL,
+#endif
+ sizeof(struct usbdk_device_priv),
+ sizeof(struct usbdk_device_handle_priv),
+ sizeof(struct usbdk_transfer_priv),
+ 0,
+};
diff --git a/libusb/os/windows_usbdk.h b/libusb/os/windows_usbdk.h
new file mode 100644
index 0000000..8d05d5f
--- /dev/null
+++ b/libusb/os/windows_usbdk.h
@@ -0,0 +1,24 @@
+/*
+* windows UsbDk backend for libusb 1.0
+* Copyright © 2014 Red Hat, Inc.
+
+* Authors:
+* Dmitry Fleytman <***@daynix.com>
+* Pavel Gurvich <***@daynix.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
--
2.1.0
Dmitry Fleytman
2015-03-02 17:59:34 UTC
Permalink
From: Dmitry Fleytman <***@redhat.com>

New file windows_nt_common.c introduced.

Signed-off-by: Dmitry Fleytman <***@redhat.com>
---
libusb/Makefile.am | 6 +-
libusb/os/windows_nt_common.c | 572 ++++++++++++++++++++++++++++++++++++++++++
libusb/os/windows_nt_common.h | 67 +++++
libusb/os/windows_usb.c | 556 ++--------------------------------------
libusb/os/windows_usb.h | 14 +-
5 files changed, 668 insertions(+), 547 deletions(-)
create mode 100644 libusb/os/windows_nt_common.c
create mode 100644 libusb/os/windows_nt_common.h

diff --git a/libusb/Makefile.am b/libusb/Makefile.am
index 2cd7021..fe9f649 100644
--- a/libusb/Makefile.am
+++ b/libusb/Makefile.am
@@ -9,7 +9,8 @@ LINUX_USBFS_SRC = os/linux_usbfs.c
DARWIN_USB_SRC = os/darwin_usb.c
OPENBSD_USB_SRC = os/openbsd_usb.c
NETBSD_USB_SRC = os/netbsd_usb.c
-WINDOWS_USB_SRC = os/poll_windows.c os/windows_usb.c libusb-1.0.rc libusb-1.0.def
+COMMON_WINDOWS_SRC = os/poll_windows.c os/windows_nt_common.c libusb-1.0.rc libusb-1.0.def
+WINDOWS_USB_SRC = os/windows_usb.c $(COMMON_WINDOWS_SRC)
WINCE_USB_SRC = os/wince_usb.c os/wince_usb.h

DIST_SUBDIRS =
@@ -78,7 +79,8 @@ libusb_1_0_la_CFLAGS = $(AM_CFLAGS)
libusb_1_0_la_LDFLAGS = $(LTLDFLAGS)
libusb_1_0_la_SOURCES = libusbi.h core.c descriptor.c io.c strerror.c sync.c \
os/linux_usbfs.h os/darwin_usb.h os/windows_usb.h os/windows_common.h \
- hotplug.h hotplug.c $(THREADS_SRC) $(OS_SRC) \
+ os/windows_nt_common.h hotplug.h hotplug.c \
+ $(THREADS_SRC) $(OS_SRC) \
os/poll_posix.h os/poll_windows.h

if OS_HAIKU
diff --git a/libusb/os/windows_nt_common.c b/libusb/os/windows_nt_common.c
new file mode 100644
index 0000000..ce2ceea
--- /dev/null
+++ b/libusb/os/windows_nt_common.c
@@ -0,0 +1,572 @@
+/*
+ * windows backend for libusb 1.0
+ * Copyright © 2009-2012 Pete Batard <***@akeo.ie>
+ * With contributions from Michael Plante, Orin Eman et al.
+ * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
+ * HID Reports IOCTLs inspired from HIDAPI by Alan Ott, Signal 11 Software
+ * Hash table functions adapted from glibc, by Ulrich Drepper et al.
+ * Major code testing contribution by Xiaofan Chen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <process.h>
+
+
+#include "libusbi.h"
+#include "windows_nt_common.h"
+#include "windows_common.h"
+
+// Global variables
+const uint64_t epoch_time = UINT64_C(116444736000000000); // 1970.01.01 00:00:000 in MS Filetime
+
+// Global variables for clock_gettime mechanism
+uint64_t hires_ticks_to_ps;
+uint64_t hires_frequency;
+volatile LONG request_count[2] = { 0, 1 }; // last one must be > 0
+HANDLE timer_request[2] = { NULL, NULL };
+HANDLE timer_response = NULL;
+HANDLE timer_mutex = NULL;
+struct timespec timer_tp;
+// Timer thread
+// NB: index 0 is for monotonic and 1 is for the thread exit event
+HANDLE timer_thread = NULL;
+
+unsigned __stdcall win_nt_clock_gettime_threaded(void* param);
+
+/*
+* Converts a windows error to human readable string
+* uses retval as errorcode, or, if 0, use GetLastError()
+*/
+#if defined(ENABLE_LOGGING)
+char *windows_error_str(uint32_t retval)
+{
+ static char err_string[ERR_BUFFER_SIZE];
+
+ DWORD size;
+ ssize_t i;
+ uint32_t error_code, format_error;
+
+ error_code = retval ? retval : GetLastError();
+
+ safe_sprintf(err_string, ERR_BUFFER_SIZE, "[%u] ", error_code);
+
+ // Translate codes returned by SetupAPI. The ones we are dealing with are either
+ // in 0x0000xxxx or 0xE000xxxx and can be distinguished from standard error codes.
+ // See http://msdn.microsoft.com/en-us/library/windows/hardware/ff545011.aspx
+ switch (error_code & 0xE0000000) {
+ case 0:
+ error_code = HRESULT_FROM_WIN32(error_code); // Still leaves ERROR_SUCCESS unmodified
+ break;
+ case 0xE0000000:
+ error_code = 0x80000000 | (FACILITY_SETUPAPI << 16) | (error_code & 0x0000FFFF);
+ break;
+ default:
+ break;
+ }
+
+ size = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &err_string[safe_strlen(err_string)],
+ ERR_BUFFER_SIZE - (DWORD)safe_strlen(err_string), NULL);
+ if (size == 0) {
+ format_error = GetLastError();
+ if (format_error)
+ safe_sprintf(err_string, ERR_BUFFER_SIZE,
+ "Windows error code %u (FormatMessage error code %u)", error_code, format_error);
+ else
+ safe_sprintf(err_string, ERR_BUFFER_SIZE, "Unknown error code %u", error_code);
+ }
+ else {
+ // Remove CR/LF terminators
+ for (i = safe_strlen(err_string) - 1; (i >= 0) && ((err_string[i] == 0x0A) || (err_string[i] == 0x0D)); i--) {
+ err_string[i] = 0;
+ }
+ }
+ return err_string;
+}
+#endif
+
+/* Hash table functions - modified From glibc 2.3.2:
+ [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
+ [Knuth] The Art of Computer Programming, part 3 (6.4) */
+typedef struct htab_entry {
+ unsigned long used;
+ char* str;
+} htab_entry;
+htab_entry* htab_table = NULL;
+usbi_mutex_t htab_write_mutex = NULL;
+unsigned long htab_size, htab_filled;
+
+/* For the used double hash method the table size has to be a prime. To
+ correct the user given table size we need a prime test. This trivial
+ algorithm is adequate because the code is called only during init and
+ the number is likely to be small */
+static int isprime(unsigned long number)
+{
+ // no even number will be passed
+ unsigned int divider = 3;
+
+ while((divider * divider < number) && (number % divider != 0))
+ divider += 2;
+
+ return (number % divider != 0);
+}
+
+/* Before using the hash table we must allocate memory for it.
+ We allocate one element more as the found prime number says.
+ This is done for more effective indexing as explained in the
+ comment for the hash function. */
+int htab_create(struct libusb_context *ctx, unsigned long nel)
+{
+ if (htab_table != NULL) {
+ usbi_err(ctx, "hash table already allocated");
+ }
+
+ // Create a mutex
+ usbi_mutex_init(&htab_write_mutex, NULL);
+
+ // Change nel to the first prime number not smaller as nel.
+ nel |= 1;
+ while(!isprime(nel))
+ nel += 2;
+
+ htab_size = nel;
+ usbi_dbg("using %d entries hash table", nel);
+ htab_filled = 0;
+
+ // allocate memory and zero out.
+ htab_table = (htab_entry*) calloc(htab_size + 1, sizeof(htab_entry));
+ if (htab_table == NULL) {
+ usbi_err(ctx, "could not allocate space for hash table");
+ return 0;
+ }
+
+ return 1;
+}
+
+/* After using the hash table it has to be destroyed. */
+void htab_destroy(void)
+{
+ size_t i;
+ if (htab_table == NULL) {
+ return;
+ }
+
+ for (i=0; i<htab_size; i++) {
+ if (htab_table[i].used) {
+ safe_free(htab_table[i].str);
+ }
+ }
+ usbi_mutex_destroy(&htab_write_mutex);
+ safe_free(htab_table);
+}
+
+/* This is the search function. It uses double hashing with open addressing.
+ We use an trick to speed up the lookup. The table is created with one
+ more element available. This enables us to use the index zero special.
+ This index will never be used because we store the first hash index in
+ the field used where zero means not used. Every other value means used.
+ The used field can be used as a first fast comparison for equality of
+ the stored and the parameter value. This helps to prevent unnecessary
+ expensive calls of strcmp. */
+unsigned long htab_hash(char* str)
+{
+ unsigned long hval, hval2;
+ unsigned long idx;
+ unsigned long r = 5381;
+ int c;
+ char* sz = str;
+
+ if (str == NULL)
+ return 0;
+
+ // Compute main hash value (algorithm suggested by Nokia)
+ while ((c = *sz++) != 0)
+ r = ((r << 5) + r) + c;
+ if (r == 0)
+ ++r;
+
+ // compute table hash: simply take the modulus
+ hval = r % htab_size;
+ if (hval == 0)
+ ++hval;
+
+ // Try the first index
+ idx = hval;
+
+ if (htab_table[idx].used) {
+ if ( (htab_table[idx].used == hval)
+ && (safe_strcmp(str, htab_table[idx].str) == 0) ) {
+ // existing hash
+ return idx;
+ }
+ usbi_dbg("hash collision ('%s' vs '%s')", str, htab_table[idx].str);
+
+ // Second hash function, as suggested in [Knuth]
+ hval2 = 1 + hval % (htab_size - 2);
+
+ do {
+ // Because size is prime this guarantees to step through all available indexes
+ if (idx <= hval2) {
+ idx = htab_size + idx - hval2;
+ } else {
+ idx -= hval2;
+ }
+
+ // If we visited all entries leave the loop unsuccessfully
+ if (idx == hval) {
+ break;
+ }
+
+ // If entry is found use it.
+ if ( (htab_table[idx].used == hval)
+ && (safe_strcmp(str, htab_table[idx].str) == 0) ) {
+ return idx;
+ }
+ }
+ while (htab_table[idx].used);
+ }
+
+ // Not found => New entry
+
+ // If the table is full return an error
+ if (htab_filled >= htab_size) {
+ usbi_err(NULL, "hash table is full (%d entries)", htab_size);
+ return 0;
+ }
+
+ // Concurrent threads might be storing the same entry at the same time
+ // (eg. "simultaneous" enums from different threads) => use a mutex
+ usbi_mutex_lock(&htab_write_mutex);
+ // Just free any previously allocated string (which should be the same as
+ // new one). The possibility of concurrent threads storing a collision
+ // string (same hash, different string) at the same time is extremely low
+ safe_free(htab_table[idx].str);
+ htab_table[idx].used = hval;
+ htab_table[idx].str = (char*) malloc(safe_strlen(str)+1);
+ if (htab_table[idx].str == NULL) {
+ usbi_err(NULL, "could not duplicate string for hash table");
+ usbi_mutex_unlock(&htab_write_mutex);
+ return 0;
+ }
+ memcpy(htab_table[idx].str, str, safe_strlen(str)+1);
+ ++htab_filled;
+ usbi_mutex_unlock(&htab_write_mutex);
+
+ return idx;
+}
+
+bool win_nt_init_clock(struct libusb_context *ctx)
+{
+ // Because QueryPerformanceCounter might report different values when
+ // running on different cores, we create a separate thread for the timer
+ // calls, which we glue to the first core always to prevent timing discrepancies.
+ for (int i = 0; i < 2; i++) {
+ timer_request[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (timer_request[i] == NULL) {
+ usbi_err(ctx, "could not create timer request event %d - aborting", i);
+ //goto init_exit;
+ return false;
+ }
+ }
+ timer_response = CreateSemaphore(NULL, 0, MAX_TIMER_SEMAPHORES, NULL);
+ if (timer_response == NULL) {
+ usbi_err(ctx, "could not create timer response semaphore - aborting");
+ //goto init_exit;
+ return false;
+ }
+ timer_mutex = CreateMutex(NULL, FALSE, NULL);
+ if (timer_mutex == NULL) {
+ usbi_err(ctx, "could not create timer mutex - aborting");
+ //goto init_exit;
+ return false;
+ }
+ timer_thread = (HANDLE)_beginthreadex(NULL, 0, win_nt_clock_gettime_threaded, NULL, 0, NULL);
+ if (timer_thread == NULL) {
+ usbi_err(ctx, "Unable to create timer thread - aborting");
+ //goto init_exit;
+ return false;
+ }
+ SetThreadAffinityMask(timer_thread, 0);
+
+ // Wait for timer thread to init before continuing.
+ if (WaitForSingleObject(timer_response, INFINITE) != WAIT_OBJECT_0) {
+ usbi_err(ctx, "Failed to wait for timer thread to become ready - aborting");
+ //goto init_exit;
+ return false;
+ }
+
+ return true;
+}
+
+void win_nt_destroy_clock()
+{
+ if (timer_thread) {
+ SetEvent(timer_request[1]); // actually the signal to quit the thread.
+ if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) {
+ usbi_dbg("could not wait for timer thread to quit");
+ TerminateThread(timer_thread, 1);
+ }
+ CloseHandle(timer_thread);
+ timer_thread = NULL;
+ }
+ for (int i = 0; i < 2; i++) {
+ if (timer_request[i]) {
+ CloseHandle(timer_request[i]);
+ timer_request[i] = NULL;
+ }
+ }
+ if (timer_response) {
+ CloseHandle(timer_response);
+ timer_response = NULL;
+ }
+ if (timer_mutex) {
+ CloseHandle(timer_mutex);
+ timer_mutex = NULL;
+ }
+}
+
+/*
+* Monotonic and real time functions
+*/
+unsigned __stdcall win_nt_clock_gettime_threaded(void* param)
+{
+ LARGE_INTEGER hires_counter, li_frequency;
+ LONG nb_responses;
+ int timer_index;
+
+ // Init - find out if we have access to a monotonic (hires) timer
+ if (!QueryPerformanceFrequency(&li_frequency)) {
+ usbi_dbg("no hires timer available on this platform");
+ hires_frequency = 0;
+ hires_ticks_to_ps = UINT64_C(0);
+ }
+ else {
+ hires_frequency = li_frequency.QuadPart;
+ // The hires frequency can go as high as 4 GHz, so we'll use a conversion
+ // to picoseconds to compute the tv_nsecs part in clock_gettime
+ hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency;
+ usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency);
+ }
+
+ // Signal windows_init() that we're ready to service requests
+ if (ReleaseSemaphore(timer_response, 1, NULL) == 0) {
+ usbi_dbg("unable to release timer semaphore: %s", windows_error_str(0));
+ }
+
+ // Main loop - wait for requests
+ while (1) {
+ timer_index = WaitForMultipleObjects(2, timer_request, FALSE, INFINITE) - WAIT_OBJECT_0;
+ if ((timer_index != 0) && (timer_index != 1)) {
+ usbi_dbg("failure to wait on requests: %s", windows_error_str(0));
+ continue;
+ }
+ if (request_count[timer_index] == 0) {
+ // Request already handled
+ ResetEvent(timer_request[timer_index]);
+ // There's still a possiblity that a thread sends a request between the
+ // time we test request_count[] == 0 and we reset the event, in which case
+ // the request would be ignored. The simple solution to that is to test
+ // request_count again and process requests if non zero.
+ if (request_count[timer_index] == 0)
+ continue;
+ }
+ switch (timer_index) {
+ case 0:
+ WaitForSingleObject(timer_mutex, INFINITE);
+ // Requests to this thread are for hires always
+ if ((QueryPerformanceCounter(&hires_counter) != 0) && (hires_frequency != 0)) {
+ timer_tp.tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
+ timer_tp.tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency) / 1000) * hires_ticks_to_ps);
+ }
+ else {
+ // Fallback to real-time if we can't get monotonic value
+ // Note that real-time clock does not wait on the mutex or this thread.
+ win_nt_clock_gettime(USBI_CLOCK_REALTIME, &timer_tp);
+ }
+ ReleaseMutex(timer_mutex);
+
+ nb_responses = InterlockedExchange((LONG*)&request_count[0], 0);
+ if ((nb_responses)
+ && (ReleaseSemaphore(timer_response, nb_responses, NULL) == 0)) {
+ usbi_dbg("unable to release timer semaphore: %s", windows_error_str(0));
+ }
+ continue;
+ case 1: // time to quit
+ usbi_dbg("timer thread quitting");
+ return 0;
+ }
+ }
+}
+
+int win_nt_clock_gettime(int clk_id, struct timespec *tp)
+{
+ FILETIME filetime;
+ ULARGE_INTEGER rtime;
+ DWORD r;
+ switch (clk_id) {
+ case USBI_CLOCK_MONOTONIC:
+ if (hires_frequency != 0) {
+ while (1) {
+ InterlockedIncrement((LONG*)&request_count[0]);
+ SetEvent(timer_request[0]);
+ r = WaitForSingleObject(timer_response, TIMER_REQUEST_RETRY_MS);
+ switch (r) {
+ case WAIT_OBJECT_0:
+ WaitForSingleObject(timer_mutex, INFINITE);
+ *tp = timer_tp;
+ ReleaseMutex(timer_mutex);
+ return LIBUSB_SUCCESS;
+ case WAIT_TIMEOUT:
+ usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?");
+ break; // Retry until successful
+ default:
+ usbi_dbg("WaitForSingleObject failed: %s", windows_error_str(0));
+ return LIBUSB_ERROR_OTHER;
+ }
+ }
+ }
+ // Fall through and return real-time if monotonic was not detected @ timer init
+ case USBI_CLOCK_REALTIME:
+ // We follow http://msdn.microsoft.com/en-us/library/ms724928%28VS.85%29.aspx
+ // with a predef epoch_time to have an epoch that starts at 1970.01.01 00:00
+ // Note however that our resolution is bounded by the Windows system time
+ // functions and is at best of the order of 1 ms (or, usually, worse)
+ GetSystemTimeAsFileTime(&filetime);
+ rtime.LowPart = filetime.dwLowDateTime;
+ rtime.HighPart = filetime.dwHighDateTime;
+ rtime.QuadPart -= epoch_time;
+ tp->tv_sec = (long)(rtime.QuadPart / 10000000);
+ tp->tv_nsec = (long)((rtime.QuadPart % 10000000) * 100);
+ return LIBUSB_SUCCESS;
+ default:
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+}
+
+void win_nt_handle_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+
+ switch (transfer->type) {
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ win_nt_transfer_callback(itransfer, io_result, io_size);
+ break;
+ case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
+ usbi_warn(ITRANSFER_CTX(itransfer), "bulk stream transfers are not yet supported on this platform");
+ break;
+ default:
+ usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
+ }
+}
+
+void win_nt_transfer_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
+{
+ int status, istatus;
+
+ usbi_dbg("handling I/O completion with errcode %d, size %d", io_result, io_size);
+
+ switch (io_result) {
+ case NO_ERROR:
+ status = win_backend_copy_transfer_data(itransfer, io_size);
+ break;
+ case ERROR_GEN_FAILURE:
+ usbi_dbg("detected endpoint stall");
+ status = LIBUSB_TRANSFER_STALL;
+ break;
+ case ERROR_SEM_TIMEOUT:
+ usbi_dbg("detected semaphore timeout");
+ status = LIBUSB_TRANSFER_TIMED_OUT;
+ break;
+ case ERROR_OPERATION_ABORTED:
+ istatus = win_backend_copy_transfer_data(itransfer, io_size);
+ if (istatus != LIBUSB_TRANSFER_COMPLETED) {
+ usbi_dbg("Failed to copy partial data in aborted operation: %d", istatus);
+ }
+ if (itransfer->flags & USBI_TRANSFER_TIMED_OUT) {
+ usbi_dbg("detected timeout");
+ status = LIBUSB_TRANSFER_TIMED_OUT;
+ }
+ else {
+ usbi_dbg("detected operation aborted");
+ status = LIBUSB_TRANSFER_CANCELLED;
+ }
+ break;
+ default:
+ usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error %d: %s", io_result, windows_error_str(io_result));
+ status = LIBUSB_TRANSFER_ERROR;
+ break;
+ }
+ win_backend_clear_transfer_priv(itransfer); // Cancel polling
+ usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status);
+}
+
+int win_nt_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready)
+{
+ POLL_NFDS_TYPE i = 0;
+ bool found = false;
+ struct usbi_transfer *transfer;
+ struct winfd *pollable_fd = NULL;
+ DWORD io_size, io_result;
+
+ usbi_mutex_lock(&ctx->open_devs_lock);
+ for (i = 0; i < nfds && num_ready > 0; i++) {
+
+ usbi_dbg("checking fd %d with revents = %04x", fds[i].fd, fds[i].revents);
+
+ if (!fds[i].revents) {
+ continue;
+ }
+
+ num_ready--;
+
+ // Because a Windows OVERLAPPED is used for poll emulation,
+ // a pollable fd is created and stored with each transfer
+ usbi_mutex_lock(&ctx->flying_transfers_lock);
+ found = false;
+ list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
+ pollable_fd = win_backend_get_fd(transfer);
+ if (pollable_fd->fd == fds[i].fd) {
+ found = true;
+ break;
+ }
+ }
+ usbi_mutex_unlock(&ctx->flying_transfers_lock);
+
+ if (found) {
+ win_backend_get_overlapped_result(transfer, pollable_fd, &io_result, &io_size);
+
+ usbi_remove_pollfd(ctx, pollable_fd->fd);
+ // let handle_callback free the event using the transfer wfd
+ // If you don't use the transfer wfd, you run a risk of trying to free a
+ // newly allocated wfd that took the place of the one from the transfer.
+ win_nt_handle_callback(transfer, io_result, io_size);
+ }
+ else {
+ usbi_mutex_unlock(&ctx->open_devs_lock);
+ usbi_err(ctx, "could not find a matching transfer for fd %x", fds[i]);
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+ }
+
+ usbi_mutex_unlock(&ctx->open_devs_lock);
+ return LIBUSB_SUCCESS;
+}
diff --git a/libusb/os/windows_nt_common.h b/libusb/os/windows_nt_common.h
new file mode 100644
index 0000000..e7b97e9
--- /dev/null
+++ b/libusb/os/windows_nt_common.h
@@ -0,0 +1,67 @@
+/*
+ * Windows backend common header for libusb 1.0
+ *
+ * This file brings together header code common between
+ * the desktop Windows backends.
+ * Copyright © 2012-2013 RealVNC Ltd.
+ * Copyright © 2009-2012 Pete Batard <***@akeo.ie>
+ * With contributions from Michael Plante, Orin Eman et al.
+ * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
+ * Major code testing contribution by Xiaofan Chen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+typedef struct USB_CONFIGURATION_DESCRIPTOR {
+ UCHAR bLength;
+ UCHAR bDescriptorType;
+ USHORT wTotalLength;
+ UCHAR bNumInterfaces;
+ UCHAR bConfigurationValue;
+ UCHAR iConfiguration;
+ UCHAR bmAttributes;
+ UCHAR MaxPower;
+} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;
+
+typedef struct libusb_device_descriptor USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
+
+#define HTAB_SIZE 1021
+
+int htab_create(struct libusb_context *ctx, unsigned long nel);
+void htab_destroy(void);
+unsigned long htab_hash(char* str);
+
+extern const uint64_t epoch_time;
+
+bool win_nt_init_clock(struct libusb_context *ctx);
+void win_nt_destroy_clock(void);
+int win_nt_clock_gettime(int clk_id, struct timespec *tp);
+
+void win_backend_clear_transfer_priv(struct usbi_transfer *itransfer);
+int win_backend_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size);
+struct winfd *win_backend_get_fd(struct usbi_transfer *transfer);
+void win_backend_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size);
+
+void win_nt_handle_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size);
+void win_nt_transfer_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size);
+int win_nt_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready);
+
+#if defined(ENABLE_LOGGING)
+char *windows_error_str(uint32_t retval);
+#endif
diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c
index f100759..7eb9e46 100644
--- a/libusb/os/windows_usb.c
+++ b/libusb/os/windows_usb.c
@@ -37,6 +37,7 @@

#include "libusbi.h"
#include "poll_windows.h"
+#include "windows_nt_common.h"
#include "windows_usb.h"

// The 2 macros below are used in conjunction with safe loops.
@@ -46,7 +47,6 @@
// Helper prototypes
static int windows_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian);
static int windows_clock_gettime(int clk_id, struct timespec *tp);
-unsigned __stdcall windows_clock_gettime_threaded(void* param);
// Common calls
static int common_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface);

@@ -100,20 +100,11 @@ static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itran

// Global variables
uint64_t hires_frequency, hires_ticks_to_ps;
-const uint64_t epoch_time = UINT64_C(116444736000000000); // 1970.01.01 00:00:000 in MS Filetime
int windows_version = WINDOWS_UNDEFINED;
static char windows_version_str[128] = "Windows Undefined";
// Concurrency
static int concurrent_usage = -1;
usbi_mutex_t autoclaim_lock;
-// Timer thread
-// NB: index 0 is for monotonic and 1 is for the thread exit event
-HANDLE timer_thread = NULL;
-HANDLE timer_mutex = NULL;
-struct timespec timer_tp;
-volatile LONG request_count[2] = {0, 1}; // last one must be > 0
-HANDLE timer_request[2] = { NULL, NULL };
-HANDLE timer_response = NULL;
// API globals
#define CHECK_WINUSBX_AVAILABLE(sub_api) do { if (sub_api == SUB_API_NOTSET) sub_api = priv->sub_api; \
if (!WinUSBX[sub_api].initialized) return LIBUSB_ERROR_ACCESS; } while(0)
@@ -144,57 +135,6 @@ static char* guid_to_string(const GUID* guid)
#endif

/*
- * Converts a windows error to human readable string
- * uses retval as errorcode, or, if 0, use GetLastError()
- */
-#if defined(ENABLE_LOGGING)
-static char *windows_error_str(uint32_t retval)
-{
-static char err_string[ERR_BUFFER_SIZE];
-
- DWORD size;
- ssize_t i;
- uint32_t error_code, format_error;
-
- error_code = retval?retval:GetLastError();
-
- safe_sprintf(err_string, ERR_BUFFER_SIZE, "[%u] ", error_code);
-
- // Translate codes returned by SetupAPI. The ones we are dealing with are either
- // in 0x0000xxxx or 0xE000xxxx and can be distinguished from standard error codes.
- // See http://msdn.microsoft.com/en-us/library/windows/hardware/ff545011.aspx
- switch (error_code & 0xE0000000) {
- case 0:
- error_code = HRESULT_FROM_WIN32(error_code); // Still leaves ERROR_SUCCESS unmodified
- break;
- case 0xE0000000:
- error_code = 0x80000000 | (FACILITY_SETUPAPI << 16) | (error_code & 0x0000FFFF);
- break;
- default:
- break;
- }
-
- size = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &err_string[safe_strlen(err_string)],
- ERR_BUFFER_SIZE - (DWORD)safe_strlen(err_string), NULL);
- if (size == 0) {
- format_error = GetLastError();
- if (format_error)
- safe_sprintf(err_string, ERR_BUFFER_SIZE,
- "Windows error code %u (FormatMessage error code %u)", error_code, format_error);
- else
- safe_sprintf(err_string, ERR_BUFFER_SIZE, "Unknown error code %u", error_code);
- } else {
- // Remove CR/LF terminators
- for (i=safe_strlen(err_string)-1; (i>=0) && ((err_string[i]==0x0A) || (err_string[i]==0x0D)); i--) {
- err_string[i] = 0;
- }
- }
- return err_string;
-}
-#endif
-
-/*
* Sanitize Microsoft's paths: convert to uppercase, add prefix and fix backslashes.
* Return an allocated sanitized string or NULL on error.
*/
@@ -460,176 +400,6 @@ err_exit:
*dev_info = INVALID_HANDLE_VALUE;
return NULL;}

-/* Hash table functions - modified From glibc 2.3.2:
- [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
- [Knuth] The Art of Computer Programming, part 3 (6.4) */
-typedef struct htab_entry {
- unsigned long used;
- char* str;
-} htab_entry;
-htab_entry* htab_table = NULL;
-usbi_mutex_t htab_write_mutex = NULL;
-unsigned long htab_size, htab_filled;
-
-/* For the used double hash method the table size has to be a prime. To
- correct the user given table size we need a prime test. This trivial
- algorithm is adequate because the code is called only during init and
- the number is likely to be small */
-static int isprime(unsigned long number)
-{
- // no even number will be passed
- unsigned int divider = 3;
-
- while((divider * divider < number) && (number % divider != 0))
- divider += 2;
-
- return (number % divider != 0);
-}
-
-/* Before using the hash table we must allocate memory for it.
- We allocate one element more as the found prime number says.
- This is done for more effective indexing as explained in the
- comment for the hash function. */
-static int htab_create(struct libusb_context *ctx, unsigned long nel)
-{
- if (htab_table != NULL) {
- usbi_err(ctx, "hash table already allocated");
- }
-
- // Create a mutex
- usbi_mutex_init(&htab_write_mutex, NULL);
-
- // Change nel to the first prime number not smaller as nel.
- nel |= 1;
- while(!isprime(nel))
- nel += 2;
-
- htab_size = nel;
- usbi_dbg("using %d entries hash table", nel);
- htab_filled = 0;
-
- // allocate memory and zero out.
- htab_table = (htab_entry*) calloc(htab_size + 1, sizeof(htab_entry));
- if (htab_table == NULL) {
- usbi_err(ctx, "could not allocate space for hash table");
- return 0;
- }
-
- return 1;
-}
-
-/* After using the hash table it has to be destroyed. */
-static void htab_destroy(void)
-{
- size_t i;
- if (htab_table == NULL) {
- return;
- }
-
- for (i=0; i<htab_size; i++) {
- if (htab_table[i].used) {
- safe_free(htab_table[i].str);
- }
- }
- usbi_mutex_destroy(&htab_write_mutex);
- safe_free(htab_table);
-}
-
-/* This is the search function. It uses double hashing with open addressing.
- We use an trick to speed up the lookup. The table is created with one
- more element available. This enables us to use the index zero special.
- This index will never be used because we store the first hash index in
- the field used where zero means not used. Every other value means used.
- The used field can be used as a first fast comparison for equality of
- the stored and the parameter value. This helps to prevent unnecessary
- expensive calls of strcmp. */
-static unsigned long htab_hash(char* str)
-{
- unsigned long hval, hval2;
- unsigned long idx;
- unsigned long r = 5381;
- int c;
- char* sz = str;
-
- if (str == NULL)
- return 0;
-
- // Compute main hash value (algorithm suggested by Nokia)
- while ((c = *sz++) != 0)
- r = ((r << 5) + r) + c;
- if (r == 0)
- ++r;
-
- // compute table hash: simply take the modulus
- hval = r % htab_size;
- if (hval == 0)
- ++hval;
-
- // Try the first index
- idx = hval;
-
- if (htab_table[idx].used) {
- if ( (htab_table[idx].used == hval)
- && (safe_strcmp(str, htab_table[idx].str) == 0) ) {
- // existing hash
- return idx;
- }
- usbi_dbg("hash collision ('%s' vs '%s')", str, htab_table[idx].str);
-
- // Second hash function, as suggested in [Knuth]
- hval2 = 1 + hval % (htab_size - 2);
-
- do {
- // Because size is prime this guarantees to step through all available indexes
- if (idx <= hval2) {
- idx = htab_size + idx - hval2;
- } else {
- idx -= hval2;
- }
-
- // If we visited all entries leave the loop unsuccessfully
- if (idx == hval) {
- break;
- }
-
- // If entry is found use it.
- if ( (htab_table[idx].used == hval)
- && (safe_strcmp(str, htab_table[idx].str) == 0) ) {
- return idx;
- }
- }
- while (htab_table[idx].used);
- }
-
- // Not found => New entry
-
- // If the table is full return an error
- if (htab_filled >= htab_size) {
- usbi_err(NULL, "hash table is full (%d entries)", htab_size);
- return 0;
- }
-
- // Concurrent threads might be storing the same entry at the same time
- // (eg. "simultaneous" enums from different threads) => use a mutex
- usbi_mutex_lock(&htab_write_mutex);
- // Just free any previously allocated string (which should be the same as
- // new one). The possibility of concurrent threads storing a collision
- // string (same hash, different string) at the same time is extremely low
- safe_free(htab_table[idx].str);
- htab_table[idx].used = hval;
- htab_table[idx].str = (char*) malloc(safe_strlen(str)+1);
- if (htab_table[idx].str == NULL) {
- usbi_err(NULL, "could not duplicate string for hash table");
- usbi_mutex_unlock(&htab_write_mutex);
- return 0;
- }
- memcpy(htab_table[idx].str, str, safe_strlen(str)+1);
- ++htab_filled;
- usbi_mutex_unlock(&htab_write_mutex);
-
- return idx;
-}
-
/*
* Returns the session ID of a device's nth level ancestor
* If there's no device at the nth level, return 0
@@ -1000,37 +770,8 @@ static int windows_init(struct libusb_context *ctx)
usb_api_backend[i].init(SUB_API_NOTSET, ctx);
}

- // Because QueryPerformanceCounter might report different values when
- // running on different cores, we create a separate thread for the timer
- // calls, which we glue to the first core always to prevent timing discrepancies.
r = LIBUSB_ERROR_NO_MEM;
- for (i = 0; i < 2; i++) {
- timer_request[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (timer_request[i] == NULL) {
- usbi_err(ctx, "could not create timer request event %d - aborting", i);
- goto init_exit;
- }
- }
- timer_response = CreateSemaphore(NULL, 0, MAX_TIMER_SEMAPHORES, NULL);
- if (timer_response == NULL) {
- usbi_err(ctx, "could not create timer response semaphore - aborting");
- goto init_exit;
- }
- timer_mutex = CreateMutex(NULL, FALSE, NULL);
- if (timer_mutex == NULL) {
- usbi_err(ctx, "could not create timer mutex - aborting");
- goto init_exit;
- }
- timer_thread = (HANDLE)_beginthreadex(NULL, 0, windows_clock_gettime_threaded, NULL, 0, NULL);
- if (timer_thread == NULL) {
- usbi_err(ctx, "Unable to create timer thread - aborting");
- goto init_exit;
- }
- SetThreadAffinityMask(timer_thread, 0);
-
- // Wait for timer thread to init before continuing.
- if (WaitForSingleObject(timer_response, INFINITE) != WAIT_OBJECT_0) {
- usbi_err(ctx, "Failed to wait for timer thread to become ready - aborting");
+ if (!win_nt_init_clock(ctx)){
goto init_exit;
}

@@ -1042,30 +783,7 @@ static int windows_init(struct libusb_context *ctx)

init_exit: // Holds semaphore here.
if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed?
- if (timer_thread) {
- SetEvent(timer_request[1]); // actually the signal to quit the thread.
- if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) {
- usbi_warn(ctx, "could not wait for timer thread to quit");
- TerminateThread(timer_thread, 1); // shouldn't happen, but we're destroying
- // all objects it might have held anyway.
- }
- CloseHandle(timer_thread);
- timer_thread = NULL;
- }
- for (i = 0; i < 2; i++) {
- if (timer_request[i]) {
- CloseHandle(timer_request[i]);
- timer_request[i] = NULL;
- }
- }
- if (timer_response) {
- CloseHandle(timer_response);
- timer_response = NULL;
- }
- if (timer_mutex) {
- CloseHandle(timer_mutex);
- timer_mutex = NULL;
- }
+ win_nt_destroy_clock();
htab_destroy();
}

@@ -1874,30 +1592,7 @@ static void windows_exit(void)
usb_api_backend[i].exit(SUB_API_NOTSET);
}
exit_polling();
-
- if (timer_thread) {
- SetEvent(timer_request[1]); // actually the signal to quit the thread.
- if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) {
- usbi_dbg("could not wait for timer thread to quit");
- TerminateThread(timer_thread, 1);
- }
- CloseHandle(timer_thread);
- timer_thread = NULL;
- }
- for (i = 0; i < 2; i++) {
- if (timer_request[i]) {
- CloseHandle(timer_request[i]);
- timer_request[i] = NULL;
- }
- }
- if (timer_response) {
- CloseHandle(timer_response);
- timer_response = NULL;
- }
- if (timer_mutex) {
- CloseHandle(timer_mutex);
- timer_mutex = NULL;
- }
+ win_nt_destroy_clock();
htab_destroy();
}

@@ -2085,7 +1780,7 @@ static void windows_destroy_device(struct libusb_device *dev)
windows_device_priv_release(dev);
}

-static void windows_clear_transfer_priv(struct usbi_transfer *itransfer)
+void win_backend_clear_transfer_priv(struct usbi_transfer *itransfer)
{
struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer);

@@ -2210,241 +1905,38 @@ static int windows_cancel_transfer(struct usbi_transfer *itransfer)
}
}

-static void windows_transfer_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
+int win_backend_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
{
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- int status, istatus;
-
- usbi_dbg("handling I/O completion with errcode %d, size %d", io_result, io_size);
-
- switch(io_result) {
- case NO_ERROR:
- status = priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, io_size);
- break;
- case ERROR_GEN_FAILURE:
- usbi_dbg("detected endpoint stall");
- status = LIBUSB_TRANSFER_STALL;
- break;
- case ERROR_SEM_TIMEOUT:
- usbi_dbg("detected semaphore timeout");
- status = LIBUSB_TRANSFER_TIMED_OUT;
- break;
- case ERROR_OPERATION_ABORTED:
- istatus = priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, io_size);
- if (istatus != LIBUSB_TRANSFER_COMPLETED) {
- usbi_dbg("Failed to copy partial data in aborted operation: %d", istatus);
- }
- if (itransfer->flags & USBI_TRANSFER_TIMED_OUT) {
- usbi_dbg("detected timeout");
- status = LIBUSB_TRANSFER_TIMED_OUT;
- } else {
- usbi_dbg("detected operation aborted");
- status = LIBUSB_TRANSFER_CANCELLED;
- }
- break;
- default:
- usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error %d: %s", io_result, windows_error_str(io_result));
- status = LIBUSB_TRANSFER_ERROR;
- break;
- }
- windows_clear_transfer_priv(itransfer); // Cancel polling
- usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status);
-}
-
-static void windows_handle_callback (struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-
- switch (transfer->type) {
- case LIBUSB_TRANSFER_TYPE_CONTROL:
- case LIBUSB_TRANSFER_TYPE_BULK:
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- windows_transfer_callback (itransfer, io_result, io_size);
- break;
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- usbi_warn(ITRANSFER_CTX(itransfer), "bulk stream transfers are not yet supported on this platform");
- break;
- default:
- usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
- }
+ return priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, io_size);
}

-static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready)
+struct winfd *win_backend_get_fd(struct usbi_transfer *transfer)
{
- struct windows_transfer_priv* transfer_priv = NULL;
- POLL_NFDS_TYPE i = 0;
- bool found;
- struct usbi_transfer *transfer;
- DWORD io_size, io_result;
-
- usbi_mutex_lock(&ctx->open_devs_lock);
- for (i = 0; i < nfds && num_ready > 0; i++) {
-
- usbi_dbg("checking fd %d with revents = %04x", fds[i].fd, fds[i].revents);
-
- if (!fds[i].revents) {
- continue;
- }
-
- num_ready--;
-
- // Because a Windows OVERLAPPED is used for poll emulation,
- // a pollable fd is created and stored with each transfer
- usbi_mutex_lock(&ctx->flying_transfers_lock);
- found = false;
- list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
- transfer_priv = usbi_transfer_get_os_priv(transfer);
- if (transfer_priv->pollable_fd.fd == fds[i].fd) {
- found = true;
- break;
- }
- }
- usbi_mutex_unlock(&ctx->flying_transfers_lock);
-
- if (found) {
- // Handle async requests that completed synchronously first
- if (HasOverlappedIoCompletedSync(transfer_priv->pollable_fd.overlapped)) {
- io_result = NO_ERROR;
- io_size = (DWORD)transfer_priv->pollable_fd.overlapped->InternalHigh;
- // Regular async overlapped
- } else if (GetOverlappedResult(transfer_priv->pollable_fd.handle,
- transfer_priv->pollable_fd.overlapped, &io_size, false)) {
- io_result = NO_ERROR;
- } else {
- io_result = GetLastError();
- }
- usbi_remove_pollfd(ctx, transfer_priv->pollable_fd.fd);
- // let handle_callback free the event using the transfer wfd
- // If you don't use the transfer wfd, you run a risk of trying to free a
- // newly allocated wfd that took the place of the one from the transfer.
- windows_handle_callback(transfer, io_result, io_size);
- } else {
- usbi_mutex_unlock(&ctx->open_devs_lock);
- usbi_err(ctx, "could not find a matching transfer for fd %x", fds[i]);
- return LIBUSB_ERROR_NOT_FOUND;
- }
- }
-
- usbi_mutex_unlock(&ctx->open_devs_lock);
- return LIBUSB_SUCCESS;
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(transfer);
+ return &transfer_priv->pollable_fd;
}

-/*
- * Monotonic and real time functions
- */
-unsigned __stdcall windows_clock_gettime_threaded(void* param)
+void win_backend_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size)
{
- LARGE_INTEGER hires_counter, li_frequency;
- LONG nb_responses;
- int timer_index;
-
- // Init - find out if we have access to a monotonic (hires) timer
- if (!QueryPerformanceFrequency(&li_frequency)) {
- usbi_dbg("no hires timer available on this platform");
- hires_frequency = 0;
- hires_ticks_to_ps = UINT64_C(0);
- } else {
- hires_frequency = li_frequency.QuadPart;
- // The hires frequency can go as high as 4 GHz, so we'll use a conversion
- // to picoseconds to compute the tv_nsecs part in clock_gettime
- hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency;
- usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency);
+ // Handle async requests that completed synchronously first
+ if (HasOverlappedIoCompletedSync(pollable_fd->overlapped)) {
+ *io_result = NO_ERROR;
+ *io_size = (DWORD)pollable_fd->overlapped->InternalHigh;
+ // Regular async overlapped
}
-
- // Signal windows_init() that we're ready to service requests
- if (ReleaseSemaphore(timer_response, 1, NULL) == 0) {
- usbi_dbg("unable to release timer semaphore: %s", windows_error_str(0));
+ else if (GetOverlappedResult(pollable_fd->handle, pollable_fd->overlapped, io_size, false)) {
+ *io_result = NO_ERROR;
}
-
- // Main loop - wait for requests
- while (1) {
- timer_index = WaitForMultipleObjects(2, timer_request, FALSE, INFINITE) - WAIT_OBJECT_0;
- if ( (timer_index != 0) && (timer_index != 1) ) {
- usbi_dbg("failure to wait on requests: %s", windows_error_str(0));
- continue;
- }
- if (request_count[timer_index] == 0) {
- // Request already handled
- ResetEvent(timer_request[timer_index]);
- // There's still a possiblity that a thread sends a request between the
- // time we test request_count[] == 0 and we reset the event, in which case
- // the request would be ignored. The simple solution to that is to test
- // request_count again and process requests if non zero.
- if (request_count[timer_index] == 0)
- continue;
- }
- switch (timer_index) {
- case 0:
- WaitForSingleObject(timer_mutex, INFINITE);
- // Requests to this thread are for hires always
- if ((QueryPerformanceCounter(&hires_counter) != 0) && (hires_frequency != 0)) {
- timer_tp.tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
- timer_tp.tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency)/1000) * hires_ticks_to_ps);
- } else {
- // Fallback to real-time if we can't get monotonic value
- // Note that real-time clock does not wait on the mutex or this thread.
- windows_clock_gettime(USBI_CLOCK_REALTIME, &timer_tp);
- }
- ReleaseMutex(timer_mutex);
-
- nb_responses = InterlockedExchange((LONG*)&request_count[0], 0);
- if ( (nb_responses)
- && (ReleaseSemaphore(timer_response, nb_responses, NULL) == 0) ) {
- usbi_dbg("unable to release timer semaphore: %s", windows_error_str(0));
- }
- continue;
- case 1: // time to quit
- usbi_dbg("timer thread quitting");
- return 0;
- }
+ else {
+ *io_result = GetLastError();
}
}

static int windows_clock_gettime(int clk_id, struct timespec *tp)
{
- FILETIME filetime;
- ULARGE_INTEGER rtime;
- DWORD r;
- switch(clk_id) {
- case USBI_CLOCK_MONOTONIC:
- if (hires_frequency != 0) {
- while (1) {
- InterlockedIncrement((LONG*)&request_count[0]);
- SetEvent(timer_request[0]);
- r = WaitForSingleObject(timer_response, TIMER_REQUEST_RETRY_MS);
- switch(r) {
- case WAIT_OBJECT_0:
- WaitForSingleObject(timer_mutex, INFINITE);
- *tp = timer_tp;
- ReleaseMutex(timer_mutex);
- return LIBUSB_SUCCESS;
- case WAIT_TIMEOUT:
- usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?");
- break; // Retry until successful
- default:
- usbi_dbg("WaitForSingleObject failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_OTHER;
- }
- }
- }
- // Fall through and return real-time if monotonic was not detected @ timer init
- case USBI_CLOCK_REALTIME:
- // We follow http://msdn.microsoft.com/en-us/library/ms724928%28VS.85%29.aspx
- // with a predef epoch_time to have an epoch that starts at 1970.01.01 00:00
- // Note however that our resolution is bounded by the Windows system time
- // functions and is at best of the order of 1 ms (or, usually, worse)
- GetSystemTimeAsFileTime(&filetime);
- rtime.LowPart = filetime.dwLowDateTime;
- rtime.HighPart = filetime.dwHighDateTime;
- rtime.QuadPart -= epoch_time;
- tp->tv_sec = (long)(rtime.QuadPart / 10000000);
- tp->tv_nsec = (long)((rtime.QuadPart % 10000000)*100);
- return LIBUSB_SUCCESS;
- default:
- return LIBUSB_ERROR_INVALID_PARAM;
- }
+ return win_nt_clock_gettime(clk_id, tp);
}


@@ -2485,10 +1977,10 @@ const struct usbi_os_backend windows_backend = {

windows_submit_transfer,
windows_cancel_transfer,
- windows_clear_transfer_priv,
+ win_backend_clear_transfer_priv,

- windows_handle_events,
- NULL, /* handle_transfer_completion() */
+ win_nt_handle_events,
+ NULL,

windows_clock_gettime,
#if defined(USBI_TIMERFD_AVAILABLE)
diff --git a/libusb/os/windows_usb.h b/libusb/os/windows_usb.h
index 817a469..3d054f8 100644
--- a/libusb/os/windows_usb.h
+++ b/libusb/os/windows_usb.h
@@ -23,6 +23,7 @@
#pragma once

#include "windows_common.h"
+#include "windows_nt_common.h"

#if defined(_MSC_VER)
// disable /W4 MSVC warnings that are benign
@@ -64,7 +65,6 @@
#define MAX_PATH_LENGTH 128
#define MAX_KEY_LENGTH 256
#define LIST_SEPARATOR ';'
-#define HTAB_SIZE 1021

// Handle code for HID interface that have been claimed ("dibs")
#define INTERFACE_CLAIMED ((HANDLE)(intptr_t)0xD1B5)
@@ -209,7 +209,6 @@ struct hid_device_priv {
uint8_t string_index[3]; // man, prod, ser
};

-typedef struct libusb_device_descriptor USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
struct windows_device_priv {
uint8_t depth; // distance to HCD
uint8_t port; // port number on the hub
@@ -455,17 +454,6 @@ typedef struct USB_INTERFACE_DESCRIPTOR {
UCHAR iInterface;
} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR;

-typedef struct USB_CONFIGURATION_DESCRIPTOR {
- UCHAR bLength;
- UCHAR bDescriptorType;
- USHORT wTotalLength;
- UCHAR bNumInterfaces;
- UCHAR bConfigurationValue;
- UCHAR iConfiguration;
- UCHAR bmAttributes;
- UCHAR MaxPower;
-} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;
-
typedef struct USB_CONFIGURATION_DESCRIPTOR_SHORT {
struct {
ULONG ConnectionIndex;
--
2.1.0
Chris Dickens
2015-03-02 19:42:43 UTC
Permalink
Hi,

I will take a look at this patch series over the next couple days. Please
note that I will not advocate that this patch series be accepted for the
next release. I think we are overdue for a 1.0.20 release and already have
some significant changes that need to be exercised. We can certainly have a
shorter amount of time between 1.0.20 and 1.0.21 releases though.

Regards,
Chris
Post by Dmitry Fleytman
Hello libusb-devel,
This series contains patches that extend Windows backend to support UsbDk.
Switch between UsbDk and WinUSB/LibusbK/Libusb0 is done at compile time
with --enable-usbdk configuration option (off by default).
UsbDk (USB Development Kit) is a set of software components meant to provide
Windows user mode applications with direct and exclusive access to USB devices.
1. UsbDk supports all types of devices and interfaces - bulk, isochronous,
composite, HID etc.
2. Device capture process is totally dynamic, i.e. no inf files and
self-signing needed, any device can be captured.
3. UsbDk co-exists with original device driver, when the device is not
captured original driver is loaded by the system automatically.
4. If user mode client terminates unexpectedly for any reason system reverts
to original device driver immediately.
5. Being USB filter driver UsbDk doesn't require WHQL-ing
as per Microsoft requirements.
UsbDk supports all Windows OS versions staring from Windows XP,
i.e. XP/Vista/7/8/8.1/2003/2008/2008R2/2012/2012R2.
Both 32 and 64 bit architectures are supported.
UsbDk is fully open source and distributed under Apache 2.0 license.
http://cgit.freedesktop.org/spice/win32/usbdk
http://www.spice-space.org/download/windows/usbdk/spice-usbdk-win-1.0-2-sources.zip
http://www.spice-space.org/download/windows/usbdk/UsbDk_1.0.2_x86.msi
http://www.spice-space.org/download/windows/usbdk/UsbDk_1.0.2_x64.msi
http://www.spice-space.org/docs/usbdk/UsbDk_at_a_Glance.pdf
http://www.spice-space.org/docs/usbdk/UsbDk_Software_Development_Manual.pdf
http://cgit.freedesktop.org/spice/win32/usbdk/tree/ARCHITECTURE
to us directly or via this mailing list.
What do you think about this series?
We will be glad to have it accepted into libusb upstream.
Best Regards,
Dmitry
windows: Move common definitions to a separate file
usbdk: Introduce usbdk backend
build: Integrate usbdk backend
configure.ac | 9 +
libusb/Makefile.am | 14 +-
libusb/core.c | 6 +
libusb/libusbi.h | 1 +
libusb/os/UsbDk/UsbDkData.h | 100 +++++
libusb/os/UsbDk/UsbDkHelper.h | 239 ++++++++++++
libusb/os/windows_nt_common.c | 572 +++++++++++++++++++++++++++
libusb/os/windows_nt_common.h | 67 ++++
libusb/os/windows_usb.c | 556 ++------------------------
libusb/os/windows_usb.h | 14 +-
libusb/os/windows_usbdk.c | 890
++++++++++++++++++++++++++++++++++++++++++
libusb/os/windows_usbdk.h | 24 ++
12 files changed, 1944 insertions(+), 548 deletions(-)
create mode 100644 libusb/os/UsbDk/UsbDkData.h
create mode 100644 libusb/os/UsbDk/UsbDkHelper.h
create mode 100644 libusb/os/windows_nt_common.c
create mode 100644 libusb/os/windows_nt_common.h
create mode 100755 libusb/os/windows_usbdk.c
create mode 100644 libusb/os/windows_usbdk.h
--
2.1.0
------------------------------------------------------------------------------
Dive into the World of Parallel Programming The Go Parallel Website,
sponsored
by Intel and developed in partnership with Slashdot Media, is your hub for
all
things parallel software development, from weekly thought leadership blogs
to
news, videos, case studies, tutorials and more. Take a look and join the
conversation now. http://goparallel.sourceforge.net/
_______________________________________________
libusb-devel mailing list
https://lists.sourceforge.net/lists/listinfo/libusb-devel
Dmitry Fleytman
2015-03-03 08:16:59 UTC
Permalink
Hi,
I will take a look at this patch series over the next couple days. Please note that I will not advocate that this patch series be accepted for the next release. I think we are overdue for a 1.0.20 release and already have some
Thanks, Chris.
significant changes that need to be exercised. We can certainly have a shorter amount of time between 1.0.20 and 1.0.21 releases though.
Regards,
Chris
Hello libusb-devel,
This series contains patches that extend Windows backend to support UsbDk.
Switch between UsbDk and WinUSB/LibusbK/Libusb0 is done at compile time
with --enable-usbdk configuration option (off by default).
UsbDk (USB Development Kit) is a set of software components meant to provide
Windows user mode applications with direct and exclusive access to USB devices.
1. UsbDk supports all types of devices and interfaces - bulk, isochronous,
composite, HID etc.
2. Device capture process is totally dynamic, i.e. no inf files and
self-signing needed, any device can be captured.
3. UsbDk co-exists with original device driver, when the device is not
captured original driver is loaded by the system automatically.
4. If user mode client terminates unexpectedly for any reason system reverts
to original device driver immediately.
5. Being USB filter driver UsbDk doesn't require WHQL-ing
as per Microsoft requirements.
UsbDk supports all Windows OS versions staring from Windows XP,
i.e. XP/Vista/7/8/8.1/2003/2008/2008R2/2012/2012R2.
Both 32 and 64 bit architectures are supported.
UsbDk is fully open source and distributed under Apache 2.0 license.
http://cgit.freedesktop.org/spice/win32/usbdk <http://cgit.freedesktop.org/spice/win32/usbdk>
Latest source tarball is at: http://www.spice-space.org/download/windows/usbdk/spice-usbdk-win-1.0-2-sources.zip <http://www.spice-space.org/download/windows/usbdk/spice-usbdk-win-1.0-2-sources.zip>
1. 32 bit: http://www.spice-space.org/download/windows/usbdk/UsbDk_1.0.2_x86.msi <http://www.spice-space.org/download/windows/usbdk/UsbDk_1.0.2_x86.msi>
2. 64 bit: http://www.spice-space.org/download/windows/usbdk/UsbDk_1.0.2_x64.msi <http://www.spice-space.org/download/windows/usbdk/UsbDk_1.0.2_x64.msi>
1. Short presentation: http://www.spice-space.org/docs/usbdk/UsbDk_at_a_Glance.pdf <http://www.spice-space.org/docs/usbdk/UsbDk_at_a_Glance.pdf>
2. SDM: http://www.spice-space.org/docs/usbdk/UsbDk_Software_Development_Manual.pdf <http://www.spice-space.org/docs/usbdk/UsbDk_Software_Development_Manual.pdf>
http://cgit.freedesktop.org/spice/win32/usbdk/tree/ARCHITECTURE <http://cgit.freedesktop.org/spice/win32/usbdk/tree/ARCHITECTURE>
to us directly or via this mailing list.
What do you think about this series?
We will be glad to have it accepted into libusb upstream.
Best Regards,
Dmitry
windows: Move common definitions to a separate file
usbdk: Introduce usbdk backend
build: Integrate usbdk backend
configure.ac <http://configure.ac/> | 9 +
libusb/Makefile.am | 14 +-
libusb/core.c | 6 +
libusb/libusbi.h | 1 +
libusb/os/UsbDk/UsbDkData.h | 100 +++++
libusb/os/UsbDk/UsbDkHelper.h | 239 ++++++++++++
libusb/os/windows_nt_common.c | 572 +++++++++++++++++++++++++++
libusb/os/windows_nt_common.h | 67 ++++
libusb/os/windows_usb.c | 556 ++------------------------
libusb/os/windows_usb.h | 14 +-
libusb/os/windows_usbdk.c | 890 ++++++++++++++++++++++++++++++++++++++++++
libusb/os/windows_usbdk.h | 24 ++
12 files changed, 1944 insertions(+), 548 deletions(-)
create mode 100644 libusb/os/UsbDk/UsbDkData.h
create mode 100644 libusb/os/UsbDk/UsbDkHelper.h
create mode 100644 libusb/os/windows_nt_common.c
create mode 100644 libusb/os/windows_nt_common.h
create mode 100755 libusb/os/windows_usbdk.c
create mode 100644 libusb/os/windows_usbdk.h
--
2.1.0
------------------------------------------------------------------------------
Dive into the World of Parallel Programming The Go Parallel Website, sponsored
by Intel and developed in partnership with Slashdot Media, is your hub for all
things parallel software development, from weekly thought leadership blogs to
news, videos, case studies, tutorials and more. Take a look and join the
conversation now. http://goparallel.sourceforge.net/ <http://goparallel.sourceforge.net/>
_______________________________________________
libusb-devel mailing list
https://lists.sourceforge.net/lists/listinfo/libusb-devel <https://lists.sourceforge.net/lists/listinfo/libusb-devel>
Pete Batard
2015-03-02 23:09:02 UTC
Permalink
Hi Dmirty.

First of all, thanks for submitting these patches. UsbDk looks quite
interesting, and something we should try to have support for in libusb.

*If* that makes sense (which is something I'm not entirely sure for now)
I may very well try to add UsbDk support into libwdi/Zadig [1], as the
goal of libwdi is to facilitate installation for any of the drivers
libusb supports, and there already is some limited support for libusb0
as a filter driver there.

But for the time being, I have to stress out that I only had a very
quick glance at what you submitted, and the following remarks are only
meant to scratch the surface.
Post by Dmitry Fleytman
Switch between UsbDk and WinUSB/LibusbK/Libusb0 is done at compile time
with --enable-usbdk configuration option (off by default).
Does "switch between" mean that you can only have one or the other?

Looking at the configure.ac changes, it looks like it is meant to
coexist with the other Windows sub-APIs, so I'm a bit confused with your
use of "switch" above, in case it means users will have to choose one or
the other.

Also, in case UsbDk can indeed coexist with the other Windows sub APIs,
I personally don't like the idea of disabling it by default, even if
it's new untested code, as this is bound to introduce confusion with
regards to the library capabilities when we deal with our users.

Besides potential bugs that introduction of new code might introduce
(and that we can work through) do you have concerns that, in its current
state, UsbDk support is likely to break support for the other Windows
sub APIs?

Also, you may want to bear in mind that the number of libusb testers on
Windows is more limited than you might think, so if UsbDk is introduced
as an optional feature, you're probably not going to get as much testing
of your code as you'd like. IMO, better make the feature non optional,
and sort anything we need to sort as it pops up.
Post by Dmitry Fleytman
libusb/os/windows_nt_common.c | 572
libusb/os/windows_nt_common.h | 67
(...)
Post by Dmitry Fleytman
+ void win_nt_destroy_clock()
(...)
Post by Dmitry Fleytman
+ int win_nt_handle_events(struct libusb_context *ctx, struct pollfd
*fds, POLL_NFDS_TYPE nfds, int num_ready)

I'm gonna have a very *subjective* objection to suffixing anything with
"NT" in 2015!

The use of NT was already obsolete in 2000, so, _please_, let's not go
for monikers that have long ran their course when introducing new files
and function calls. And yes, I know that NT is still being used by
Windows and Microsoft internally, but that's only because of legacy...
which we're absolutely not being bound to here. Or do we anticipate that
we'll have to support a different Windows architecture than NT in the
future?

The reason I'm not too happy with that suffix is, if I was new to
libusb, and started looking at the Windows source, anything suffixed in
_nt would make me think that I'm dealing with code that probably hasn't
been updated in more than 15 years, regardless of its content... and
thus wouldn't inspire me to want to do anything with it.

Besides, libusb has some history of using the designation "core" for
common stuff, so, to bring a little bit of harmonization between what
Windows and the rest of libusb does, I'd prefer to see the use of
win_core_function_name() as a more modern alternative. Then again, if
anybody has other suggestions, as long as they're not using terminology
that's rooted in the past, I'm open to them. Also, what was wrong with
just "windows_common.c" and "windows_common.h"?


That's all I have to superficially comment on for now. I'll try to have
a closer look if/when I get a chance, but then again, I'm quite happy to
see that Chris already has plans to do so in a much shorter timeframe
(and I agree with him that this is something that we want to introduce
before 1.0.21).

Regards,

/Pete

[1] https://github.com/pbatard/libwdi/wiki
Dmitry Fleytman
2015-03-03 09:03:52 UTC
Permalink
Hi Pete,

Thanks for your reply. Please find my answers below.
Post by Pete Batard
Hi Dmirty.
First of all, thanks for submitting these patches. UsbDk looks quite
interesting, and something we should try to have support for in libusb.
*If* that makes sense (which is something I'm not entirely sure for now)
I may very well try to add UsbDk support into libwdi/Zadig [1], as the
goal of libwdi is to facilitate installation for any of the drivers
libusb supports, and there already is some limited support for libusb0
as a filter driver there.
While UsbDk doesn’t require installation per-device, device is “captured” automatically when client application (libusb or other) opens it via UsbDk_StartRedirect() API, it may have perfect sense to simulate installation by using “Hider API” to detach device from Windows OS. This is good to avoid Windows “New hardware found” pop-ups for devices that do not have “traditional” Windows drivers.

See http://cgit.freedesktop.org/spice/win32/usbdk/tree/UsbDkHelper/UsbDkHelperHider.h <http://cgit.freedesktop.org/spice/win32/usbdk/tree/UsbDkHelper/UsbDkHelperHider.h> for hider API definitions.
Post by Pete Batard
But for the time being, I have to stress out that I only had a very
quick glance at what you submitted, and the following remarks are only
meant to scratch the surface.
Post by Dmitry Fleytman
Switch between UsbDk and WinUSB/LibusbK/Libusb0 is done at compile time
with --enable-usbdk configuration option (off by default).
Does "switch between" mean that you can only have one or the other?
Looking at the configure.ac changes, it looks like it is meant to
coexist with the other Windows sub-APIs, so I'm a bit confused with your
use of "switch" above, in case it means users will have to choose one or
the other.
Also, in case UsbDk can indeed coexist with the other Windows sub APIs,
I personally don't like the idea of disabling it by default, even if
it's new untested code, as this is bound to introduce confusion with
regards to the library capabilities when we deal with our users.
This series introduce compile time selection of Windows backend.
Indeed, it is easy to make this selection run-time, we even have patch for that to simplify our internal testing.

In order to do this we need to define backend selection rules that will be good for everyone.
There are 2 possible approaches:

1. Add explicit API to libusb for selection of the backend
2. Extend current libusb backend selection logic that selects libusbk/winusb sub-api based on libusbk is presence in the system.

Overall I think run time selection mechanism is better than compile time and option 1 is better that option 2.
What do you think?
Post by Pete Batard
Besides potential bugs that introduction of new code might introduce
(and that we can work through) do you have concerns that, in its current
state, UsbDk support is likely to break support for the other Windows
sub APIs?
Since UsbDk support is totally separate part of code there should be no changes in other sub-api’s behaviour.
The only change in other sub-api’s code is moving some functions to separate file, so unless something was broken by patch 1 from the series, there should be no changes in other sub-api’s logic.
Post by Pete Batard
Also, you may want to bear in mind that the number of libusb testers on
Windows is more limited than you might think, so if UsbDk is introduced
as an optional feature, you're probably not going to get as much testing
of your code as you'd like. IMO, better make the feature non optional,
and sort anything we need to sort as it pops up.
Good point!
Post by Pete Batard
Post by Dmitry Fleytman
libusb/os/windows_nt_common.c | 572
libusb/os/windows_nt_common.h | 67
(...)
Post by Dmitry Fleytman
+ void win_nt_destroy_clock()
(...)
Post by Dmitry Fleytman
+ int win_nt_handle_events(struct libusb_context *ctx, struct pollfd
*fds, POLL_NFDS_TYPE nfds, int num_ready)
I'm gonna have a very *subjective* objection to suffixing anything with
"NT" in 2015!
The use of NT was already obsolete in 2000, so, _please_, let's not go
for monikers that have long ran their course when introducing new files
and function calls. And yes, I know that NT is still being used by
Windows and Microsoft internally, but that's only because of legacy...
which we're absolutely not being bound to here. Or do we anticipate that
we'll have to support a different Windows architecture than NT in the
future?
libusb supports Windows CE, this is why we added “nt” to the prefix.
Post by Pete Batard
The reason I'm not too happy with that suffix is, if I was new to
libusb, and started looking at the Windows source, anything suffixed in
_nt would make me think that I'm dealing with code that probably hasn't
been updated in more than 15 years, regardless of its content... and
thus wouldn't inspire me to want to do anything with it.
Besides, libusb has some history of using the designation "core" for
common stuff, so, to bring a little bit of harmonization between what
Windows and the rest of libusb does, I'd prefer to see the use of
win_core_function_name() as a more modern alternative. Then again, if
anybody has other suggestions, as long as they're not using terminology
that's rooted in the past, I'm open to them. Also, what was wrong with
just "windows_common.c" and "windows_common.h”?
The same as with function names, windows CE support is the problem.

I think you’re right regarding this and “nt” should be changed to something newer.

If Windows CE support is not an issues, I’d go for “windows_core" prefix.
I tend to change it in next version of the series if there is no objections.
Post by Pete Batard
That's all I have to superficially comment on for now. I'll try to have
a closer look if/when I get a chance, but then again, I'm quite happy to
Thanks again, Pete,
~Dmitry
Post by Pete Batard
see that Chris already has plans to do so in a much shorter timeframe
(and I agree with him that this is something that we want to introduce
before 1.0.21).
Regards,
/Pete
[1] https://github.com/pbatard/libwdi/wiki
------------------------------------------------------------------------------
Dive into the World of Parallel Programming The Go Parallel Website, sponsored
by Intel and developed in partnership with Slashdot Media, is your hub for all
things parallel software development, from weekly thought leadership blogs to
news, videos, case studies, tutorials and more. Take a look and join the
conversation now. http://goparallel.sourceforge.net/
_______________________________________________
libusb-devel mailing list
https://lists.sourceforge.net/lists/listinfo/libusb-devel
Tim Roberts
2015-03-03 17:51:31 UTC
Permalink
Post by Dmitry Fleytman
Post by Dmitry Fleytman
libusb/os/windows_nt_common.c | 572
libusb/os/windows_nt_common.h | 67
(...)
Post by Dmitry Fleytman
+ void win_nt_destroy_clock()
(...)
Post by Dmitry Fleytman
+ int win_nt_handle_events(struct libusb_context *ctx, struct pollfd
*fds, POLL_NFDS_TYPE nfds, int num_ready)
I'm gonna have a very *subjective* objection to suffixing anything with
"NT" in 2015!
The use of NT was already obsolete in 2000, so, _please_, let's not go
for monikers that have long ran their course when introducing new files
and function calls. And yes, I know that NT is still being used by
Windows and Microsoft internally, but that's only because of legacy...
which we're absolutely not being bound to here. Or do we anticipate that
we'll have to support a different Windows architecture than NT in the
future?
I've had an interesting range of reactions to your objection. Let me
try to present some other ways to think about it.

It's true that Microsoft stopped using Windows NT in its marketing
material as of Windows XP (the Windows 2000 tag line was the redundant
phrase "Built on NT Techology"), but it's also true that the system we
now generically call Windows uses the NT kernel, essentially unchanged
in its fundamental design from its 1989 origins. That term is not
inaccurate. This is not terribly different from Linux, where we have
marketing terms like Ubuntu and Fedora and Mint that are used to
describe operating systems that use the Linux kernel, which is only
slightly younger than the NT kernel.

Microsoft would like us to think that there is only One True Windows,
but that's not quite true yet, as long as CE still lives.

In my personal opinion, there's nothing wrong with having _nt_ in the
file names, but I would just as soon remove "_nt_" from the function names.
--
Tim Roberts, ***@probo.com
Providenza & Boekelheide, Inc.
Xiaofan Chen
2015-03-03 01:26:34 UTC
Permalink
Post by Dmitry Fleytman
Hello libusb-devel,
This series contains patches that extend Windows backend to support UsbDk.
Switch between UsbDk and WinUSB/LibusbK/Libusb0 is done at compile time
with --enable-usbdk configuration option (off by default).
UsbDk (USB Development Kit) is a set of software components meant to provide
Windows user mode applications with direct and exclusive access to USB devices.
1. UsbDk supports all types of devices and interfaces - bulk, isochronous,
composite, HID etc.
2. Device capture process is totally dynamic, i.e. no inf files and
self-signing needed, any device can be captured.
3. UsbDk co-exists with original device driver, when the device is not
captured original driver is loaded by the system automatically.
4. If user mode client terminates unexpectedly for any reason system reverts
to original device driver immediately.
5. Being USB filter driver UsbDk doesn't require WHQL-ing
as per Microsoft requirements.
UsbDk supports all Windows OS versions staring from Windows XP,
i.e. XP/Vista/7/8/8.1/2003/2008/2008R2/2012/2012R2.
Both 32 and 64 bit architectures are supported.
UsbDk is fully open source and distributed under Apache 2.0 license.
Very nice. Just wondering how mature is UsbDK now.

Usually I test libusb Windows backend with a few libusb examples,
libusbdotnet, libftdi and OpenOCD. I will give it a try soon (under
Windows 7 and Windows 8.1, and maybe Windows 10 preview).
--
Xiaofan
Dmitry Fleytman
2015-03-03 09:10:17 UTC
Permalink
Post by Xiaofan Chen
Post by Dmitry Fleytman
Hello libusb-devel,
This series contains patches that extend Windows backend to support UsbDk.
Switch between UsbDk and WinUSB/LibusbK/Libusb0 is done at compile time
with --enable-usbdk configuration option (off by default).
UsbDk (USB Development Kit) is a set of software components meant to provide
Windows user mode applications with direct and exclusive access to USB devices.
1. UsbDk supports all types of devices and interfaces - bulk, isochronous,
composite, HID etc.
2. Device capture process is totally dynamic, i.e. no inf files and
self-signing needed, any device can be captured.
3. UsbDk co-exists with original device driver, when the device is not
captured original driver is loaded by the system automatically.
4. If user mode client terminates unexpectedly for any reason system reverts
to original device driver immediately.
5. Being USB filter driver UsbDk doesn't require WHQL-ing
as per Microsoft requirements.
UsbDk supports all Windows OS versions staring from Windows XP,
i.e. XP/Vista/7/8/8.1/2003/2008/2008R2/2012/2012R2.
Both 32 and 64 bit architectures are supported.
UsbDk is fully open source and distributed under Apache 2.0 license.
Very nice. Just wondering how mature is UsbDK now.
Thanks, Xiaofan.

We use libusb with UsbDk for USB redirection feature in spice client [1].
While there is no public version yet, internal testing at RedHat shows that it is stable and functional for all types of devices.

[1] http://www.spice-space.org/page/Spice-Gtk <http://www.spice-space.org/page/Spice-Gtk>
Post by Xiaofan Chen
Usually I test libusb Windows backend with a few libusb examples,
libusbdotnet, libftdi and OpenOCD. I will give it a try soon (under
Windows 7 and Windows 8.1, and maybe Windows 10 preview).
Great thanks, we’ll be glad to see your testing results,
~Dmitry
Post by Xiaofan Chen
--
Xiaofan
Xiaofan Chen
2015-03-04 00:08:36 UTC
Permalink
Post by Dmitry Fleytman
1. UsbDk supports all types of devices and interfaces - bulk, isochronous,
composite, HID etc.
2. Device capture process is totally dynamic, i.e. no inf files and
self-signing needed, any device can be captured.
3. UsbDk co-exists with original device driver, when the device is not
captured original driver is loaded by the system automatically.
4. If user mode client terminates unexpectedly for any reason system reverts
to original device driver immediately.
5. Being USB filter driver UsbDk doesn't require WHQL-ing
as per Microsoft requirements.
From the above, it seems to me that when the device
is captured, the original device driver is not loaded.
So it is not really "co-exists", right? It seems to me it
is more a type of dynamic switching of driver. Am I right?

http://cgit.freedesktop.org/spice/win32/usbdk/tree/ARCHITECTURE
"UsbDk.sys is both USB filter driver and generic USB device driver.
On installation it is being registered as USB filter driver and
system invokes it for each new USB device being discovered including
USB hubs. On invocation UsbDk.sys checks type of underlying device
and creates filter instances for USB hubs only.

Being a filter of USB hub UsbDk.sys receives all requests from upper
part of USB stack including enumeration requests that originated by
PNP manager (IRP_MJ_PNP/IRP_MN_QUERY_DEVICE_RELATIONS)."

The filter mentioned above means actually UsbDk acts as a upper
filter driver of USB Root Hub, not really a upper filter driver
of the USB device (which libusb-win32 filter driver is).

"Upon enumeration request completion by USB hub driver UsbDk.sys scans
array of child devices returned and in case there are devices to be
redirected (according to current configuration) it attaches as filter
to those devices as well.

As a result all PNP manager requests pass via UsbDk.sys callbacks and the
latter patches device ID properties as needed to make PNP manager recognize
the device as a generic USB device.

Besides that UsbDk.sys marks underlying device object as raw PDO so the system
assigns the driver who created it (UsbDk.sys) to be the device driver as well."

So it seems that UsbDk only acts as a upper filter driver for the device
to be captured briefly and then forces re-enumeration of the device and
then act as a device driver. Am I right?

In that case, it seems UsbDk is really useful under Windows to implement
dynamically attach/detach the UsbDk driver (similar to Linux where
the original driver can be attached/detached, detached means to use
usbfs driver).
Post by Dmitry Fleytman
windows: Move common definitions to a separate file
usbdk: Introduce usbdk backend
build: Integrate usbdk backend
configure.ac | 9 +
libusb/Makefile.am | 14 +-
libusb/core.c | 6 +
libusb/libusbi.h | 1 +
libusb/os/UsbDk/UsbDkData.h | 100 +++++
libusb/os/UsbDk/UsbDkHelper.h | 239 ++++++++++++
libusb/os/windows_nt_common.c | 572 +++++++++++++++++++++++++++
libusb/os/windows_nt_common.h | 67 ++++
libusb/os/windows_usb.c | 556 ++------------------------
libusb/os/windows_usb.h | 14 +-
libusb/os/windows_usbdk.c | 890 ++++++++++++++++++++++++++++++++++++++++++
libusb/os/windows_usbdk.h | 24 ++
12 files changed, 1944 insertions(+), 548 deletions(-)
create mode 100644 libusb/os/UsbDk/UsbDkData.h
create mode 100644 libusb/os/UsbDk/UsbDkHelper.h
create mode 100644 libusb/os/windows_nt_common.c
create mode 100644 libusb/os/windows_nt_common.h
create mode 100755 libusb/os/windows_usbdk.c
create mode 100644 libusb/os/windows_usbdk.h
Just wondering if the files can be compiled by MSVC. It would
be good to provide VS solutions files (say VS2013) and
WDK 7 build files. Take note libusb Windows backend
supports MSVC along with MinGW.org, MinGW-w64
and Cygwin.
--
Xiaofan
Dmitry Fleytman
2015-03-04 08:33:24 UTC
Permalink
Hi Xiaofan,
Post by Dmitry Fleytman
Post by Dmitry Fleytman
1. UsbDk supports all types of devices and interfaces - bulk, isochronous,
composite, HID etc.
2. Device capture process is totally dynamic, i.e. no inf files and
self-signing needed, any device can be captured.
3. UsbDk co-exists with original device driver, when the device is not
captured original driver is loaded by the system automatically.
4. If user mode client terminates unexpectedly for any reason system reverts
to original device driver immediately.
5. Being USB filter driver UsbDk doesn't require WHQL-ing
as per Microsoft requirements.
From the above, it seems to me that when the device
is captured, the original device driver is not loaded.
So it is not really "co-exists", right? It seems to me it
is more a type of dynamic switching of driver. Am I right?
Exactly.
By co-existance with original driver I meant this dynamic switch ability.
Post by Dmitry Fleytman
http://cgit.freedesktop.org/spice/win32/usbdk/tree/ARCHITECTURE
"UsbDk.sys is both USB filter driver and generic USB device driver.
On installation it is being registered as USB filter driver and
system invokes it for each new USB device being discovered including
USB hubs. On invocation UsbDk.sys checks type of underlying device
and creates filter instances for USB hubs only.
Being a filter of USB hub UsbDk.sys receives all requests from upper
part of USB stack including enumeration requests that originated by
PNP manager (IRP_MJ_PNP/IRP_MN_QUERY_DEVICE_RELATIONS)."
The filter mentioned above means actually UsbDk acts as a upper
filter driver of USB Root Hub, not really a upper filter driver
of the USB device (which libusb-win32 filter driver is).
Yes, UsbDk is USB hub filter driver and generic USB device driver, 2 in one.
Post by Dmitry Fleytman
"Upon enumeration request completion by USB hub driver UsbDk.sys scans
array of child devices returned and in case there are devices to be
redirected (according to current configuration) it attaches as filter
to those devices as well.
As a result all PNP manager requests pass via UsbDk.sys callbacks and the
latter patches device ID properties as needed to make PNP manager recognize
the device as a generic USB device.
Besides that UsbDk.sys marks underlying device object as raw PDO so the system
assigns the driver who created it (UsbDk.sys) to be the device driver as well."
So it seems that UsbDk only acts as a upper filter driver for the device
to be captured briefly and then forces re-enumeration of the device and
then act as a device driver. Am I right?
Exactly.
Post by Dmitry Fleytman
In that case, it seems UsbDk is really useful under Windows to implement
dynamically attach/detach the UsbDk driver (similar to Linux where
the original driver can be attached/detached, detached means to use
usbfs driver).
Yes, you are right. The thing UsbDk does is pretty much similar to Linux’s attach/detach.
Post by Dmitry Fleytman
Post by Dmitry Fleytman
windows: Move common definitions to a separate file
usbdk: Introduce usbdk backend
build: Integrate usbdk backend
configure.ac | 9 +
libusb/Makefile.am | 14 +-
libusb/core.c | 6 +
libusb/libusbi.h | 1 +
libusb/os/UsbDk/UsbDkData.h | 100 +++++
libusb/os/UsbDk/UsbDkHelper.h | 239 ++++++++++++
libusb/os/windows_nt_common.c | 572 +++++++++++++++++++++++++++
libusb/os/windows_nt_common.h | 67 ++++
libusb/os/windows_usb.c | 556 ++------------------------
libusb/os/windows_usb.h | 14 +-
libusb/os/windows_usbdk.c | 890 ++++++++++++++++++++++++++++++++++++++++++
libusb/os/windows_usbdk.h | 24 ++
12 files changed, 1944 insertions(+), 548 deletions(-)
create mode 100644 libusb/os/UsbDk/UsbDkData.h
create mode 100644 libusb/os/UsbDk/UsbDkHelper.h
create mode 100644 libusb/os/windows_nt_common.c
create mode 100644 libusb/os/windows_nt_common.h
create mode 100755 libusb/os/windows_usbdk.c
create mode 100644 libusb/os/windows_usbdk.h
Just wondering if the files can be compiled by MSVC. It would
be good to provide VS solutions files (say VS2013) and
WDK 7 build files. Take note libusb Windows backend
supports MSVC along with MinGW.org, MinGW-w64
and Cygwin.
I didn’t know that. Thanks for the information.
I’ll check MSVC build before submitting the next version.


~Dmitry
Post by Dmitry Fleytman
--
Xiaofan
Jason Kotzin
2015-03-05 01:57:34 UTC
Permalink
Dmitry -

I have successfully applied the patches.

One thing to note, is you need to regenerate the configure scripts, so ./autogen.sh or bootstrap.

Configured successfully, but I can’t compile.

I needed to do the following:

diff --git a/libusb/os/windows_usbdk.c b/libusb/os/windows_usbdk.c
index 9d56da1..5e82538 100755
--- a/libusb/os/windows_usbdk.c
+++ b/libusb/os/windows_usbdk.c
@@ -23,11 +23,13 @@

#include <config.h>
#include <stdio.h>
-#include "ntstatus.h"
+//#include "ntstatus.h"
+#include <ddk/ntstatus.h>

#include "libusbi.h"
#include "windows_usbdk.h"
-#include "cfgmgr32.h"
+//#include "cfgmgr32.h"
+#include <ddk/cfgmgr32.h>
#include "windows_common.h"
#include "windows_nt_common.h"

After that, there are undefined enums:

os/windows_usbdk.c: In function 'win_backend_get_overlapped_result':
os/windows_usbdk.c:818:22: error: 'STATUS_REQUEST_CANCELED' undeclared (first use in this function)
os/windows_usbdk.c:818:22: note: each undeclared identifier is reported only once for each function it appears in

Thanks, would love to try this, let me know what I’m missing.

Very Sincerely,
Jason
Post by Dmitry Fleytman
Hi Xiaofan,
Post by Dmitry Fleytman
Post by Dmitry Fleytman
1. UsbDk supports all types of devices and interfaces - bulk, isochronous,
composite, HID etc.
2. Device capture process is totally dynamic, i.e. no inf files and
self-signing needed, any device can be captured.
3. UsbDk co-exists with original device driver, when the device is not
captured original driver is loaded by the system automatically.
4. If user mode client terminates unexpectedly for any reason system reverts
to original device driver immediately.
5. Being USB filter driver UsbDk doesn't require WHQL-ing
as per Microsoft requirements.
From the above, it seems to me that when the device
is captured, the original device driver is not loaded.
So it is not really "co-exists", right? It seems to me it
is more a type of dynamic switching of driver. Am I right?
Exactly.
By co-existance with original driver I meant this dynamic switch ability.
Post by Dmitry Fleytman
http://cgit.freedesktop.org/spice/win32/usbdk/tree/ARCHITECTURE
"UsbDk.sys is both USB filter driver and generic USB device driver.
On installation it is being registered as USB filter driver and
system invokes it for each new USB device being discovered including
USB hubs. On invocation UsbDk.sys checks type of underlying device
and creates filter instances for USB hubs only.
Being a filter of USB hub UsbDk.sys receives all requests from upper
part of USB stack including enumeration requests that originated by
PNP manager (IRP_MJ_PNP/IRP_MN_QUERY_DEVICE_RELATIONS)."
The filter mentioned above means actually UsbDk acts as a upper
filter driver of USB Root Hub, not really a upper filter driver
of the USB device (which libusb-win32 filter driver is).
Yes, UsbDk is USB hub filter driver and generic USB device driver, 2 in one.
Post by Dmitry Fleytman
"Upon enumeration request completion by USB hub driver UsbDk.sys scans
array of child devices returned and in case there are devices to be
redirected (according to current configuration) it attaches as filter
to those devices as well.
As a result all PNP manager requests pass via UsbDk.sys callbacks and the
latter patches device ID properties as needed to make PNP manager recognize
the device as a generic USB device.
Besides that UsbDk.sys marks underlying device object as raw PDO so the system
assigns the driver who created it (UsbDk.sys) to be the device driver as well."
So it seems that UsbDk only acts as a upper filter driver for the device
to be captured briefly and then forces re-enumeration of the device and
then act as a device driver. Am I right?
Exactly.
Post by Dmitry Fleytman
In that case, it seems UsbDk is really useful under Windows to implement
dynamically attach/detach the UsbDk driver (similar to Linux where
the original driver can be attached/detached, detached means to use
usbfs driver).
Yes, you are right. The thing UsbDk does is pretty much similar to Linux’s attach/detach.
Post by Dmitry Fleytman
Post by Dmitry Fleytman
windows: Move common definitions to a separate file
usbdk: Introduce usbdk backend
build: Integrate usbdk backend
configure.ac | 9 +
libusb/Makefile.am | 14 +-
libusb/core.c | 6 +
libusb/libusbi.h | 1 +
libusb/os/UsbDk/UsbDkData.h | 100 +++++
libusb/os/UsbDk/UsbDkHelper.h | 239 ++++++++++++
libusb/os/windows_nt_common.c | 572 +++++++++++++++++++++++++++
libusb/os/windows_nt_common.h | 67 ++++
libusb/os/windows_usb.c | 556 ++------------------------
libusb/os/windows_usb.h | 14 +-
libusb/os/windows_usbdk.c | 890 ++++++++++++++++++++++++++++++++++++++++++
libusb/os/windows_usbdk.h | 24 ++
12 files changed, 1944 insertions(+), 548 deletions(-)
create mode 100644 libusb/os/UsbDk/UsbDkData.h
create mode 100644 libusb/os/UsbDk/UsbDkHelper.h
create mode 100644 libusb/os/windows_nt_common.c
create mode 100644 libusb/os/windows_nt_common.h
create mode 100755 libusb/os/windows_usbdk.c
create mode 100644 libusb/os/windows_usbdk.h
Just wondering if the files can be compiled by MSVC. It would
be good to provide VS solutions files (say VS2013) and
WDK 7 build files. Take note libusb Windows backend
supports MSVC along with MinGW.org, MinGW-w64
and Cygwin.
I didn’t know that. Thanks for the information.
I’ll check MSVC build before submitting the next version.
~Dmitry
Post by Dmitry Fleytman
--
Xiaofan
------------------------------------------------------------------------------
Dive into the World of Parallel Programming The Go Parallel Website, sponsored
by Intel and developed in partnership with Slashdot Media, is your hub for all
things parallel software development, from weekly thought leadership blogs to
news, videos, case studies, tutorials and more. Take a look and join the
conversation now. http://goparallel.sourceforge.net/
_______________________________________________
libusb-devel mailing list
https://lists.sourceforge.net/lists/listinfo/libusb-devel
Xiaofan Chen
2015-03-05 02:56:49 UTC
Permalink
Post by Jason Kotzin
Dmitry -
I have successfully applied the patches.
Hmm, I tried to apply the patch series and I could not even pass this
step. Potentially it is because of the combination of Gmail and Mac
OS X (I use Mac OS X at home and mainly test libusb under
VirtualBox VMs, I only test under a real Windows 7 x64 laptop when
I suspect that VirtualBox is the potential problem).

Just wondering if you can send the patches as attachments to
help me pass this first step.
Post by Jason Kotzin
One thing to note, is you need to regenerate the configure scripts, so
./autogen.sh or bootstrap.
Configured successfully, but I can’t compile.
Which version of MinGW do you use? I suspect that MinGW-w64
is used by the authors and not MinGW.org.
--
Xiaofan
Jason Kotzin
2015-03-05 03:02:40 UTC
Permalink
I’m using the pre-built binaries on my mac from: http://crossgcc.rts-software.org/doku.php <http://crossgcc.rts-software.org/doku.php>

Patch attached. This also has my patch mentioned in my previous email, you may need to remove that.

Yes, I had trouble with the patches, it needed to be applied in a specific order. So I branched the latest libusb tree, successfully applied the patches, and can fork and do a merge request if needed.

Let me know if this helps.

Very Sincerely,
Jason
Post by Xiaofan Chen
Post by Jason Kotzin
Dmitry -
I have successfully applied the patches.
Hmm, I tried to apply the patch series and I could not even pass this
step. Potentially it is because of the combination of Gmail and Mac
OS X (I use Mac OS X at home and mainly test libusb under
VirtualBox VMs, I only test under a real Windows 7 x64 laptop when
I suspect that VirtualBox is the potential problem).
Just wondering if you can send the patches as attachments to
help me pass this first step.
Post by Jason Kotzin
One thing to note, is you need to regenerate the configure scripts, so
./autogen.sh or bootstrap.
Configured successfully, but I can’t compile.
Which version of MinGW do you use? I suspect that MinGW-w64
is used by the authors and not MinGW.org.
--
Xiaofan
Dmitry Fleytman
2015-03-05 08:45:00 UTC
Permalink
Hello Xiaofan, Jason,

For convenience, I’ve created libusb fork on github and put patches there, see branch usbdk-backend-v1 at:
https://github.com/dmitryfleytman/libusb/tree/usbdk-backend-v1 <https://github.com/dmitryfleytman/libusb/tree/usbdk-backend-v1>

Regarding the build, we’re compiling on FC21 system with mingw32/64, i.e.

./autogen.sh
mingw32-configure --enable-usbdk=yes (or mingw64-configure --enable-usbdk=yes)
make

If that is not an “official” way to build, please let me know how you do it and we will make corresponding changes in our patches.

Dmitry.
Post by Jason Kotzin
I’m using the pre-built binaries on my mac from: http://crossgcc.rts-software.org/doku.php <http://crossgcc.rts-software.org/doku.php>
Patch attached. This also has my patch mentioned in my previous email, you may need to remove that.
Yes, I had trouble with the patches, it needed to be applied in a specific order. So I branched the latest libusb tree, successfully applied the patches, and can fork and do a merge request if needed.
Let me know if this helps.
Very Sincerely,
Jason
<UsbDk.patch>
Post by Xiaofan Chen
Post by Jason Kotzin
Dmitry -
I have successfully applied the patches.
Hmm, I tried to apply the patch series and I could not even pass this
step. Potentially it is because of the combination of Gmail and Mac
OS X (I use Mac OS X at home and mainly test libusb under
VirtualBox VMs, I only test under a real Windows 7 x64 laptop when
I suspect that VirtualBox is the potential problem).
Just wondering if you can send the patches as attachments to
help me pass this first step.
Post by Jason Kotzin
One thing to note, is you need to regenerate the configure scripts, so
./autogen.sh or bootstrap.
Configured successfully, but I can’t compile.
Which version of MinGW do you use? I suspect that MinGW-w64
is used by the authors and not MinGW.org <http://mingw.org/>.
--
Xiaofan
Xiaofan Chen
2015-03-05 16:01:14 UTC
Permalink
Post by Dmitry Fleytman
Hello Xiaofan, Jason,
For convenience, I’ve created libusb fork on github and put patches there,
https://github.com/dmitryfleytman/libusb/tree/usbdk-backend-v1
Thanks a lot. This helps.

Firstly I did some simple tests under Mac OS X just to see if there
are some side effects or not and it seems okay.
Post by Dmitry Fleytman
Regarding the build, we’re compiling on FC21 system with mingw32/64, i.e.
./autogen.sh
mingw32-configure --enable-usbdk=yes (or mingw64-configure
--enable-usbdk=yes)
make
If that is not an “official” way to build, please let me know how you do it
and we will make corresponding changes in our patches.
Seems to be okay with my not-so-recent version of MinGW-w64 (4.8.2)
32 bit under Windows 7 x86.
It does not build with an older version of MinGW-w64(4.7.2) but I think
that is not a real problem.

Then I tried it with a usb device. usbdk seems to hide the device
successfully and libusb xusb example seems to work fine. That
is a good sign.

I also tried to use libusbdotnet with the device (Benchmark firmware
for libusbdotnet/libusbK) but libusbdotnet has problem to load the
libusb-1.0.dll I built. I will try later.
--
Xiaofan
Xiaofan Chen
2015-03-06 15:09:33 UTC
Permalink
Post by Xiaofan Chen
Post by Dmitry Fleytman
Regarding the build, we’re compiling on FC21 system with mingw32/64, i.e.
./autogen.sh
mingw32-configure --enable-usbdk=yes (or mingw64-configure
--enable-usbdk=yes)
make
Seems to be okay with my not-so-recent version of MinGW-w64 (4.8.2)
32 bit under Windows 7 x86.
It does not build with an older version of MinGW-w64(4.7.2) but I think
that is not a real problem.
Then I tried it with a usb device. usbdk seems to hide the device
successfully and libusb xusb example seems to work fine. That
is a good sign.
I also tried to use libusbdotnet with the device (Benchmark firmware
for libusbdotnet/libusbK) but libusbdotnet has problem to load the
libusb-1.0.dll I built. I will try later.
BTW, I also tried under Windows 8.1 x64 using MinGW-w64 4.8.2
64bit compiler and the results are also positive with the simple
listdev/xusb tests. The hiding/unhiding are a bit strange but I
will read the documentation to understand bettwe how UsbDk works.

Currently it seems to me UsbDkController.exe can only filter
on per-device and not per-interface (libusb-win32 filter does both).
Am I right? It should be useful to add per interface option.
--
Xiaofan
Dmitry Fleytman
2015-03-06 15:57:50 UTC
Permalink
Post by Xiaofan Chen
Post by Xiaofan Chen
Post by Dmitry Fleytman
Regarding the build, we’re compiling on FC21 system with mingw32/64, i.e.
./autogen.sh
mingw32-configure --enable-usbdk=yes (or mingw64-configure
--enable-usbdk=yes)
make
Seems to be okay with my not-so-recent version of MinGW-w64 (4.8.2)
32 bit under Windows 7 x86.
It does not build with an older version of MinGW-w64(4.7.2) but I think
that is not a real problem.
Then I tried it with a usb device. usbdk seems to hide the device
successfully and libusb xusb example seems to work fine. That
is a good sign.
I also tried to use libusbdotnet with the device (Benchmark firmware
for libusbdotnet/libusbK) but libusbdotnet has problem to load the
libusb-1.0.dll I built. I will try later.
BTW, I also tried under Windows 8.1 x64 using MinGW-w64 4.8.2
64bit compiler and the results are also positive with the simple
listdev/xusb tests. The hiding/unhiding are a bit strange but I
will read the documentation to understand bettwe how UsbDk works.
Hide/unhide API is not utilised by libusb.
It is a separate API to detach a device from OS without actually acquiring it. There is a number of use cases for it but they are out of libusb scope.
Post by Xiaofan Chen
Currently it seems to me UsbDkController.exe can only filter
on per-device and not per-interface (libusb-win32 filter does both).
Am I right? It should be useful to add per interface option.
Do you mean composite devices split by pre-interface filtering?

BTW, UsbDkController.exe is a simple testing application not meant for production. It does not necessarily support all features of UsbDk API.
Post by Xiaofan Chen
--
Xiaofan
Xiaofan Chen
2015-03-06 23:24:54 UTC
Permalink
Post by Dmitry Fleytman
Post by Xiaofan Chen
BTW, I also tried under Windows 8.1 x64 using MinGW-w64 4.8.2
64bit compiler and the results are also positive with the simple
listdev/xusb tests. The hiding/unhiding are a bit strange but I
will read the documentation to understand bettwe how UsbDk works.
Hide/unhide API is not utilised by libusb.
It is a separate API to detach a device from OS without actually
acquiring it. There is a number of use cases for it but they are out of
libusb scope.
Right. I was talking about UsbDkController.exe.
Post by Dmitry Fleytman
Post by Xiaofan Chen
Currently it seems to me UsbDkController.exe can only filter
on per-device and not per-interface (libusb-win32 filter does both).
Am I right? It should be useful to add per interface option.
Do you mean composite devices split by pre-interface filtering?
Yes. libusb-win32 filter can be used to filter the composite
parent or the individual interface.
Post by Dmitry Fleytman
BTW, UsbDkController.exe is a simple testing application not
meant for production. It does not necessarily support all features
of UsbDk API.
I see. Probably more examples can be provided to demonstrate
the features. :)
--
Xiaofan
Dmitry Fleytman
2015-03-08 11:36:09 UTC
Permalink
Post by Xiaofan Chen
Post by Dmitry Fleytman
Post by Xiaofan Chen
BTW, I also tried under Windows 8.1 x64 using MinGW-w64 4.8.2
64bit compiler and the results are also positive with the simple
listdev/xusb tests. The hiding/unhiding are a bit strange but I
will read the documentation to understand bettwe how UsbDk works.
Hide/unhide API is not utilised by libusb.
It is a separate API to detach a device from OS without actually
acquiring it. There is a number of use cases for it but they are out of
libusb scope.
Right. I was talking about UsbDkController.exe.
Post by Dmitry Fleytman
Post by Xiaofan Chen
Currently it seems to me UsbDkController.exe can only filter
on per-device and not per-interface (libusb-win32 filter does both).
Am I right? It should be useful to add per interface option.
Do you mean composite devices split by pre-interface filtering?
Yes. libusb-win32 filter can be used to filter the composite
parent or the individual interface.
Currently UsbDk doesn’t support composite device split.
This feature is in our task list.
Post by Xiaofan Chen
Post by Dmitry Fleytman
BTW, UsbDkController.exe is a simple testing application not
meant for production. It does not necessarily support all features
of UsbDk API.
I see. Probably more examples can be provided to demonstrate
the features. :)
--
Xiaofan
Xiaofan Chen
2015-03-06 23:35:02 UTC
Permalink
Post by Xiaofan Chen
BTW, I also tried under Windows 8.1 x64 using MinGW-w64 4.8.2
64bit compiler and the results are also positive with the simple
listdev/xusb tests.
Then I tested libftdi-1 under Windows 7 x86 and the results
are positive.

So based on the simple tests, UsbDk and the libusb patches
seem to work fine.

Right now I do not have a good MinGW.org installation to
test the MinGW.org build (now MinGW.org installer
seems to quite problematic) and the older working
MinGW.org toolchain with GCC 4.7.2 failed to build
the code similar to an older MinGW-w64 4.7.2 installation.

I do not use Cygwin (since I do not really need to use it and
do not quite like it) any more so I will not test that one.

Overall I think it seems to work fine based on the simple
tests I have done. Good job!
--
Xiaofan
Xiaofan Chen
2015-03-07 01:48:18 UTC
Permalink
Post by Xiaofan Chen
So based on the simple tests, UsbDk and the libusb patches
seem to work fine.
Right now I do not have a good MinGW.org installation to
test the MinGW.org build (now MinGW.org installer
seems to quite problematic) and the older working
MinGW.org toolchain with GCC 4.7.2 failed to build
the code similar to an older MinGW-w64 4.7.2 installation.
For the record, the following is the build log for an
older MinGW-w64 4.7.2 installation. Not so sure if it is
easy to fix. But this is not really important since later
version I have works (4.8.2).

***@mcuee-PC /c/work/libusb/usbdk/mingw32/libusb
$ make -i
make all-recursive
make[1]: Entering directory `/c/work/libusb/usbdk/mingw32/libusb'
Making all in libusb
make[2]: Entering directory `/c/work/libusb/usbdk/mingw32/libusb/libusb'
make[3]: Entering directory `/c/work/libusb/usbdk/mingw32/libusb/libusb'
CC os/libusb_1_0_la-windows_usbdk.lo
os/windows_usbdk.c: In function 'usbdk_do_control_transfer':
os/windows_usbdk.c:573:36: error: 'NTSTATUS' undeclared (first use in this funct
ion)
os/windows_usbdk.c:573:36: note: each undeclared identifier is reported only onc
e for each function it appears in
os/windows_usbdk.c:573:36: error: expected ')' before numeric constant
os/windows_usbdk.c: In function 'usbdk_do_bulk_transfer':
os/windows_usbdk.c:638:36: error: 'NTSTATUS' undeclared (first use in this funct
ion)
os/windows_usbdk.c:638:36: error: expected ')' before numeric constant
os/windows_usbdk.c: In function 'usbdk_do_iso_transfer':
os/windows_usbdk.c:710:36: error: 'NTSTATUS' undeclared (first use in this funct
ion)
os/windows_usbdk.c:710:36: error: expected ')' before numeric constant
os/windows_usbdk.c: In function 'win_backend_get_overlapped_result':
os/windows_usbdk.c:803:9: error: 'NTSTATUS' undeclared (first use in this functi
on)
os/windows_usbdk.c:803:9: error: expected ')' before numeric constant
os/windows_usbdk.c:814:22: error: expected ')' before numeric constant
os/windows_usbdk.c:815:22: error: expected ')' before numeric constant
os/windows_usbdk.c:816:22: error: 'STATUS_REQUEST_CANCELED' undeclared (first us
e in this function)
Makefile:681: recipe for target `os/libusb_1_0_la-windows_usbdk.lo' failed
make[3]: [os/libusb_1_0_la-windows_usbdk.lo] Error 1 (ignored)
mv: cannot stat `os/.deps/libusb_1_0_la-windows_usbdk.Tpo': No such file or dire
ctory
Makefile:681: recipe for target `os/libusb_1_0_la-windows_usbdk.lo' failed
make[3]: [os/libusb_1_0_la-windows_usbdk.lo] Error 1 (ignored)
CCLD libusb-1.0.la
libtool: link: `os/libusb_1_0_la-windows_usbdk.lo' is not a valid libtool object

Makefile:500: recipe for target `libusb-1.0.la' failed
make[3]: [libusb-1.0.la] Error 1 (ignored)
make[3]: Leaving directory `/c/work/libusb/usbdk/mingw32/libusb/libusb'
CC os/libusb_1_0_la-windows_usbdk.lo
os/windows_usbdk.c: In function 'usbdk_do_control_transfer':
os/windows_usbdk.c:573:36: error: 'NTSTATUS' undeclared (first use in this funct
ion)
os/windows_usbdk.c:573:36: note: each undeclared identifier is reported only onc
e for each function it appears in
os/windows_usbdk.c:573:36: error: expected ')' before numeric constant
os/windows_usbdk.c: In function 'usbdk_do_bulk_transfer':
os/windows_usbdk.c:638:36: error: 'NTSTATUS' undeclared (first use in this funct
ion)
os/windows_usbdk.c:638:36: error: expected ')' before numeric constant
os/windows_usbdk.c: In function 'usbdk_do_iso_transfer':
os/windows_usbdk.c:710:36: error: 'NTSTATUS' undeclared (first use in this funct
ion)
os/windows_usbdk.c:710:36: error: expected ')' before numeric constant
os/windows_usbdk.c: In function 'win_backend_get_overlapped_result':
os/windows_usbdk.c:803:9: error: 'NTSTATUS' undeclared (first use in this functi
on)
os/windows_usbdk.c:803:9: error: expected ')' before numeric constant
os/windows_usbdk.c:814:22: error: expected ')' before numeric constant
os/windows_usbdk.c:815:22: error: expected ')' before numeric constant
os/windows_usbdk.c:816:22: error: 'STATUS_REQUEST_CANCELED' undeclared (first us
e in this function)
Makefile:681: recipe for target `os/libusb_1_0_la-windows_usbdk.lo' failed
make[2]: [os/libusb_1_0_la-windows_usbdk.lo] Error 1 (ignored)
mv: cannot stat `os/.deps/libusb_1_0_la-windows_usbdk.Tpo': No such file or dire
ctory
Makefile:681: recipe for target `os/libusb_1_0_la-windows_usbdk.lo' failed
make[2]: [os/libusb_1_0_la-windows_usbdk.lo] Error 1 (ignored)
CCLD libusb-1.0.la
libtool: link: `os/libusb_1_0_la-windows_usbdk.lo' is not a valid libtool object

Makefile:500: recipe for target `libusb-1.0.la' failed
make[2]: [libusb-1.0.la] Error 1 (ignored)
GEN libusb-1.0.dll
make[2]: Leaving directory `/c/work/libusb/usbdk/mingw32/libusb/libusb'
Making all in doc
make[2]: Entering directory `/c/work/libusb/usbdk/mingw32/libusb/doc'
make[2]: Nothing to be done for `all'.
make[2]: Leaving directory `/c/work/libusb/usbdk/mingw32/libusb/doc'
Making all in examples
make[2]: Entering directory `/c/work/libusb/usbdk/mingw32/libusb/examples'
make[2]: *** No rule to make target `../libusb/libusb-1.0.la', needed by `listde
vs.exe'. Stop.
make[2]: Leaving directory `/c/work/libusb/usbdk/mingw32/libusb/examples'
Makefile:409: recipe for target `all-recursive' failed
make[1]: [all-recursive] Error 1 (ignored)
make[1]: Leaving directory `/c/work/libusb/usbdk/mingw32/libusb'
--
Xiaofan
Xiaofan Chen
2015-03-07 01:55:31 UTC
Permalink
Post by Xiaofan Chen
Post by Xiaofan Chen
So based on the simple tests, UsbDk and the libusb patches
seem to work fine.
Right now I do not have a good MinGW.org installation to
test the MinGW.org build (now MinGW.org installer
seems to quite problematic) and the older working
MinGW.org toolchain with GCC 4.7.2 failed to build
the code similar to an older MinGW-w64 4.7.2 installation.
For the record, the following is the build log for an
older MinGW-w64 4.7.2 installation. Not so sure if it is
easy to fix. But this is not really important since later
version I have works (4.8.2).
Another log for my MinGW.org with GCC 4.7.2.

On one hand, it is not that important, on the other hand,
both failed toolchain have no problem to build the normal
libusb git. So it is kind of regression as well.

$ make -i
make all-recursive
make[1]: Entering directory `/c/work/libusb/usbdk/mingworg/libusb'
Making all in libusb
make[2]: Entering directory `/c/work/libusb/usbdk/mingworg/libusb/libusb'
make[3]: Entering directory `/c/work/libusb/usbdk/mingworg/libusb/libusb'
CC os/libusb_1_0_la-windows_usbdk.lo
os/windows_usbdk.c:26:22: fatal error: ntstatus.h: No such file or directory
compilation terminated.
make[3]: [os/libusb_1_0_la-windows_usbdk.lo] Error 1 (ignored)
mv: cannot stat `os/.deps/libusb_1_0_la-windows_usbdk.Tpo': No such file or dire
ctory
make[3]: [os/libusb_1_0_la-windows_usbdk.lo] Error 1 (ignored)
CC os/libusb_1_0_la-windows_nt_common.lo
os/windows_nt_common.c: In function 'windows_error_str':
os/windows_nt_common.c:77:36: error: 'FACILITY_SETUPAPI' undeclared (first use i
n this function)
os/windows_nt_common.c:77:36: note: each undeclared identifier is reported only
once for each function it appears in
make[3]: [os/libusb_1_0_la-windows_nt_common.lo] Error 1 (ignored)
mv: cannot stat `os/.deps/libusb_1_0_la-windows_nt_common.Tpo': No such file or
directory
make[3]: [os/libusb_1_0_la-windows_nt_common.lo] Error 1 (ignored)
CCLD libusb-1.0.la
libtool: link: `os/libusb_1_0_la-windows_usbdk.lo' is not a valid libtool object

make[3]: [libusb-1.0.la] Error 1 (ignored)
make[3]: Leaving directory `/c/work/libusb/usbdk/mingworg/libusb/libusb'
CC os/libusb_1_0_la-windows_usbdk.lo
os/windows_usbdk.c:26:22: fatal error: ntstatus.h: No such file or directory
compilation terminated.
make[2]: [os/libusb_1_0_la-windows_usbdk.lo] Error 1 (ignored)
mv: cannot stat `os/.deps/libusb_1_0_la-windows_usbdk.Tpo': No such file or dire
ctory
make[2]: [os/libusb_1_0_la-windows_usbdk.lo] Error 1 (ignored)
CC os/libusb_1_0_la-windows_nt_common.lo
os/windows_nt_common.c: In function 'windows_error_str':
os/windows_nt_common.c:77:36: error: 'FACILITY_SETUPAPI' undeclared (first use i
n this function)
os/windows_nt_common.c:77:36: note: each undeclared identifier is reported only
once for each function it appears in
make[2]: [os/libusb_1_0_la-windows_nt_common.lo] Error 1 (ignored)
mv: cannot stat `os/.deps/libusb_1_0_la-windows_nt_common.Tpo': No such file or
directory
make[2]: [os/libusb_1_0_la-windows_nt_common.lo] Error 1 (ignored)
CCLD libusb-1.0.la
libtool: link: `os/libusb_1_0_la-windows_usbdk.lo' is not a valid libtool object

make[2]: [libusb-1.0.la] Error 1 (ignored)
GEN libusb-1.0.dll
make[2]: Leaving directory `/c/work/libusb/usbdk/mingworg/libusb/libusb'
Making all in doc
make[2]: Entering directory `/c/work/libusb/usbdk/mingworg/libusb/doc'
make[2]: Nothing to be done for `all'.
make[2]: Leaving directory `/c/work/libusb/usbdk/mingworg/libusb/doc'
Making all in examples
make[2]: Entering directory `/c/work/libusb/usbdk/mingworg/libusb/examples'
make[2]: *** No rule to make target `../libusb/libusb-1.0.la', needed by `listde
vs.exe'. Stop.
make[2]: Leaving directory `/c/work/libusb/usbdk/mingworg/libusb/examples'
make[1]: [all-recursive] Error 1 (ignored)
make[1]: Leaving directory `/c/work/libusb/usbdk/mingworg/libusb'
--
Xiaofan
Pete Batard
2015-03-05 22:09:35 UTC
Permalink
Post by Dmitry Fleytman
For convenience, I’ve created libusb fork on github and put patches
https://github.com/dmitryfleytman/libusb/tree/usbdk-backend-v1
Thanks for this. I guess I'm going to continue with the superficial
nitpicking for now. :)

1. Why do you need an UsbDk/ subdirectory? We have one for haiku, yes,
but it's mostly because they have quite a number of additional files
(that are C++ rather than our usual C), and they needed a dedicated
configure. On the other hand, UsbDk\ contains only 2 headers and the
current windows_usbdk.h header in parent directory is "empty" (see #4)

2. The libusb naming convention for sources is to use lowercase and
underscore. Your UsbDk headers should really be named
"windows_usbdk_data.h" and "windows_usbdk_helper.h"

3. Those headers are rather small - couldn't they be merged in a single
windows_usbdk.h (which would also solve #4)?

4. What's the point of the current windows_usbdk.h that only contains a
#pragma once? That seems rather useless.

5. (This is more of a *strongly preferred* request) Anybody who brings
major changes to Windows is expected to provide and have tested a
working solution for all of MinGW, cygwin and Visual Studio (2013 being
preferred since its Community Edition is freely available). You don't
have to test every individual instance of each (meaning, if you tested
with MinGW32, we're not really gonna expect you to also have tested with
MinGW-w64), but you are strongly advised to provide a working Visual
Studio solution sooner rather than later...

6. On that account, what [is|was] your plan to bring the optionality of
UsbDk for Visual Studio? I hope you realize that Visual Studio doesn't
exactly provide users with a configure step to pick features... I guess
we could go with what we did for DLL vs static (one solution
encompassing 2 library projects), but that means we'll have to contend
with 4 project files... multiplied by the number of versions of Visual
Studio we intend to support.

7. I think we're gonna have to solve the confusion of having something
like windows_common.h + [winnt_common.h|windows_core.h] + windows_usb.h,
because the current designation hardly gives any hind as to what is the
exact purpose of each of these generic headers. Also if Windows gets
broken down between windows_usb and windows_usbdk, I think we ought to
rename windows_usb.c (and possibly windows_usbdk.c), as, per designation
alone, windows_usb is expected to be a superset of anything USB, which
therefore should include windows_usbdk. Thus, we have to find a means to
convey that the new "windows_usb" is really "windows_usb, sans the UsbDk
functionality". Right now, considering that UsbDk is a filter, and the
rest of the interface is aimed at conventional single drivers (with the
exception of libusb0 as a filter, but that doesn't bother me much, since
the prime use of libusb0 is regular) what I'd be leaning on would be to
have a windows_driver.c and windows_filter.c (which of course is
somewhat of a misnommer since a filter driver is still a driver). Or it
could be something else that makes more send. However I don't think we
should continue with windows_usb.c when that source has just lost its
USB genericity...

Regards,

/Pete
Dmitry Fleytman
2015-03-06 13:13:13 UTC
Permalink
Post by Pete Batard
Post by Dmitry Fleytman
For convenience, I’ve created libusb fork on github and put patches
https://github.com/dmitryfleytman/libusb/tree/usbdk-backend-v1
Thanks for this. I guess I'm going to continue with the superficial
nitpicking for now. :)
Hi Pete,
Post by Pete Batard
1. Why do you need an UsbDk/ subdirectory? We have one for haiku, yes,
but it's mostly because they have quite a number of additional files
(that are C++ rather than our usual C), and they needed a dedicated
configure. On the other hand, UsbDk\ contains only 2 headers and the
current windows_usbdk.h header in parent directory is "empty" (see #4)
2. The libusb naming convention for sources is to use lowercase and
underscore. Your UsbDk headers should really be named
"windows_usbdk_data.h" and "windows_usbdk_helper.h"
3. Those headers are rather small - couldn't they be merged in a single
windows_usbdk.h (which would also solve #4)?
4. What's the point of the current windows_usbdk.h that only contains a
#pragma once? That seems rather useless.
The idea behind subdirectory and 2 files with these specific names is that we put headers with API definitions as-is from UsbDk source tree. This was done to simplify future updates of UsbDk headers - plain copy instead of manual merge. However, if you think it is better to have header files that follow libusb guidelines anyway, we will do corresponding changes.
Post by Pete Batard
5. (This is more of a *strongly preferred* request) Anybody who brings
major changes to Windows is expected to provide and have tested a
working solution for all of MinGW, cygwin and Visual Studio (2013 being
preferred since its Community Edition is freely available). You don't
have to test every individual instance of each (meaning, if you tested
with MinGW32, we're not really gonna expect you to also have tested with
MinGW-w64), but you are strongly advised to provide a working Visual
Studio solution sooner rather than later…
Yes, we could do this.
Post by Pete Batard
6. On that account, what [is|was] your plan to bring the optionality of
UsbDk for Visual Studio? I hope you realize that Visual Studio doesn't
exactly provide users with a configure step to pick features... I guess
we could go with what we did for DLL vs static (one solution
encompassing 2 library projects), but that means we'll have to contend
with 4 project files... multiplied by the number of versions of Visual
Studio we intend to support.
The same level of optionality may be achieved by single solution with multiple configurations.

In any case, I tend to make backend selection logic run-time instead of compile time.
What strategy would you suggest - having additional libusb API for Windows sub-backed selection or extending current libusbk/winusb selection scheme?
Post by Pete Batard
7. I think we're gonna have to solve the confusion of having something
like windows_common.h + [winnt_common.h|windows_core.h] + windows_usb.h,
because the current designation hardly gives any hind as to what is the
exact purpose of each of these generic headers. Also if Windows gets
broken down between windows_usb and windows_usbdk, I think we ought to
rename windows_usb.c (and possibly windows_usbdk.c), as, per designation
alone, windows_usb is expected to be a superset of anything USB, which
therefore should include windows_usbdk. Thus, we have to find a means to
convey that the new "windows_usb" is really "windows_usb, sans the UsbDk
functionality". Right now, considering that UsbDk is a filter, and the
rest of the interface is aimed at conventional single drivers (with the
exception of libusb0 as a filter, but that doesn't bother me much, since
the prime use of libusb0 is regular) what I'd be leaning on would be to
have a windows_driver.c and windows_filter.c (which of course is
somewhat of a misnomer since a filter driver is still a driver). Or it
could be something else that makes more send. However I don't think we
should continue with windows_usb.c when that source has just lost its
USB genericity…
What if we establish naming by API names, i.e. windows_usb.c with support for WinUsb/libusbk becomes windows_winusb.c and UsbDk support stays at windows_usbdk.c?

~Dmitry
Post by Pete Batard
Regards,
/Pete
------------------------------------------------------------------------------
Dive into the World of Parallel Programming The Go Parallel Website, sponsored
by Intel and developed in partnership with Slashdot Media, is your hub for all
things parallel software development, from weekly thought leadership blogs to
news, videos, case studies, tutorials and more. Take a look and join the
conversation now. http://goparallel.sourceforge.net/
_______________________________________________
libusb-devel mailing list
https://lists.sourceforge.net/lists/listinfo/libusb-devel
Pete Batard
2015-03-08 22:40:24 UTC
Permalink
Post by Dmitry Fleytman
The idea behind subdirectory and 2 files with these specific names is
that we put headers with API definitions as-is from UsbDk source tree.
This was done to simplify future updates of UsbDk headers
I would prefer avoiding that. I think it makes more sense to try to keep
libusb as a standalone project, that doesn't require specific knowledge
of another project to understand our sourcecode structure, and I'm
hoping that 2 merged headers in sync is OK.
Post by Dmitry Fleytman
Post by Pete Batard
6. On that account, what [is|was] your plan to bring the optionality of
UsbDk for Visual Studio?
The same level of optionality may be achieved by single solution with
multiple configurations.
True. The only downside I see is that most MSVC users would be used to
using configurations for Release/Debug, and little else, so they may not
expect the selection to happen there. I'm also a bit partial to having
different projects, as we do for DLL and static, as this makes it
explicitly clear when a user opens the solution. Then again, I'm the one
who introduced this approach in libusb, so I can't say I'm totally
impartial here... ;)
Post by Dmitry Fleytman
What strategy would you suggest - having additional libusb API for
Windows sub-backed selection or extending current libusbk/winusb
selection scheme?
Due to the WinUSB-like nature of the libusbK DLL (and the fact that it
will also handle libusb0 in a WinUSB like manner), the only selection
occurring happens at runtime, according to the driver that is installed
for the target device.

Of course, since we can't use that for UsbDk, we need a different
approach. I guess your question is a follow up to a question you had,
which I didn't answer in your previous reply.
Post by Dmitry Fleytman
1. Add explicit API to libusb for selection of the backend
2. Extend current libusb backend selection logic that selects
libusbk/winusb sub-api based on libusbk is presence in the system.
My current thinking is that we seem to have an API that could be used to
do exactly the kind of UsbDk driver runtime "override", in the form of
libusb_detach_kernel_driver() [1]. As a matter of fact, this is an API
that was a bit problematic on Windows, because it looked like a pure
POSIX construct that would never make much sense in a Microsoft world...
But with UsbDk, this might not be true any longer.

If I understand what UsbDk correctly, it looks like detach_driver would
fit the bill nicely for giving Windows libusb users the choice of using
UsbDk at runtime, by "detaching" whatever regular driver is currently
installed, and get the UsbDk filter in. Then when they are done with
libusb/UsbDk access, they can call libusb_attach_kernel_driver() to
reattach the existing regular driver.
Oh and the other nice thing we have going to attach/detach is that we
have an LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER [2] capability as well,
to indicate whether the current libusb supports the feature.

So I guess my preference for UsbDk usage would be to have it enabled
default (though we can keep the switch to allow people to disable it if
they want to), and have libusb app developers rely on
libusb_has_capability() and libusb_detach_kernel_driver() to access
their devices through UsbDk.

Of course this means that someone wishing to update an existing Windows
application to always use UsbDk will have to add extra code (as opposed
to flipping a switch on library compilation), since those are not
expected to use detach_driver(). However, this is probably what we want
to ensure that an app that was using WinUSB/libusb0/libusbK continues to
do so. And then again, some apps that are being ported to Windows may
already use has_capability() and detach_driver(), in which case they
will have to add extra code if they don't want to use UsbDk.

Now, since I still haven't looked at the details of your proposal, I
can't tell for sure if detach/attach is something that would be easy to
apply to what you currently have, or if it might be a headache. I'd also
like to find out if other people on this list have a strong opinion (or
technical flaw) against the use of the existing detach/attach for Windows.
Post by Dmitry Fleytman
Post by Pete Batard
7. I think we're gonna have to solve the confusion of having something
like windows_common.h + [winnt_common.h|windows_core.h] + windows_usb.h
(...)
have a windows_driver.c and windows_filter.c
What if we establish naming by API names, i.e. windows_usb.c with support
for WinUsb/libusbk becomes windows_winusb.c and UsbDk support stays
at windows_usbdk.c?
That sounds much clearer than what I was proposing!
Unless the libusb0/libusbK people are unhappy to see only the WinUSB
name mentioned, I think your proposal is the better solution indeed.

Regards,

/Pete

[1]
http://libusb.sourceforge.net/api-1.0/group__dev.html#ga21bd343325f558987ca57e4e281a6d47
[2]
http://libusb.sourceforge.net/api-1.0/group__misc.html#gaab1b3fa0728c06fafbee897795889bd5
Xiaofan Chen
2015-03-09 09:22:09 UTC
Permalink
Post by Pete Batard
Post by Dmitry Fleytman
Post by Pete Batard
7. I think we're gonna have to solve the confusion of having something
like windows_common.h + [winnt_common.h|windows_core.h] + windows_usb.h
(...)
have a windows_driver.c and windows_filter.c
What if we establish naming by API names, i.e. windows_usb.c with support
for WinUsb/libusbk becomes windows_winusb.c and UsbDk support stays
at windows_usbdk.c?
That sounds much clearer than what I was proposing!
Unless the libusb0/libusbK people are unhappy to see only the WinUSB
name mentioned, I think your proposal is the better solution indeed.
I do not see this as a problem myself. In fact, I think WinUSB is
the preferred general purpose driver in the future. libusb0.sys does
not matter too much for libusb Windows backend since its unique
filter capability does not work too well for many device. WinUSB
has bridged libusbK's main advantage (isoc transfer) in Windows 8.1
so that libusbK's limited use will probably for those who like the
Windows only libusbK API.

UsbDk's dynamic driver switching capability is interesting. So I think
it may well have some niches as well.

To Travis: if you have some objection, please respond. If no response,
then I assume you are okay with the proposal.
--
Xiaofan
Graeme Gill
2015-03-10 00:00:09 UTC
Permalink
Post by Xiaofan Chen
the preferred general purpose driver in the future. libusb0.sys does
not matter too much for libusb Windows backend since its unique
filter capability does not work too well for many device.
Are there any contemporary reports of problems with libusb0.sys
as a filter driver ? - I've not noticed any on the libusb-win32 list,
just the references to the historical problems before Travis fixed it.
Post by Xiaofan Chen
WinUSB
has bridged libusbK's main advantage (isoc transfer) in Windows 8.1
so that libusbK's limited use will probably for those who like the
Windows only libusbK API.
The inability to control certain aspects of WinUSB enumeration behavior
(making it incompatible with some USB devices I support) makes it
a non-choice for my particular application, so don't draw
the conclusion that libusb0 is deprecated - it's not.
Post by Xiaofan Chen
UsbDk's dynamic driver switching capability is interesting. So I think
it may well have some niches as well.
It's attractive from the point of view of inter-working with existing
vendor devices system drivers (just like libusb0 filter mode), perhaps
avoiding the need to swap drivers simply to use alternate user applications.

Graeme Gill.
Xiaofan Chen
2015-03-10 06:35:55 UTC
Permalink
Post by Graeme Gill
Post by Xiaofan Chen
the preferred general purpose driver in the future. libusb0.sys does
not matter too much for libusb Windows backend since its unique
filter capability does not work too well for many device.
Are there any contemporary reports of problems with libusb0.sys
as a filter driver ? - I've not noticed any on the libusb-win32 list,
just the references to the historical problems before Travis fixed it.
It does not work on device with (most of the?) UMDF driver which
seems to be preferred driver model for many USB device.

The problem with current libusb Windows backend is that
libusb0.sys does not work well, especially the filter mode.
Therefore it can not be recommended to be used now
with the libusb Windows backend (libusb-1.0 API).

Probably this should be fixed but I think it is not the focus now.
Post by Graeme Gill
Post by Xiaofan Chen
WinUSB
has bridged libusbK's main advantage (isoc transfer) in Windows 8.1
so that libusbK's limited use will probably for those who like the
Windows only libusbK API.
The inability to control certain aspects of WinUSB enumeration behavior
(making it incompatible with some USB devices I support) makes it
a non-choice for my particular application, so don't draw
the conclusion that libusb0 is deprecated - it's not.
I never say that libusb0.sys (or libusb-win32 project) is deprecated.
In fact, it is in bug-fix only mode but still supported. It is just that it
does not work with the current libusb Windows backend.
Post by Graeme Gill
Post by Xiaofan Chen
UsbDk's dynamic driver switching capability is interesting. So I think
it may well have some niches as well.
It's attractive from the point of view of inter-working with existing
vendor devices system drivers (just like libusb0 filter mode), perhaps
avoiding the need to swap drivers simply to use alternate user applications.
--
Xiaofan
Graeme Gill
2015-03-10 07:26:39 UTC
Permalink
Post by Xiaofan Chen
It does not work on device with (most of the?) UMDF driver which
seems to be preferred driver model for many USB device.
OK.
Post by Xiaofan Chen
In fact, it is in bug-fix only mode but still supported. It is just that it
does not work with the current libusb Windows backend.
It worked OK with my libusb changes, how many years ago now ?
Sad that official libusb never caught up.

Graeme Gill.

Loading...