From: Dmitry F. <dm...@da...> - 2015-03-02 18:25:37
|
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 (dfl...@re...) and Kirill Moizik (km...@re...) 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 |
From: Dmitry F. <dm...@da...> - 2015-03-02 18:26:37
|
Signed-off-by: Dmitry Fleytman <dfl...@re...> --- 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 |
From: Dmitry F. <dm...@da...> - 2015-03-02 18:30:18
|
From: Dmitry Fleytman <dfl...@re...> Signed-off-by: Pavel Gurvich <pa...@da...> Signed-off-by: Dmitry Fleytman <dfl...@re...> --- 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 <dm...@da...> +* Pavel Gurvich <pa...@da...> +* +* 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 <dm...@da...> +* Pavel Gurvich <pa...@da...> +* +* 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 <dm...@da...> + * Pavel Gurvich <pa...@da...> + * + * 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 = <ransfer->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 <dm...@da...> +* Pavel Gurvich <pa...@da...> +* +* 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 |
From: Dmitry F. <dm...@da...> - 2015-03-02 18:30:26
|
From: Dmitry Fleytman <dfl...@re...> New file windows_nt_common.c introduced. Signed-off-by: Dmitry Fleytman <dfl...@re...> --- 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 <pe...@ak...> + * 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 <pe...@ak...> + * 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 |
From: Chris D. <chr...@gm...> - 2015-03-02 19:42:52
|
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 On Mon, Mar 2, 2015 at 9:59 AM, Dmitry Fleytman <dm...@da...> wrote: > 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 (dfl...@re...) and > Kirill Moizik (km...@re...) 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 > > > > ------------------------------------------------------------------------------ > 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 > lib...@li... > https://lists.sourceforge.net/lists/listinfo/libusb-devel > |
From: Dmitry F. <dm...@da...> - 2015-03-03 08:17:08
|
> On Mar 2, 2015, at 21:42 PM, Chris Dickens <chr...@gm...> wrote: > > 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 > > On Mon, Mar 2, 2015 at 9:59 AM, Dmitry Fleytman <dm...@da... <mailto:dm...@da...>> wrote: > 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 <http://spice-space.org/>, source code repository available at: > 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> > > 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 <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> > > UsbDk documentation: > 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> > 3. UsbDk architecture specificatin (part of source tree): > http://cgit.freedesktop.org/spice/win32/usbdk/tree/ARCHITECTURE <http://cgit.freedesktop.org/spice/win32/usbdk/tree/ARCHITECTURE> > > UsbDk is maintained by Dmitry Fleytman (dfl...@re... <mailto:dfl...@re...>) and > Kirill Moizik (km...@re... <mailto:km...@re...>) 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 <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 > lib...@li... <mailto:lib...@li...> > https://lists.sourceforge.net/lists/listinfo/libusb-devel <https://lists.sourceforge.net/lists/listinfo/libusb-devel> > |
From: Pete B. <pe...@ak...> - 2015-03-02 23:09:13
|
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. On 2015.03.02 17:59, Dmitry Fleytman wrote: > 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. From [PATCH 1/3]: > libusb/os/windows_nt_common.c | 572 > libusb/os/windows_nt_common.h | 67 (...) > + void win_nt_destroy_clock() (...) > + 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 |
From: Dmitry F. <dm...@da...> - 2015-03-03 09:04:06
|
Hi Pete, Thanks for your reply. Please find my answers below. > On Mar 3, 2015, at 01:09 AM, Pete Batard <pe...@ak...> wrote: > > 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. > > 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. > > On 2015.03.02 17:59, Dmitry Fleytman wrote: >> 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? > > 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. > > 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! > > From [PATCH 1/3]: > >> libusb/os/windows_nt_common.c | 572 >> libusb/os/windows_nt_common.h | 67 > (...) >> + void win_nt_destroy_clock() > (...) >> + 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. > > 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. > > > 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 > 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 > lib...@li... > https://lists.sourceforge.net/lists/listinfo/libusb-devel |
From: Tim R. <ti...@pr...> - 2015-03-03 17:51:39
|
Pete Batard wrote: > From [PATCH 1/3]: > > > libusb/os/windows_nt_common.c | 572 > > libusb/os/windows_nt_common.h | 67 > (...) > > + void win_nt_destroy_clock() > (...) > > + 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, ti...@pr... Providenza & Boekelheide, Inc. |
From: Xiaofan C. <xia...@gm...> - 2015-03-03 01:26:40
|
On Tue, Mar 3, 2015 at 1:59 AM, Dmitry Fleytman <dm...@da...> wrote: > 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. > 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 |
From: Dmitry F. <dm...@da...> - 2015-03-03 09:10:26
|
> On Mar 3, 2015, at 03:26 AM, Xiaofan Chen <xia...@gm...> wrote: > > On Tue, Mar 3, 2015 at 1:59 AM, Dmitry Fleytman <dm...@da...> wrote: >> 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. >> > > 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> > > 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 > > > -- > Xiaofan |
From: Xiaofan C. <xia...@gm...> - 2015-03-04 00:08:44
|
On Tue, Mar 3, 2015 at 1:59 AM, Dmitry Fleytman <dm...@da...> wrote: > 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. >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). > > 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 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 |
From: Dmitry F. <dm...@da...> - 2015-03-04 08:33:33
|
Hi Xiaofan, > On Mar 4, 2015, at 02:08 AM, Xiaofan Chen <xia...@gm...> wrote: > > On Tue, Mar 3, 2015 at 1:59 AM, Dmitry Fleytman <dm...@da...> wrote: >> 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. > > 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. > > 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. > > "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. > > 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. > >> >> 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 > > 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 > > > -- > Xiaofan |
From: Jason K. <jas...@gm...> - 2015-03-05 01:57:43
|
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 > On Mar 4, 2015, at 12:33 AM, Dmitry Fleytman <dm...@da...> wrote: > > > Hi Xiaofan, > >> On Mar 4, 2015, at 02:08 AM, Xiaofan Chen <xia...@gm...> wrote: >> >> On Tue, Mar 3, 2015 at 1:59 AM, Dmitry Fleytman <dm...@da...> wrote: >>> 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. >> >> 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. > >> >> 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. > >> >> "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. > >> >> 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. > >> >>> >>> 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 >> >> 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 > >> >> >> -- >> 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 > lib...@li... > https://lists.sourceforge.net/lists/listinfo/libusb-devel |
From: Xiaofan C. <xia...@gm...> - 2015-03-05 02:56:57
|
On Thu, Mar 5, 2015 at 9:57 AM, Jason Kotzin <jas...@gm...> wrote: > 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. > 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 |
From: Jason K. <jas...@gm...> - 2015-03-05 03:02:49
|
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 > On Mar 4, 2015, at 6:56 PM, Xiaofan Chen <xia...@gm...> wrote: > > On Thu, Mar 5, 2015 at 9:57 AM, Jason Kotzin <jas...@gm...> wrote: >> 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. > >> 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 |
From: Dmitry F. <dm...@da...> - 2015-03-05 08:45:08
|
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. > On Mar 5, 2015, at 05:02 AM, Jason Kotzin <jas...@gm...> wrote: > > 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> > >> On Mar 4, 2015, at 6:56 PM, Xiaofan Chen <xia...@gm... <mailto:xia...@gm...>> wrote: >> >> On Thu, Mar 5, 2015 at 9:57 AM, Jason Kotzin <jas...@gm... <mailto:jas...@gm...>> wrote: >>> 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. >> >>> 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 > |
From: Pete B. <pe...@ak...> - 2015-03-05 22:32:17
|
On 2015.03.05 08:45, Dmitry Fleytman wrote: > 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 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 |
From: Dmitry F. <dm...@da...> - 2015-03-06 13:13:19
|
> On Mar 6, 2015, at 24:09 AM, Pete Batard <pe...@ak...> wrote: > > On 2015.03.05 08:45, Dmitry Fleytman wrote: >> 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 > > Thanks for this. I guess I'm going to continue with the superficial > nitpicking for now. :) Hi Pete, > > 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. > > 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. > > 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? > > 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 > > 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 > lib...@li... > https://lists.sourceforge.net/lists/listinfo/libusb-devel |
From: Pete B. <pe...@ak...> - 2015-03-08 22:40:35
|
On 2015.03.06 13:13, Dmitry Fleytman wrote: > 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. >> 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... ;) > 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. > 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. 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. >> 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 |
From: Xiaofan C. <xia...@gm...> - 2015-03-09 09:22:15
|
On Mon, Mar 9, 2015 at 6:40 AM, Pete Batard <pe...@ak...> wrote: > On 2015.03.06 13:13, Dmitry Fleytman wrote: > >>> 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 |
From: Graeme G. <gr...@ar...> - 2015-03-10 00:00:18
|
Xiaofan Chen wrote: > 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. > 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. > 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. |
From: Xiaofan C. <xia...@gm...> - 2015-03-10 06:36:02
|
On Tue, Mar 10, 2015 at 8:00 AM, Graeme Gill <gr...@ar...> wrote: > Xiaofan Chen wrote: >> 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. >> 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. >> 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 |
From: Graeme G. <gr...@ar...> - 2015-03-10 07:26:47
|
Xiaofan Chen wrote: > It does not work on device with (most of the?) UMDF driver which > seems to be preferred driver model for many USB device. OK. > 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. |
From: Xiaofan C. <xia...@gm...> - 2015-03-05 16:01:23
|
On Thu, Mar 5, 2015 at 4:45 PM, Dmitry Fleytman <dm...@da...> wrote: > 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 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. > 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 |