diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e4d33dccc..296c3584d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -749,19 +749,19 @@ if(ENABLE_SDL) endif() if(NOT ANDROID) - add_definitions(-D__LIBUSB__) - if(NOT APPLE) - find_package(LibUSB) - endif() - if(LIBUSB_FOUND AND NOT APPLE) - message("Using shared LibUSB") - include_directories(${LIBUSB_INCLUDE_DIR}) - else() - message("Using static LibUSB from Externals") - add_subdirectory(Externals/libusb) - set(LIBUSB_LIBRARIES usb) - endif() - set(LIBUSB_FOUND true) + add_definitions(-D__LIBUSB__) + if(NOT APPLE) + find_package(LibUSB) + endif() + if(LIBUSB_FOUND AND NOT APPLE) + message("Using shared LibUSB") + include_directories(${LIBUSB_INCLUDE_DIR}) + else() + message("Using static LibUSB from Externals") + add_subdirectory(Externals/libusb) + set(LIBUSB_LIBRARIES usb) + endif() + set(LIBUSB_FOUND true) endif() set(SFML_REQD_VERSION 2.1) diff --git a/Externals/libusb/AUTHORS b/Externals/libusb/AUTHORS index b7d7ac9b4f..70d407bd19 100644 --- a/Externals/libusb/AUTHORS +++ b/Externals/libusb/AUTHORS @@ -1,7 +1,7 @@ Copyright © 2001 Johannes Erdfelt Copyright © 2007-2009 Daniel Drake Copyright © 2010-2012 Peter Stuge -Copyright © 2008-2013 Nathan Hjelm +Copyright © 2008-2016 Nathan Hjelm Copyright © 2009-2013 Pete Batard Copyright © 2009-2013 Ludovic Rousseau Copyright © 2010-2012 Michael Plante diff --git a/Externals/libusb/ChangeLog b/Externals/libusb/ChangeLog index fc5fc2ad5f..2b076b34ac 100644 --- a/Externals/libusb/ChangeLog +++ b/Externals/libusb/ChangeLog @@ -1,6 +1,23 @@ For detailed information about the changes below, please see the git log or visit: http://log.libusb.info +2016-10-01: v1.0.21: +* Core: Refactor code related to transfer flags and timeout handling +* Darwin: Ignore root hub simulation devices +* Darwin: Improved support for OS X El Capitan +* Darwin: Work around devices with buggy endpoint descriptors +* Darwin: Do not use objc_registerThreadWithCollector after its deprecation +* Darwin: Use C11 atomics on 10.12+ as the OS atomics are now deprecated +* Linux: Support preallocating kernel memory for zerocopy USB +* Linux: Deal with receiving POLLERR before all transfers have completed +* Solaris: Add solaris backend +* Windows: Add Visual Studio 2015 support +* Windows: Add usbdk backend +* Prevent attempts to recursively handle events +* Fix race condition in handle_timeout() +* Allow transferred argument to be optional in bulk APIs +* Various other bug fixes and improvements + 2015-09-13: v1.0.20 * Add Haiku support * Fix multiple memory and resource leaks (#16, #52, #76, #81) diff --git a/Externals/libusb/DOLPHIN b/Externals/libusb/DOLPHIN index 4ff041c81a..dae7a9c3c6 100644 --- a/Externals/libusb/DOLPHIN +++ b/Externals/libusb/DOLPHIN @@ -1,4 +1,4 @@ -Dolphin-specific changes (as of 2016-08-25) +Dolphin-specific changes (as of 2016-11-20) ------------------------------------------- - removed all toplevel directories save msvc/ & libusb/ diff --git a/Externals/libusb/INSTALL b/Externals/libusb/INSTALL index 5458714e1e..2099840756 100644 --- a/Externals/libusb/INSTALL +++ b/Externals/libusb/INSTALL @@ -1,19 +1,25 @@ Installation Instructions ************************* -Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, -2006 Free Software Foundation, Inc. +Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, +Inc. -This file is free documentation; the Free Software Foundation gives -unlimited permission to copy, distribute and modify it. + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. Basic Installation ================== -Briefly, the shell commands `./configure; make; make install' should -configure, build, and install this package. The following + Briefly, the shell command `./configure && make && make install' +should configure, build, and install this package. The following more-detailed instructions are generic; see the `README' file for -instructions specific to this package. +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses @@ -42,7 +48,7 @@ may remove or edit it. you want to change it or regenerate `configure' using a newer version of `autoconf'. -The simplest way to compile this package is: + The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. @@ -53,12 +59,22 @@ The simplest way to compile this package is: 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with - the package. + the package, generally using the just-built uninstalled binaries. 4. Type `make install' to install the programs and any data files and - documentation. + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. - 5. You can remove the program binaries and object files from the + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is @@ -67,12 +83,22 @@ The simplest way to compile this package is: all sorts of other programs in order to regenerate files that came with the distribution. + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + Compilers and Options ===================== -Some systems require unusual options for compilation or linking that the -`configure' script does not know about. Run `./configure --help' for -details on some of the pertinent environment variables. + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here @@ -85,25 +111,41 @@ is an example: Compiling For Multiple Architectures ==================================== -You can compile the package for more than one kind of computer at the + You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the -source code in the directory that `configure' is in and in `..'. +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. With a non-GNU `make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + Installation Names ================== -By default, `make install' installs the package's commands under + By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving -`configure' the option `--prefix=PREFIX'. +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you @@ -114,16 +156,47 @@ Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories -you can set and what kinds of files go in them. +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. -Optional Features -================= - -Some packages pay attention to `--enable-FEATURE' options to + Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The @@ -135,14 +208,58 @@ find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + HP-UX `make' updates targets which have the same time stamps as +their prerequisites, which makes it generally unusable when shipped +generated files such as `configure' are involved. Use GNU `make' +instead. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + Specifying the System Type ========================== -There may be some features `configure' cannot figure out automatically, -but needs to determine by the type of machine the package will run on. -Usually, assuming the package is built to be run on the _same_ -architectures, `configure' can figure that out, but if it prints a -message saying it cannot guess the machine type, give it the + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: @@ -150,7 +267,8 @@ type, such as `sun4', or a canonical name which has the form: where SYSTEM can have one of these forms: - OS KERNEL-OS + OS + KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't @@ -168,9 +286,9 @@ eventually be run) with `--host=TYPE'. Sharing Defaults ================ -If you want to set default values for `configure' scripts to share, you -can create a site shell script called `config.site' that gives default -values for variables like `CC', `cache_file', and `prefix'. + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. @@ -179,7 +297,7 @@ A warning: not all `configure' scripts look for a site script. Defining Variables ================== -Variables not defined in a site shell script can be set in the + Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set @@ -191,18 +309,27 @@ causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL' due to -an Autoconf bug. Until the bug is fixed you can use this workaround: +an Autoconf limitation. Until the limitation is lifted, you can use +this workaround: - CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== -`configure' recognizes the following options to control how it operates. + `configure' recognizes the following options to control how it +operates. `--help' `-h' - Print a summary of the options to `configure', and exit. + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. `--version' `-V' @@ -229,6 +356,15 @@ an Autoconf bug. Until the bug is fixed you can use this workaround: Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. - diff --git a/Externals/libusb/README b/Externals/libusb/README index 9d434f9727..0554e4eb03 100644 --- a/Externals/libusb/README +++ b/Externals/libusb/README @@ -1,15 +1,18 @@ -libusb -====== +# libusb + +[![Build Status](https://travis-ci.org/libusb/libusb.svg?branch=master)](https://travis-ci.org/libusb/libusb) +[![Build status](https://ci.appveyor.com/api/projects/status/xvrfam94jii4a6lw?svg=true)](https://ci.appveyor.com/project/LudovicRousseau/libusb) +[![Coverity Scan Build Status](https://scan.coverity.com/projects/2180/badge.svg)](https://scan.coverity.com/projects/libusb-libusb) libusb is a library for USB device access from Linux, Mac OS X, Windows, OpenBSD/NetBSD and Haiku userspace. It is written in C (Haiku backend in C++) and licensed under the GNU Lesser General Public License version 2.1 or, at your option, any later -version (see COPYING). +version (see [COPYING](COPYING)). libusb is abstracted internally in such a way that it can hopefully -be ported to other operating systems. Please see the PORTING file -for more information. +be ported to other operating systems. Please see the [PORTING](PORTING) +file for more information. libusb homepage: http://libusb.info/ @@ -24,6 +27,7 @@ http://mailing-list.libusb.info - Hans de Goede - Xiaofan Chen - Ludovic Rousseau -- Nathan Hjelm +- Nathan Hjelm - Chris Dickens + (Please use the mailing list rather than mailing developers directly) diff --git a/Externals/libusb/TODO b/Externals/libusb/TODO index 19dd1d0e6f..1e13760efe 100644 --- a/Externals/libusb/TODO +++ b/Externals/libusb/TODO @@ -1,2 +1,2 @@ Please see the libusb roadmap by visiting: -https://github.com/libusb/libusb/issues/milestones?direction=asc&sort=due_date +https://github.com/libusb/libusb/milestones?direction=asc&sort=due_date&state=open diff --git a/Externals/libusb/libusb/Makefile.am b/Externals/libusb/libusb/Makefile.am index 0cab0a0919..b1b892d9c6 100644 --- a/Externals/libusb/libusb/Makefile.am +++ b/Externals/libusb/libusb/Makefile.am @@ -4,58 +4,71 @@ AUTOMAKE_OPTIONS = subdir-objects lib_LTLIBRARIES = libusb-1.0.la -POSIX_POLL_SRC = os/poll_posix.c -LINUX_USBFS_SRC = os/linux_usbfs.c -DARWIN_USB_SRC = os/darwin_usb.c +POSIX_POLL_SRC = os/poll_posix.h os/poll_posix.c +POSIX_THREADS_SRC = os/threads_posix.h os/threads_posix.c +WINDOWS_POLL_SRC = os/poll_windows.h os/poll_windows.c +WINDOWS_THREADS_SRC = os/threads_windows.h os/threads_windows.c +LINUX_USBFS_SRC = os/linux_usbfs.h os/linux_usbfs.c +DARWIN_USB_SRC = os/darwin_usb.h 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 -WINCE_USB_SRC = os/wince_usb.c os/wince_usb.h +SUNOS_USB_SRC = os/sunos_usb.c os/sunos_usb.h +WINDOWS_COMMON_SRC = os/windows_nt_common.h os/windows_nt_common.c \ + os/windows_common.h libusb-1.0.rc libusb-1.0.def +WINDOWS_USB_SRC = os/windows_winusb.h os/windows_winusb.c +WINDOWS_USBDK_SRC = os/windows_usbdk.h os/windows_usbdk.c +WINCE_USB_SRC = os/wince_usb.h os/wince_usb.c +HAIKU_USB_SRC = os/haiku_usb.h os/haiku_usb_backend.cpp \ + os/haiku_usb_raw.h os/haiku_usb_raw.cpp os/haiku_pollfs.cpp -DIST_SUBDIRS = - -EXTRA_DIST = $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) $(OPENBSD_USB_SRC) \ - $(NETBSD_USB_SRC) $(WINDOWS_USB_SRC) $(WINCE_USB_SRC) \ - $(POSIX_POLL_SRC) \ - os/threads_posix.c os/threads_windows.c \ +EXTRA_DIST = $(POSIX_POLL_SRC) $(POSIX_THREADS_SRC) \ + $(WINDOWS_POLL_SRC) $(WINDOWS_THREADS_SRC) \ + $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) \ + $(OPENBSD_USB_SRC) $(NETBSD_USB_SRC) \ + $(WINDOWS_COMMON_SRC) $(WINDOWS_USB_SRC) $(WINDOWS_USBDK_SRC) \ + $(WINCE_USB_SRC) $(HAIKU_USB_SRC) \ os/linux_udev.c os/linux_netlink.c -dist-hook: - cp -r os/haiku $(distdir)/os/haiku - rm -rf $(distdir)/os/haiku/autom4te.cache - if OS_LINUX if USE_UDEV -OS_SRC = $(LINUX_USBFS_SRC) $(POSIX_POLL_SRC) \ - os/linux_udev.c +OS_SRC = $(LINUX_USBFS_SRC) os/linux_udev.c else -OS_SRC = $(LINUX_USBFS_SRC) $(POSIX_POLL_SRC) \ - os/linux_netlink.c +OS_SRC = $(LINUX_USBFS_SRC) os/linux_netlink.c endif endif if OS_DARWIN -OS_SRC = $(DARWIN_USB_SRC) $(POSIX_POLL_SRC) +OS_SRC = $(DARWIN_USB_SRC) AM_CFLAGS_EXT = -no-cpp-precomp endif if OS_OPENBSD -OS_SRC = $(OPENBSD_USB_SRC) $(POSIX_POLL_SRC) +OS_SRC = $(OPENBSD_USB_SRC) endif if OS_NETBSD -OS_SRC = $(NETBSD_USB_SRC) $(POSIX_POLL_SRC) +OS_SRC = $(NETBSD_USB_SRC) +endif + +if OS_SUNOS +OS_SRC = $(SUNOS_USB_SRC) endif if OS_HAIKU -OS_SRC = $(POSIX_POLL_SRC) -SUBDIRS = os/haiku +noinst_LTLIBRARIES = libusb_haiku.la +libusb_haiku_la_SOURCES = $(HAIKU_USB_SRC) +libusb_1_0_la_LIBADD = libusb_haiku.la endif if OS_WINDOWS -OS_SRC = $(WINDOWS_USB_SRC) + +if USE_USBDK +OS_SRC = $(WINDOWS_USBDK_SRC) $(WINDOWS_COMMON_SRC) +else +OS_SRC = $(WINDOWS_USB_SRC) $(WINDOWS_COMMON_SRC) +endif .rc.lo: $(AM_V_GEN)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --tag=RC --mode=compile $(RC) $(RCFLAGS) -i $< -o $@ @@ -69,22 +82,23 @@ if CREATE_IMPORT_LIB $(AM_V_GEN)$(DLLTOOL) $(DLLTOOLFLAGS) --kill-at --input-def $(srcdir)/libusb-1.0.def --dllname $@ --output-lib .libs/$@.a endif -if THREADS_POSIX -THREADS_SRC = os/threads_posix.h os/threads_posix.c +if OS_WINDOWS +POLL_SRC = $(WINDOWS_POLL_SRC) else -THREADS_SRC = os/threads_windows.h os/threads_windows.c +POLL_SRC = $(POSIX_POLL_SRC) +endif + +if THREADS_POSIX +THREADS_SRC = $(POSIX_THREADS_SRC) +else +THREADS_SRC = $(WINDOWS_THREADS_SRC) endif 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/poll_posix.h os/poll_windows.h - -if OS_HAIKU -libusb_1_0_la_LIBADD = os/haiku/libhaikuusb.la -endif +libusb_1_0_la_SOURCES = libusbi.h libusb.h version.h version_nano.h \ + core.c descriptor.c hotplug.h hotplug.c io.c strerror.c sync.c \ + $(POLL_SRC) $(THREADS_SRC) $(OS_SRC) hdrdir = $(includedir)/libusb-1.0 hdr_HEADERS = libusb.h diff --git a/Externals/libusb/libusb/Makefile.in b/Externals/libusb/libusb/Makefile.in index 143c5c3f87..4d65495a95 100644 --- a/Externals/libusb/libusb/Makefile.in +++ b/Externals/libusb/libusb/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.15 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2014 Free Software Foundation, Inc. +# Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -16,17 +16,7 @@ VPATH = @srcdir@ -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -90,6 +80,8 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = libusb +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/depcomp $(hdr_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ @@ -97,7 +89,6 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/libusb/version.h $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(hdr_HEADERS) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -130,45 +121,53 @@ am__uninstall_files_from_dir = { \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(hdrdir)" -LTLIBRARIES = $(lib_LTLIBRARIES) -@OS_HAIKU_TRUE@libusb_1_0_la_DEPENDENCIES = os/haiku/libhaikuusb.la -am__libusb_1_0_la_SOURCES_DIST = 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 \ - os/threads_windows.h os/threads_windows.c os/threads_posix.h \ - os/threads_posix.c os/darwin_usb.c os/poll_posix.c \ +LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) +@OS_HAIKU_TRUE@libusb_1_0_la_DEPENDENCIES = libusb_haiku.la +am__libusb_1_0_la_SOURCES_DIST = libusbi.h libusb.h version.h \ + version_nano.h core.c descriptor.c hotplug.h hotplug.c io.c \ + strerror.c sync.c os/poll_posix.h os/poll_posix.c \ + os/poll_windows.h os/poll_windows.c os/threads_windows.h \ + os/threads_windows.c os/threads_posix.h os/threads_posix.c \ + os/darwin_usb.h os/darwin_usb.c os/linux_usbfs.h \ os/linux_usbfs.c os/linux_netlink.c os/linux_udev.c \ - os/netbsd_usb.c os/openbsd_usb.c os/poll_windows.c \ - os/windows_usb.c libusb-1.0.rc libusb-1.0.def os/poll_posix.h \ - os/poll_windows.h + os/netbsd_usb.c os/openbsd_usb.c os/sunos_usb.c os/sunos_usb.h \ + os/windows_winusb.h os/windows_winusb.c os/windows_nt_common.h \ + os/windows_nt_common.c os/windows_common.h libusb-1.0.rc \ + libusb-1.0.def os/windows_usbdk.h os/windows_usbdk.c am__dirstamp = $(am__leading_dot)dirstamp -@THREADS_POSIX_FALSE@am__objects_1 = \ -@THREADS_POSIX_FALSE@ os/libusb_1_0_la-threads_windows.lo -@THREADS_POSIX_TRUE@am__objects_1 = os/libusb_1_0_la-threads_posix.lo -am__objects_2 = os/libusb_1_0_la-darwin_usb.lo -am__objects_3 = os/libusb_1_0_la-poll_posix.lo -am__objects_4 = os/libusb_1_0_la-linux_usbfs.lo -am__objects_5 = os/libusb_1_0_la-netbsd_usb.lo -am__objects_6 = os/libusb_1_0_la-openbsd_usb.lo -am__objects_7 = os/libusb_1_0_la-poll_windows.lo \ - os/libusb_1_0_la-windows_usb.lo libusb-1.0.lo -@OS_DARWIN_FALSE@@OS_HAIKU_FALSE@@OS_LINUX_FALSE@@OS_NETBSD_FALSE@@OS_OPENBSD_FALSE@@OS_WINDOWS_TRUE@am__objects_8 = $(am__objects_7) -@OS_DARWIN_FALSE@@OS_HAIKU_FALSE@@OS_LINUX_FALSE@@OS_NETBSD_FALSE@@OS_OPENBSD_TRUE@am__objects_8 = $(am__objects_6) \ -@OS_DARWIN_FALSE@@OS_HAIKU_FALSE@@OS_LINUX_FALSE@@OS_NETBSD_FALSE@@OS_OPENBSD_TRUE@ $(am__objects_3) -@OS_DARWIN_FALSE@@OS_HAIKU_FALSE@@OS_LINUX_FALSE@@OS_NETBSD_TRUE@am__objects_8 = $(am__objects_5) \ -@OS_DARWIN_FALSE@@OS_HAIKU_FALSE@@OS_LINUX_FALSE@@OS_NETBSD_TRUE@ $(am__objects_3) -@OS_DARWIN_FALSE@@OS_HAIKU_FALSE@@OS_LINUX_TRUE@@USE_UDEV_FALSE@am__objects_8 = $(am__objects_4) \ -@OS_DARWIN_FALSE@@OS_HAIKU_FALSE@@OS_LINUX_TRUE@@USE_UDEV_FALSE@ $(am__objects_3) \ -@OS_DARWIN_FALSE@@OS_HAIKU_FALSE@@OS_LINUX_TRUE@@USE_UDEV_FALSE@ os/libusb_1_0_la-linux_netlink.lo -@OS_DARWIN_FALSE@@OS_HAIKU_FALSE@@OS_LINUX_TRUE@@USE_UDEV_TRUE@am__objects_8 = $(am__objects_4) \ -@OS_DARWIN_FALSE@@OS_HAIKU_FALSE@@OS_LINUX_TRUE@@USE_UDEV_TRUE@ $(am__objects_3) \ -@OS_DARWIN_FALSE@@OS_HAIKU_FALSE@@OS_LINUX_TRUE@@USE_UDEV_TRUE@ os/libusb_1_0_la-linux_udev.lo -@OS_DARWIN_FALSE@@OS_HAIKU_TRUE@am__objects_8 = $(am__objects_3) -@OS_DARWIN_TRUE@am__objects_8 = $(am__objects_2) $(am__objects_3) +am__objects_1 = os/libusb_1_0_la-poll_posix.lo +am__objects_2 = os/libusb_1_0_la-poll_windows.lo +@OS_WINDOWS_FALSE@am__objects_3 = $(am__objects_1) +@OS_WINDOWS_TRUE@am__objects_3 = $(am__objects_2) +am__objects_4 = os/libusb_1_0_la-threads_windows.lo +am__objects_5 = os/libusb_1_0_la-threads_posix.lo +@THREADS_POSIX_FALSE@am__objects_6 = $(am__objects_4) +@THREADS_POSIX_TRUE@am__objects_6 = $(am__objects_5) +am__objects_7 = os/libusb_1_0_la-darwin_usb.lo +am__objects_8 = os/libusb_1_0_la-linux_usbfs.lo +am__objects_9 = os/libusb_1_0_la-netbsd_usb.lo +am__objects_10 = os/libusb_1_0_la-openbsd_usb.lo +am__objects_11 = os/libusb_1_0_la-sunos_usb.lo +am__objects_12 = os/libusb_1_0_la-windows_winusb.lo +am__objects_13 = os/libusb_1_0_la-windows_nt_common.lo libusb-1.0.lo +am__objects_14 = os/libusb_1_0_la-windows_usbdk.lo +@OS_DARWIN_FALSE@@OS_LINUX_FALSE@@OS_NETBSD_FALSE@@OS_OPENBSD_FALSE@@OS_SUNOS_FALSE@@OS_WINDOWS_TRUE@@USE_USBDK_FALSE@am__objects_15 = $(am__objects_12) \ +@OS_DARWIN_FALSE@@OS_LINUX_FALSE@@OS_NETBSD_FALSE@@OS_OPENBSD_FALSE@@OS_SUNOS_FALSE@@OS_WINDOWS_TRUE@@USE_USBDK_FALSE@ $(am__objects_13) +@OS_DARWIN_FALSE@@OS_LINUX_FALSE@@OS_NETBSD_FALSE@@OS_OPENBSD_FALSE@@OS_SUNOS_FALSE@@OS_WINDOWS_TRUE@@USE_USBDK_TRUE@am__objects_15 = $(am__objects_14) \ +@OS_DARWIN_FALSE@@OS_LINUX_FALSE@@OS_NETBSD_FALSE@@OS_OPENBSD_FALSE@@OS_SUNOS_FALSE@@OS_WINDOWS_TRUE@@USE_USBDK_TRUE@ $(am__objects_13) +@OS_DARWIN_FALSE@@OS_LINUX_FALSE@@OS_NETBSD_FALSE@@OS_OPENBSD_FALSE@@OS_SUNOS_TRUE@am__objects_15 = $(am__objects_11) +@OS_DARWIN_FALSE@@OS_LINUX_FALSE@@OS_NETBSD_FALSE@@OS_OPENBSD_TRUE@am__objects_15 = $(am__objects_10) +@OS_DARWIN_FALSE@@OS_LINUX_FALSE@@OS_NETBSD_TRUE@am__objects_15 = $(am__objects_9) +@OS_DARWIN_FALSE@@OS_LINUX_TRUE@@USE_UDEV_FALSE@am__objects_15 = $(am__objects_8) \ +@OS_DARWIN_FALSE@@OS_LINUX_TRUE@@USE_UDEV_FALSE@ os/libusb_1_0_la-linux_netlink.lo +@OS_DARWIN_FALSE@@OS_LINUX_TRUE@@USE_UDEV_TRUE@am__objects_15 = $(am__objects_8) \ +@OS_DARWIN_FALSE@@OS_LINUX_TRUE@@USE_UDEV_TRUE@ os/libusb_1_0_la-linux_udev.lo +@OS_DARWIN_TRUE@am__objects_15 = $(am__objects_7) am_libusb_1_0_la_OBJECTS = libusb_1_0_la-core.lo \ - libusb_1_0_la-descriptor.lo libusb_1_0_la-io.lo \ - libusb_1_0_la-strerror.lo libusb_1_0_la-sync.lo \ - libusb_1_0_la-hotplug.lo $(am__objects_1) $(am__objects_8) + libusb_1_0_la-descriptor.lo libusb_1_0_la-hotplug.lo \ + libusb_1_0_la-io.lo libusb_1_0_la-strerror.lo \ + libusb_1_0_la-sync.lo $(am__objects_3) $(am__objects_6) \ + $(am__objects_15) libusb_1_0_la_OBJECTS = $(am_libusb_1_0_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -177,6 +176,15 @@ am__v_lt_1 = libusb_1_0_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libusb_1_0_la_CFLAGS) \ $(CFLAGS) $(libusb_1_0_la_LDFLAGS) $(LDFLAGS) -o $@ +libusb_haiku_la_LIBADD = +am__libusb_haiku_la_SOURCES_DIST = os/haiku_usb.h \ + os/haiku_usb_backend.cpp os/haiku_usb_raw.h \ + os/haiku_usb_raw.cpp os/haiku_pollfs.cpp +am__objects_16 = os/haiku_usb_backend.lo os/haiku_usb_raw.lo \ + os/haiku_pollfs.lo +@OS_HAIKU_TRUE@am_libusb_haiku_la_OBJECTS = $(am__objects_16) +libusb_haiku_la_OBJECTS = $(am_libusb_haiku_la_OBJECTS) +@OS_HAIKU_TRUE@am_libusb_haiku_la_rpath = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false @@ -211,30 +219,33 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = -SOURCES = $(libusb_1_0_la_SOURCES) -DIST_SOURCES = $(am__libusb_1_0_la_SOURCES_DIST) -RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ - ctags-recursive dvi-recursive html-recursive info-recursive \ - install-data-recursive install-dvi-recursive \ - install-exec-recursive install-html-recursive \ - install-info-recursive install-pdf-recursive \ - install-ps-recursive install-recursive installcheck-recursive \ - installdirs-recursive pdf-recursive ps-recursive \ - tags-recursive uninstall-recursive +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +SOURCES = $(libusb_1_0_la_SOURCES) $(libusb_haiku_la_SOURCES) +DIST_SOURCES = $(am__libusb_1_0_la_SOURCES_DIST) \ + $(am__libusb_haiku_la_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(hdr_HEADERS) -RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ - distclean-recursive maintainer-clean-recursive -am__recursive_targets = \ - $(RECURSIVE_TARGETS) \ - $(RECURSIVE_CLEAN_TARGETS) \ - $(am__extra_recursive_targets) -AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ - distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is @@ -254,33 +265,7 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags -am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -am__relativize = \ - dir0=`pwd`; \ - sed_first='s,^\([^/]*\)/.*$$,\1,'; \ - sed_rest='s,^[^/]*/*,,'; \ - sed_last='s,^.*/\([^/]*\)$$,\1,'; \ - sed_butlast='s,/*[^/]*$$,,'; \ - while test -n "$$dir1"; do \ - first=`echo "$$dir1" | sed -e "$$sed_first"`; \ - if test "$$first" != "."; then \ - if test "$$first" = ".."; then \ - dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ - dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ - else \ - first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ - if test "$$first2" = "$$first"; then \ - dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ - else \ - dir2="../$$dir2"; \ - fi; \ - dir0="$$dir0"/"$$first"; \ - fi; \ - fi; \ - dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ - done; \ - reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ @@ -295,6 +280,10 @@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ @@ -322,7 +311,6 @@ LIPO = @LIPO@ LN_S = @LN_S@ LTLDFLAGS = @LTLDFLAGS@ LTLIBOBJS = @LTLIBOBJS@ -MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ @@ -335,6 +323,7 @@ OS_HAIKU = @OS_HAIKU@ OS_LINUX = @OS_LINUX@ OS_NETBSD = @OS_NETBSD@ OS_OPENBSD = @OS_OPENBSD@ +OS_SUNOS = @OS_SUNOS@ OS_WINDOWS = @OS_WINDOWS@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ @@ -353,6 +342,7 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_UDEV = @USE_UDEV@ +USE_USBDK = @USE_USBDK@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ @@ -360,6 +350,7 @@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ @@ -401,7 +392,6 @@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ -subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ @@ -409,50 +399,61 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = subdir-objects lib_LTLIBRARIES = libusb-1.0.la -POSIX_POLL_SRC = os/poll_posix.c -LINUX_USBFS_SRC = os/linux_usbfs.c -DARWIN_USB_SRC = os/darwin_usb.c +POSIX_POLL_SRC = os/poll_posix.h os/poll_posix.c +POSIX_THREADS_SRC = os/threads_posix.h os/threads_posix.c +WINDOWS_POLL_SRC = os/poll_windows.h os/poll_windows.c +WINDOWS_THREADS_SRC = os/threads_windows.h os/threads_windows.c +LINUX_USBFS_SRC = os/linux_usbfs.h os/linux_usbfs.c +DARWIN_USB_SRC = os/darwin_usb.h 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 -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) \ - $(POSIX_POLL_SRC) \ - os/threads_posix.c os/threads_windows.c \ +SUNOS_USB_SRC = os/sunos_usb.c os/sunos_usb.h +WINDOWS_COMMON_SRC = os/windows_nt_common.h os/windows_nt_common.c \ + os/windows_common.h libusb-1.0.rc libusb-1.0.def + +WINDOWS_USB_SRC = os/windows_winusb.h os/windows_winusb.c +WINDOWS_USBDK_SRC = os/windows_usbdk.h os/windows_usbdk.c +WINCE_USB_SRC = os/wince_usb.h os/wince_usb.c +HAIKU_USB_SRC = os/haiku_usb.h os/haiku_usb_backend.cpp \ + os/haiku_usb_raw.h os/haiku_usb_raw.cpp os/haiku_pollfs.cpp + +EXTRA_DIST = $(POSIX_POLL_SRC) $(POSIX_THREADS_SRC) \ + $(WINDOWS_POLL_SRC) $(WINDOWS_THREADS_SRC) \ + $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) \ + $(OPENBSD_USB_SRC) $(NETBSD_USB_SRC) \ + $(WINDOWS_COMMON_SRC) $(WINDOWS_USB_SRC) $(WINDOWS_USBDK_SRC) \ + $(WINCE_USB_SRC) $(HAIKU_USB_SRC) \ os/linux_udev.c os/linux_netlink.c -@OS_DARWIN_TRUE@OS_SRC = $(DARWIN_USB_SRC) $(POSIX_POLL_SRC) -@OS_HAIKU_TRUE@OS_SRC = $(POSIX_POLL_SRC) -@OS_LINUX_TRUE@@USE_UDEV_FALSE@OS_SRC = $(LINUX_USBFS_SRC) $(POSIX_POLL_SRC) \ -@OS_LINUX_TRUE@@USE_UDEV_FALSE@ os/linux_netlink.c - -@OS_LINUX_TRUE@@USE_UDEV_TRUE@OS_SRC = $(LINUX_USBFS_SRC) $(POSIX_POLL_SRC) \ -@OS_LINUX_TRUE@@USE_UDEV_TRUE@ os/linux_udev.c - -@OS_NETBSD_TRUE@OS_SRC = $(NETBSD_USB_SRC) $(POSIX_POLL_SRC) -@OS_OPENBSD_TRUE@OS_SRC = $(OPENBSD_USB_SRC) $(POSIX_POLL_SRC) -@OS_WINDOWS_TRUE@OS_SRC = $(WINDOWS_USB_SRC) +@OS_DARWIN_TRUE@OS_SRC = $(DARWIN_USB_SRC) +@OS_LINUX_TRUE@@USE_UDEV_FALSE@OS_SRC = $(LINUX_USBFS_SRC) os/linux_netlink.c +@OS_LINUX_TRUE@@USE_UDEV_TRUE@OS_SRC = $(LINUX_USBFS_SRC) os/linux_udev.c +@OS_NETBSD_TRUE@OS_SRC = $(NETBSD_USB_SRC) +@OS_OPENBSD_TRUE@OS_SRC = $(OPENBSD_USB_SRC) +@OS_SUNOS_TRUE@OS_SRC = $(SUNOS_USB_SRC) +@OS_WINDOWS_TRUE@@USE_USBDK_FALSE@OS_SRC = $(WINDOWS_USB_SRC) $(WINDOWS_COMMON_SRC) +@OS_WINDOWS_TRUE@@USE_USBDK_TRUE@OS_SRC = $(WINDOWS_USBDK_SRC) $(WINDOWS_COMMON_SRC) @OS_DARWIN_TRUE@AM_CFLAGS_EXT = -no-cpp-precomp -@OS_HAIKU_TRUE@SUBDIRS = os/haiku -@THREADS_POSIX_FALSE@THREADS_SRC = os/threads_windows.h os/threads_windows.c -@THREADS_POSIX_TRUE@THREADS_SRC = os/threads_posix.h os/threads_posix.c +@OS_HAIKU_TRUE@noinst_LTLIBRARIES = libusb_haiku.la +@OS_HAIKU_TRUE@libusb_haiku_la_SOURCES = $(HAIKU_USB_SRC) +@OS_HAIKU_TRUE@libusb_1_0_la_LIBADD = libusb_haiku.la +@OS_WINDOWS_FALSE@POLL_SRC = $(POSIX_POLL_SRC) +@OS_WINDOWS_TRUE@POLL_SRC = $(WINDOWS_POLL_SRC) +@THREADS_POSIX_FALSE@THREADS_SRC = $(WINDOWS_THREADS_SRC) +@THREADS_POSIX_TRUE@THREADS_SRC = $(POSIX_THREADS_SRC) 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/poll_posix.h os/poll_windows.h +libusb_1_0_la_SOURCES = libusbi.h libusb.h version.h version_nano.h \ + core.c descriptor.c hotplug.h hotplug.c io.c strerror.c sync.c \ + $(POLL_SRC) $(THREADS_SRC) $(OS_SRC) -@OS_HAIKU_TRUE@libusb_1_0_la_LIBADD = os/haiku/libhaikuusb.la hdrdir = $(includedir)/libusb-1.0 hdr_HEADERS = libusb.h -all: all-recursive +all: all-am .SUFFIXES: -.SUFFIXES: .c .lo .o .obj .rc -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) +.SUFFIXES: .c .cpp .lo .o .obj .rc +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ @@ -464,6 +465,7 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libusb/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu libusb/Makefile +.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -476,9 +478,9 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) +$(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): @@ -516,20 +518,33 @@ clean-libLTLIBRARIES: echo rm -f $${locs}; \ rm -f $${locs}; \ } + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } os/$(am__dirstamp): @$(MKDIR_P) os @: > os/$(am__dirstamp) os/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) os/$(DEPDIR) @: > os/$(DEPDIR)/$(am__dirstamp) +os/libusb_1_0_la-poll_posix.lo: os/$(am__dirstamp) \ + os/$(DEPDIR)/$(am__dirstamp) +os/libusb_1_0_la-poll_windows.lo: os/$(am__dirstamp) \ + os/$(DEPDIR)/$(am__dirstamp) os/libusb_1_0_la-threads_windows.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libusb_1_0_la-threads_posix.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libusb_1_0_la-darwin_usb.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) -os/libusb_1_0_la-poll_posix.lo: os/$(am__dirstamp) \ - os/$(DEPDIR)/$(am__dirstamp) os/libusb_1_0_la-linux_usbfs.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libusb_1_0_la-linux_netlink.lo: os/$(am__dirstamp) \ @@ -540,13 +555,24 @@ os/libusb_1_0_la-netbsd_usb.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) os/libusb_1_0_la-openbsd_usb.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) -os/libusb_1_0_la-poll_windows.lo: os/$(am__dirstamp) \ +os/libusb_1_0_la-sunos_usb.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) -os/libusb_1_0_la-windows_usb.lo: os/$(am__dirstamp) \ +os/libusb_1_0_la-windows_winusb.lo: os/$(am__dirstamp) \ + os/$(DEPDIR)/$(am__dirstamp) +os/libusb_1_0_la-windows_nt_common.lo: os/$(am__dirstamp) \ + os/$(DEPDIR)/$(am__dirstamp) +os/libusb_1_0_la-windows_usbdk.lo: os/$(am__dirstamp) \ os/$(DEPDIR)/$(am__dirstamp) libusb-1.0.la: $(libusb_1_0_la_OBJECTS) $(libusb_1_0_la_DEPENDENCIES) $(EXTRA_libusb_1_0_la_DEPENDENCIES) $(AM_V_CCLD)$(libusb_1_0_la_LINK) -rpath $(libdir) $(libusb_1_0_la_OBJECTS) $(libusb_1_0_la_LIBADD) $(LIBS) +os/haiku_usb_backend.lo: os/$(am__dirstamp) \ + os/$(DEPDIR)/$(am__dirstamp) +os/haiku_usb_raw.lo: os/$(am__dirstamp) os/$(DEPDIR)/$(am__dirstamp) +os/haiku_pollfs.lo: os/$(am__dirstamp) os/$(DEPDIR)/$(am__dirstamp) + +libusb_haiku.la: $(libusb_haiku_la_OBJECTS) $(libusb_haiku_la_DEPENDENCIES) $(EXTRA_libusb_haiku_la_DEPENDENCIES) + $(AM_V_CXXLD)$(CXXLINK) $(am_libusb_haiku_la_rpath) $(libusb_haiku_la_OBJECTS) $(libusb_haiku_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -562,6 +588,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-io.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-strerror.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-sync.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/haiku_pollfs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/haiku_usb_backend.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/haiku_usb_raw.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libusb_1_0_la-darwin_usb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libusb_1_0_la-linux_netlink.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libusb_1_0_la-linux_udev.Plo@am__quote@ @@ -570,9 +599,12 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libusb_1_0_la-openbsd_usb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libusb_1_0_la-poll_posix.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libusb_1_0_la-poll_windows.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libusb_1_0_la-sunos_usb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libusb_1_0_la-threads_posix.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libusb_1_0_la-threads_windows.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libusb_1_0_la-windows_usb.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libusb_1_0_la-windows_nt_common.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libusb_1_0_la-windows_usbdk.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@os/$(DEPDIR)/libusb_1_0_la-windows_winusb.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @@ -612,6 +644,13 @@ libusb_1_0_la-descriptor.lo: descriptor.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-descriptor.lo `test -f 'descriptor.c' || echo '$(srcdir)/'`descriptor.c +libusb_1_0_la-hotplug.lo: hotplug.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-hotplug.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-hotplug.Tpo -c -o libusb_1_0_la-hotplug.lo `test -f 'hotplug.c' || echo '$(srcdir)/'`hotplug.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-hotplug.Tpo $(DEPDIR)/libusb_1_0_la-hotplug.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hotplug.c' object='libusb_1_0_la-hotplug.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-hotplug.lo `test -f 'hotplug.c' || echo '$(srcdir)/'`hotplug.c + libusb_1_0_la-io.lo: io.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-io.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-io.Tpo -c -o libusb_1_0_la-io.lo `test -f 'io.c' || echo '$(srcdir)/'`io.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-io.Tpo $(DEPDIR)/libusb_1_0_la-io.Plo @@ -633,12 +672,19 @@ libusb_1_0_la-sync.lo: sync.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-sync.lo `test -f 'sync.c' || echo '$(srcdir)/'`sync.c -libusb_1_0_la-hotplug.lo: hotplug.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-hotplug.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-hotplug.Tpo -c -o libusb_1_0_la-hotplug.lo `test -f 'hotplug.c' || echo '$(srcdir)/'`hotplug.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-hotplug.Tpo $(DEPDIR)/libusb_1_0_la-hotplug.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hotplug.c' object='libusb_1_0_la-hotplug.lo' libtool=yes @AMDEPBACKSLASH@ +os/libusb_1_0_la-poll_posix.lo: os/poll_posix.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT os/libusb_1_0_la-poll_posix.lo -MD -MP -MF os/$(DEPDIR)/libusb_1_0_la-poll_posix.Tpo -c -o os/libusb_1_0_la-poll_posix.lo `test -f 'os/poll_posix.c' || echo '$(srcdir)/'`os/poll_posix.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libusb_1_0_la-poll_posix.Tpo os/$(DEPDIR)/libusb_1_0_la-poll_posix.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/poll_posix.c' object='os/libusb_1_0_la-poll_posix.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-hotplug.lo `test -f 'hotplug.c' || echo '$(srcdir)/'`hotplug.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o os/libusb_1_0_la-poll_posix.lo `test -f 'os/poll_posix.c' || echo '$(srcdir)/'`os/poll_posix.c + +os/libusb_1_0_la-poll_windows.lo: os/poll_windows.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT os/libusb_1_0_la-poll_windows.lo -MD -MP -MF os/$(DEPDIR)/libusb_1_0_la-poll_windows.Tpo -c -o os/libusb_1_0_la-poll_windows.lo `test -f 'os/poll_windows.c' || echo '$(srcdir)/'`os/poll_windows.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libusb_1_0_la-poll_windows.Tpo os/$(DEPDIR)/libusb_1_0_la-poll_windows.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/poll_windows.c' object='os/libusb_1_0_la-poll_windows.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o os/libusb_1_0_la-poll_windows.lo `test -f 'os/poll_windows.c' || echo '$(srcdir)/'`os/poll_windows.c os/libusb_1_0_la-threads_windows.lo: os/threads_windows.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT os/libusb_1_0_la-threads_windows.lo -MD -MP -MF os/$(DEPDIR)/libusb_1_0_la-threads_windows.Tpo -c -o os/libusb_1_0_la-threads_windows.lo `test -f 'os/threads_windows.c' || echo '$(srcdir)/'`os/threads_windows.c @@ -661,13 +707,6 @@ os/libusb_1_0_la-darwin_usb.lo: os/darwin_usb.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o os/libusb_1_0_la-darwin_usb.lo `test -f 'os/darwin_usb.c' || echo '$(srcdir)/'`os/darwin_usb.c -os/libusb_1_0_la-poll_posix.lo: os/poll_posix.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT os/libusb_1_0_la-poll_posix.lo -MD -MP -MF os/$(DEPDIR)/libusb_1_0_la-poll_posix.Tpo -c -o os/libusb_1_0_la-poll_posix.lo `test -f 'os/poll_posix.c' || echo '$(srcdir)/'`os/poll_posix.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libusb_1_0_la-poll_posix.Tpo os/$(DEPDIR)/libusb_1_0_la-poll_posix.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/poll_posix.c' object='os/libusb_1_0_la-poll_posix.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o os/libusb_1_0_la-poll_posix.lo `test -f 'os/poll_posix.c' || echo '$(srcdir)/'`os/poll_posix.c - os/libusb_1_0_la-linux_usbfs.lo: os/linux_usbfs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT os/libusb_1_0_la-linux_usbfs.lo -MD -MP -MF os/$(DEPDIR)/libusb_1_0_la-linux_usbfs.Tpo -c -o os/libusb_1_0_la-linux_usbfs.lo `test -f 'os/linux_usbfs.c' || echo '$(srcdir)/'`os/linux_usbfs.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libusb_1_0_la-linux_usbfs.Tpo os/$(DEPDIR)/libusb_1_0_la-linux_usbfs.Plo @@ -703,19 +742,57 @@ os/libusb_1_0_la-openbsd_usb.lo: os/openbsd_usb.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o os/libusb_1_0_la-openbsd_usb.lo `test -f 'os/openbsd_usb.c' || echo '$(srcdir)/'`os/openbsd_usb.c -os/libusb_1_0_la-poll_windows.lo: os/poll_windows.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT os/libusb_1_0_la-poll_windows.lo -MD -MP -MF os/$(DEPDIR)/libusb_1_0_la-poll_windows.Tpo -c -o os/libusb_1_0_la-poll_windows.lo `test -f 'os/poll_windows.c' || echo '$(srcdir)/'`os/poll_windows.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libusb_1_0_la-poll_windows.Tpo os/$(DEPDIR)/libusb_1_0_la-poll_windows.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/poll_windows.c' object='os/libusb_1_0_la-poll_windows.lo' libtool=yes @AMDEPBACKSLASH@ +os/libusb_1_0_la-sunos_usb.lo: os/sunos_usb.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT os/libusb_1_0_la-sunos_usb.lo -MD -MP -MF os/$(DEPDIR)/libusb_1_0_la-sunos_usb.Tpo -c -o os/libusb_1_0_la-sunos_usb.lo `test -f 'os/sunos_usb.c' || echo '$(srcdir)/'`os/sunos_usb.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libusb_1_0_la-sunos_usb.Tpo os/$(DEPDIR)/libusb_1_0_la-sunos_usb.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/sunos_usb.c' object='os/libusb_1_0_la-sunos_usb.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o os/libusb_1_0_la-poll_windows.lo `test -f 'os/poll_windows.c' || echo '$(srcdir)/'`os/poll_windows.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o os/libusb_1_0_la-sunos_usb.lo `test -f 'os/sunos_usb.c' || echo '$(srcdir)/'`os/sunos_usb.c -os/libusb_1_0_la-windows_usb.lo: os/windows_usb.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT os/libusb_1_0_la-windows_usb.lo -MD -MP -MF os/$(DEPDIR)/libusb_1_0_la-windows_usb.Tpo -c -o os/libusb_1_0_la-windows_usb.lo `test -f 'os/windows_usb.c' || echo '$(srcdir)/'`os/windows_usb.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libusb_1_0_la-windows_usb.Tpo os/$(DEPDIR)/libusb_1_0_la-windows_usb.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/windows_usb.c' object='os/libusb_1_0_la-windows_usb.lo' libtool=yes @AMDEPBACKSLASH@ +os/libusb_1_0_la-windows_winusb.lo: os/windows_winusb.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT os/libusb_1_0_la-windows_winusb.lo -MD -MP -MF os/$(DEPDIR)/libusb_1_0_la-windows_winusb.Tpo -c -o os/libusb_1_0_la-windows_winusb.lo `test -f 'os/windows_winusb.c' || echo '$(srcdir)/'`os/windows_winusb.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libusb_1_0_la-windows_winusb.Tpo os/$(DEPDIR)/libusb_1_0_la-windows_winusb.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/windows_winusb.c' object='os/libusb_1_0_la-windows_winusb.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o os/libusb_1_0_la-windows_usb.lo `test -f 'os/windows_usb.c' || echo '$(srcdir)/'`os/windows_usb.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o os/libusb_1_0_la-windows_winusb.lo `test -f 'os/windows_winusb.c' || echo '$(srcdir)/'`os/windows_winusb.c + +os/libusb_1_0_la-windows_nt_common.lo: os/windows_nt_common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT os/libusb_1_0_la-windows_nt_common.lo -MD -MP -MF os/$(DEPDIR)/libusb_1_0_la-windows_nt_common.Tpo -c -o os/libusb_1_0_la-windows_nt_common.lo `test -f 'os/windows_nt_common.c' || echo '$(srcdir)/'`os/windows_nt_common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libusb_1_0_la-windows_nt_common.Tpo os/$(DEPDIR)/libusb_1_0_la-windows_nt_common.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/windows_nt_common.c' object='os/libusb_1_0_la-windows_nt_common.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o os/libusb_1_0_la-windows_nt_common.lo `test -f 'os/windows_nt_common.c' || echo '$(srcdir)/'`os/windows_nt_common.c + +os/libusb_1_0_la-windows_usbdk.lo: os/windows_usbdk.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT os/libusb_1_0_la-windows_usbdk.lo -MD -MP -MF os/$(DEPDIR)/libusb_1_0_la-windows_usbdk.Tpo -c -o os/libusb_1_0_la-windows_usbdk.lo `test -f 'os/windows_usbdk.c' || echo '$(srcdir)/'`os/windows_usbdk.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) os/$(DEPDIR)/libusb_1_0_la-windows_usbdk.Tpo os/$(DEPDIR)/libusb_1_0_la-windows_usbdk.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/windows_usbdk.c' object='os/libusb_1_0_la-windows_usbdk.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o os/libusb_1_0_la-windows_usbdk.lo `test -f 'os/windows_usbdk.c' || echo '$(srcdir)/'`os/windows_usbdk.c + +.cpp.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo @@ -745,61 +822,14 @@ uninstall-hdrHEADERS: files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(hdrdir)'; $(am__uninstall_files_from_dir) -# This directory's subdirectories are mostly independent; you can cd -# into them and run 'make' without going through this Makefile. -# To change the values of 'make' variables: instead of editing Makefiles, -# (1) if the variable is set in 'config.status', edit 'config.status' -# (which will cause the Makefiles to be regenerated when you run 'make'); -# (2) otherwise, pass the desired values on the 'make' command line. -$(am__recursive_targets): - @fail=; \ - if $(am__make_keepgoing); then \ - failcom='fail=yes'; \ - else \ - failcom='exit 1'; \ - fi; \ - dot_seen=no; \ - target=`echo $@ | sed s/-recursive//`; \ - case "$@" in \ - distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ - *) list='$(SUBDIRS)' ;; \ - esac; \ - for subdir in $$list; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - dot_seen=yes; \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done; \ - if test "$$dot_seen" = "no"; then \ - $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ - fi; test -z "$$fail" - ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-recursive +tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ - if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ - include_option=--etags-include; \ - empty_fix=.; \ - else \ - include_option=--include; \ - empty_fix=; \ - fi; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test ! -f $$subdir/TAGS || \ - set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ - fi; \ - done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ @@ -812,7 +842,7 @@ tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $$unique; \ fi; \ fi -ctags: ctags-recursive +ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) @@ -825,7 +855,7 @@ GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-recursive +cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ @@ -874,51 +904,22 @@ distdir: $(DISTFILES) || exit 1; \ fi; \ done - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - $(am__make_dryrun) \ - || test -d "$(distdir)/$$subdir" \ - || $(MKDIR_P) "$(distdir)/$$subdir" \ - || exit 1; \ - dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ - $(am__relativize); \ - new_distdir=$$reldir; \ - dir1=$$subdir; dir2="$(top_distdir)"; \ - $(am__relativize); \ - new_top_distdir=$$reldir; \ - echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ - echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ - ($(am__cd) $$subdir && \ - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$$new_top_distdir" \ - distdir="$$new_distdir" \ - am__remove_distdir=: \ - am__skip_length_check=: \ - am__skip_mode_fix=: \ - distdir) \ - || exit 1; \ - fi; \ - done - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$(top_distdir)" distdir="$(distdir)" \ - dist-hook check-am: all-am -check: check-recursive +check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) -installdirs: installdirs-recursive -installdirs-am: +installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(hdrdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done -install: install-recursive -install-exec: install-exec-recursive -install-data: install-data-recursive -uninstall: uninstall-recursive +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am -installcheck: installcheck-recursive +installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ @@ -942,103 +943,97 @@ distclean-generic: maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -clean: clean-recursive +clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ - mostlyclean-am + clean-noinstLTLIBRARIES mostlyclean-am -distclean: distclean-recursive +distclean: distclean-am -rm -rf ./$(DEPDIR) os/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags -dvi: dvi-recursive +dvi: dvi-am dvi-am: -html: html-recursive +html: html-am html-am: -info: info-recursive +info: info-am info-am: install-data-am: install-hdrHEADERS -install-dvi: install-dvi-recursive +install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES -install-html: install-html-recursive +install-html: install-html-am install-html-am: -install-info: install-info-recursive +install-info: install-info-am install-info-am: install-man: -install-pdf: install-pdf-recursive +install-pdf: install-pdf-am install-pdf-am: -install-ps: install-ps-recursive +install-ps: install-ps-am install-ps-am: installcheck-am: -maintainer-clean: maintainer-clean-recursive +maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) os/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic -mostlyclean: mostlyclean-recursive +mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool -pdf: pdf-recursive +pdf: pdf-am pdf-am: -ps: ps-recursive +ps: ps-am ps-am: uninstall-am: uninstall-hdrHEADERS uninstall-libLTLIBRARIES -.MAKE: $(am__recursive_targets) install-am install-strip +.MAKE: install-am install-strip -.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ - check-am clean clean-generic clean-libLTLIBRARIES \ - clean-libtool cscopelist-am ctags ctags-am dist-hook distclean \ - distclean-compile distclean-generic distclean-libtool \ - distclean-tags distdir dvi dvi-am html html-am info info-am \ - install install-am install-data install-data-am install-dvi \ - install-dvi-am install-exec install-exec-am install-hdrHEADERS \ - install-html install-html-am install-info install-info-am \ +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-noinstLTLIBRARIES \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-hdrHEADERS install-html \ + install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ - installcheck-am installdirs installdirs-am maintainer-clean \ + installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-hdrHEADERS \ uninstall-libLTLIBRARIES -.PRECIOUS: Makefile - all: libusb-1.0.la libusb-1.0.dll -dist-hook: - cp -r os/haiku $(distdir)/os/haiku - rm -rf $(distdir)/os/haiku/autom4te.cache - @OS_WINDOWS_TRUE@.rc.lo: @OS_WINDOWS_TRUE@ $(AM_V_GEN)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --tag=RC --mode=compile $(RC) $(RCFLAGS) -i $< -o $@ diff --git a/Externals/libusb/libusb/core.c b/Externals/libusb/libusb/core.c index 5884dcfb1a..99aab7bb03 100644 --- a/Externals/libusb/libusb/core.c +++ b/Externals/libusb/libusb/core.c @@ -53,11 +53,19 @@ 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) const struct usbi_os_backend * const usbi_backend = &haiku_usb_raw_backend; +#elif defined (OS_SUNOS) +const struct usbi_os_backend * const usbi_backend = &sunos_backend; #else #error "Unsupported OS" #endif @@ -96,7 +104,7 @@ struct list_head active_contexts_list; * * \section API Application Programming Interface (API) * - * See the \ref api page for a complete list of the libusb functions. + * See the \ref libusb_api page for a complete list of the libusb functions. * * \section features Library features * @@ -108,7 +116,7 @@ struct list_head active_contexts_list; * usually won't need to thread) * - Lightweight with lean API * - Compatible with libusb-0.1 through the libusb-compat-0.1 translation layer - * - Hotplug support (on some platforms). See \ref hotplug. + * - Hotplug support (on some platforms). See \ref libusb_hotplug. * * \section gettingstarted Getting Started * @@ -116,7 +124,7 @@ struct list_head active_contexts_list; * links to the different categories of libusb's functionality. * * One decision you will have to make is whether to use the synchronous - * or the asynchronous data transfer interface. The \ref io documentation + * or the asynchronous data transfer interface. The \ref libusb_io documentation * provides some insight into this topic. * * Some example programs can be found in the libusb source distribution under @@ -127,7 +135,7 @@ struct list_head active_contexts_list; * * libusb functions typically return 0 on success or a negative error code * on failure. These negative error codes relate to LIBUSB_ERROR constants - * which are listed on the \ref misc "miscellaneous" documentation page. + * which are listed on the \ref libusb_misc "miscellaneous" documentation page. * * \section msglog Debug message logging * @@ -137,7 +145,7 @@ struct list_head active_contexts_list; * libusb_set_debug(), or the setting of the environmental variable * LIBUSB_DEBUG outside of the application, can result in logging being * produced. Your application should therefore not close stderr, but instead - * direct it to the null device if its output is undesireable. + * direct it to the null device if its output is undesirable. * * The libusb_set_debug() function can be used to enable logging of certain * messages. Under standard configuration, libusb doesn't really log much @@ -172,12 +180,12 @@ struct list_head active_contexts_list; * * \section remarks Other remarks * - * libusb does have imperfections. The \ref caveats "caveats" page attempts + * libusb does have imperfections. The \ref libusb_caveats "caveats" page attempts * to document these. */ /** - * \page caveats Caveats + * \page libusb_caveats Caveats * * \section devresets Device resets * @@ -293,7 +301,7 @@ if (cfg != desired) */ /** - * \page contexts Contexts + * \page libusb_contexts Contexts * * It is possible that libusb may be used simultaneously from two independent * libraries linked into the same executable. For example, if your application @@ -332,7 +340,7 @@ if (cfg != desired) */ /** - * \page api Application Programming Interface + * \page libusb_api Application Programming Interface * * This is the complete list of libusb functions, structures and * enumerations in alphabetical order. @@ -351,6 +359,8 @@ if (cfg != desired) * - libusb_control_transfer_get_setup() * - libusb_cpu_to_le16() * - libusb_detach_kernel_driver() + * - libusb_dev_mem_alloc() + * - libusb_dev_mem_free() * - libusb_error_name() * - libusb_event_handler_active() * - libusb_event_handling_ok() @@ -365,6 +375,7 @@ if (cfg != desired) * - libusb_free_config_descriptor() * - libusb_free_container_id_descriptor() * - libusb_free_device_list() + * - libusb_free_pollfds() * - libusb_free_ss_endpoint_companion_descriptor() * - libusb_free_ss_usb_device_capability_descriptor() * - libusb_free_streams() @@ -389,8 +400,10 @@ if (cfg != desired) * - libusb_get_max_packet_size() * - libusb_get_next_timeout() * - libusb_get_parent() + * - libusb_get_pollfds() * - libusb_get_port_number() * - libusb_get_port_numbers() + * - libusb_get_port_path() * - libusb_get_ss_endpoint_companion_descriptor() * - libusb_get_ss_usb_device_capability_descriptor() * - libusb_get_string_descriptor() @@ -406,6 +419,7 @@ if (cfg != desired) * - libusb_hotplug_deregister_callback() * - libusb_hotplug_register_callback() * - libusb_init() + * - libusb_interrupt_event_handler() * - libusb_interrupt_transfer() * - libusb_kernel_driver_active() * - libusb_lock_events() @@ -477,14 +491,14 @@ if (cfg != desired) */ /** - * @defgroup lib Library initialization/deinitialization + * @defgroup libusb_lib Library initialization/deinitialization * This page details how to initialize and deinitialize libusb. Initialization * must be performed before using any libusb functionality, and similarly you * must not call any libusb functions after deinitialization. */ /** - * @defgroup dev Device handling and enumeration + * @defgroup libusb_dev Device handling and enumeration * The functionality documented below is designed to help with the following * operations: * - Enumerating the USB devices currently attached to the system @@ -594,7 +608,7 @@ libusb_free_device_list(list, 1); * libusb_close(). */ -/** @defgroup misc Miscellaneous */ +/** @defgroup libusb_misc Miscellaneous */ /* we traverse usbfs without knowing how many devices we are going to find. * so we create this discovered_devs model which is similar to a linked-list @@ -615,6 +629,16 @@ static struct discovered_devs *discovered_devs_alloc(void) return ret; } +static void discovered_devs_free(struct discovered_devs *discdevs) +{ + size_t i; + + for (i = 0; i < discdevs->len; i++) + libusb_unref_device(discdevs->devices[i]); + + free(discdevs); +} + /* append a device to the discovered devices collection. may realloc itself, * returning new discdevs. returns NULL on realloc failure. */ struct discovered_devs *discovered_devs_append( @@ -622,6 +646,7 @@ struct discovered_devs *discovered_devs_append( { size_t len = discdevs->len; size_t capacity; + struct discovered_devs *new_discdevs; /* if there is space, just append the device */ if (len < discdevs->capacity) { @@ -633,27 +658,23 @@ struct discovered_devs *discovered_devs_append( /* exceeded capacity, need to grow */ usbi_dbg("need to increase capacity"); capacity = discdevs->capacity + DISCOVERED_DEVICES_SIZE_STEP; - discdevs = usbi_reallocf(discdevs, + /* can't use usbi_reallocf here because in failure cases it would + * free the existing discdevs without unreferencing its devices. */ + new_discdevs = realloc(discdevs, sizeof(*discdevs) + (sizeof(void *) * capacity)); - if (discdevs) { - discdevs->capacity = capacity; - discdevs->devices[len] = libusb_ref_device(dev); - discdevs->len++; + if (!new_discdevs) { + discovered_devs_free(discdevs); + return NULL; } + discdevs = new_discdevs; + discdevs->capacity = capacity; + discdevs->devices[len] = libusb_ref_device(dev); + discdevs->len++; + return discdevs; } -static void discovered_devs_free(struct discovered_devs *discdevs) -{ - size_t i; - - for (i = 0; i < discdevs->len; i++) - libusb_unref_device(discdevs->devices[i]); - - free(discdevs); -} - /* Allocate a new device with a specific session ID. The returned device has * a reference count of 1. */ struct libusb_device *usbi_alloc_device(struct libusb_context *ctx, @@ -666,7 +687,7 @@ struct libusb_device *usbi_alloc_device(struct libusb_context *ctx, if (!dev) return NULL; - r = usbi_mutex_init(&dev->lock, NULL); + r = usbi_mutex_init(&dev->lock); if (r) { free(dev); return NULL; @@ -766,7 +787,7 @@ struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx, return ret; } -/** @ingroup dev +/** @ingroup libusb_dev * Returns a list of USB devices currently attached to the system. This is * your entry point into finding a USB device to operate. * @@ -842,11 +863,12 @@ ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx, *list = ret; out: - discovered_devs_free(discdevs); + if (discdevs) + discovered_devs_free(discdevs); return len; } -/** \ingroup dev +/** \ingroup libusb_dev * Frees a list of devices previously discovered using * libusb_get_device_list(). If the unref_devices parameter is set, the * reference count of each device in the list is decremented by 1. @@ -869,7 +891,7 @@ void API_EXPORTED libusb_free_device_list(libusb_device **list, free(list); } -/** \ingroup dev +/** \ingroup libusb_dev * Get the number of the bus that a device is connected to. * \param dev a device * \returns the bus number @@ -879,7 +901,7 @@ uint8_t API_EXPORTED libusb_get_bus_number(libusb_device *dev) return dev->bus_number; } -/** \ingroup dev +/** \ingroup libusb_dev * Get the number of the port that a device is connected to. * Unless the OS does something funky, or you are hot-plugging USB extension cards, * the port number returned by this call is usually guaranteed to be uniquely tied @@ -898,7 +920,7 @@ uint8_t API_EXPORTED libusb_get_port_number(libusb_device *dev) return dev->port_number; } -/** \ingroup dev +/** \ingroup libusb_dev * Get the list of all port numbers from root for the specified device * * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 @@ -932,7 +954,7 @@ int API_EXPORTED libusb_get_port_numbers(libusb_device *dev, return port_numbers_len - i; } -/** \ingroup dev +/** \ingroup libusb_dev * Deprecated please use libusb_get_port_numbers instead. */ int API_EXPORTED libusb_get_port_path(libusb_context *ctx, libusb_device *dev, @@ -943,7 +965,7 @@ int API_EXPORTED libusb_get_port_path(libusb_context *ctx, libusb_device *dev, return libusb_get_port_numbers(dev, port_numbers, port_numbers_len); } -/** \ingroup dev +/** \ingroup libusb_dev * Get the the parent from the specified device. * \param dev a device * \returns the device parent or NULL if not available @@ -960,7 +982,7 @@ libusb_device * LIBUSB_CALL libusb_get_parent(libusb_device *dev) return dev->parent_dev; } -/** \ingroup dev +/** \ingroup libusb_dev * Get the address of the device on the bus it is connected to. * \param dev a device * \returns the device address @@ -970,7 +992,7 @@ uint8_t API_EXPORTED libusb_get_device_address(libusb_device *dev) return dev->device_address; } -/** \ingroup dev +/** \ingroup libusb_dev * Get the negotiated connection speed for a device. * \param dev a device * \returns a \ref libusb_speed code, where LIBUSB_SPEED_UNKNOWN means that @@ -1006,7 +1028,7 @@ static const struct libusb_endpoint_descriptor *find_endpoint( return NULL; } -/** \ingroup dev +/** \ingroup libusb_dev * Convenience function to retrieve the wMaxPacketSize value for a particular * endpoint in the active device configuration. * @@ -1049,7 +1071,7 @@ out: return r; } -/** \ingroup dev +/** \ingroup libusb_dev * Calculate the maximum packet size which a specific endpoint is capable is * sending or receiving in the duration of 1 microframe * @@ -1110,7 +1132,7 @@ out: return r; } -/** \ingroup dev +/** \ingroup libusb_dev * Increment the reference count of a device. * \param dev the device to reference * \returns the same device @@ -1124,7 +1146,7 @@ libusb_device * LIBUSB_CALL libusb_ref_device(libusb_device *dev) return dev; } -/** \ingroup dev +/** \ingroup libusb_dev * Decrement the reference count of a device. If the decrement operation * causes the reference count to reach zero, the device shall be destroyed. * \param dev the device to unreference @@ -1196,7 +1218,7 @@ int usbi_clear_event(struct libusb_context *ctx) return 0; } -/** \ingroup dev +/** \ingroup libusb_dev * Open a device and obtain a device handle. A handle allows you to perform * I/O on the device in question. * @@ -1207,7 +1229,7 @@ int usbi_clear_event(struct libusb_context *ctx) * This is a non-blocking function; no requests are sent over the bus. * * \param dev the device to open - * \param handle output location for the returned device handle pointer. Only + * \param dev_handle output location for the returned device handle pointer. Only * populated when the return code is 0. * \returns 0 on success * \returns LIBUSB_ERROR_NO_MEM on memory allocation failure @@ -1216,10 +1238,10 @@ int usbi_clear_event(struct libusb_context *ctx) * \returns another LIBUSB_ERROR code on other failure */ int API_EXPORTED libusb_open(libusb_device *dev, - libusb_device_handle **handle) + libusb_device_handle **dev_handle) { struct libusb_context *ctx = DEVICE_CTX(dev); - struct libusb_device_handle *_handle; + struct libusb_device_handle *_dev_handle; size_t priv_size = usbi_backend->device_handle_priv_size; int r; usbi_dbg("open %d.%d", dev->bus_number, dev->device_address); @@ -1228,39 +1250,39 @@ int API_EXPORTED libusb_open(libusb_device *dev, return LIBUSB_ERROR_NO_DEVICE; } - _handle = malloc(sizeof(*_handle) + priv_size); - if (!_handle) + _dev_handle = malloc(sizeof(*_dev_handle) + priv_size); + if (!_dev_handle) return LIBUSB_ERROR_NO_MEM; - r = usbi_mutex_init(&_handle->lock, NULL); + r = usbi_mutex_init(&_dev_handle->lock); if (r) { - free(_handle); + free(_dev_handle); return LIBUSB_ERROR_OTHER; } - _handle->dev = libusb_ref_device(dev); - _handle->auto_detach_kernel_driver = 0; - _handle->claimed_interfaces = 0; - memset(&_handle->os_priv, 0, priv_size); + _dev_handle->dev = libusb_ref_device(dev); + _dev_handle->auto_detach_kernel_driver = 0; + _dev_handle->claimed_interfaces = 0; + memset(&_dev_handle->os_priv, 0, priv_size); - r = usbi_backend->open(_handle); + r = usbi_backend->open(_dev_handle); if (r < 0) { usbi_dbg("open %d.%d returns %d", dev->bus_number, dev->device_address, r); libusb_unref_device(dev); - usbi_mutex_destroy(&_handle->lock); - free(_handle); + usbi_mutex_destroy(&_dev_handle->lock); + free(_dev_handle); return r; } usbi_mutex_lock(&ctx->open_devs_lock); - list_add(&_handle->list, &ctx->open_devs); + list_add(&_dev_handle->list, &ctx->open_devs); usbi_mutex_unlock(&ctx->open_devs_lock); - *handle = _handle; + *dev_handle = _dev_handle; return 0; } -/** \ingroup dev +/** \ingroup libusb_dev * Convenience function for finding a device with a particular * idVendor/idProduct combination. This function is intended * for those scenarios where you are using libusb to knock up a quick test @@ -1274,8 +1296,8 @@ int API_EXPORTED libusb_open(libusb_device *dev, * \param ctx the context to operate on, or NULL for the default context * \param vendor_id the idVendor value to search for * \param product_id the idProduct value to search for - * \returns a handle for the first found device, or NULL on error or if the - * device could not be found. */ + * \returns a device handle for the first found device, or NULL on error + * or if the device could not be found. */ DEFAULT_VISIBILITY libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid( libusb_context *ctx, uint16_t vendor_id, uint16_t product_id) @@ -1283,7 +1305,7 @@ libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid( struct libusb_device **devs; struct libusb_device *found = NULL; struct libusb_device *dev; - struct libusb_device_handle *handle = NULL; + struct libusb_device_handle *dev_handle = NULL; size_t i = 0; int r; @@ -1302,14 +1324,14 @@ libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid( } if (found) { - r = libusb_open(found, &handle); + r = libusb_open(found, &dev_handle); if (r < 0) - handle = NULL; + dev_handle = NULL; } out: libusb_free_device_list(devs, 1); - return handle; + return dev_handle; } static void do_close(struct libusb_context *ctx, @@ -1318,8 +1340,6 @@ static void do_close(struct libusb_context *ctx, struct usbi_transfer *itransfer; struct usbi_transfer *tmp; - libusb_lock_events(ctx); - /* remove any transfers in flight that are for this device */ usbi_mutex_lock(&ctx->flying_transfers_lock); @@ -1331,23 +1351,23 @@ static void do_close(struct libusb_context *ctx, if (transfer->dev_handle != dev_handle) continue; - if (!(itransfer->flags & USBI_TRANSFER_DEVICE_DISAPPEARED)) { + usbi_mutex_lock(&itransfer->lock); + if (!(itransfer->state_flags & USBI_TRANSFER_DEVICE_DISAPPEARED)) { usbi_err(ctx, "Device handle closed while transfer was still being processed, but the device is still connected as far as we know"); - if (itransfer->flags & USBI_TRANSFER_CANCELLING) + if (itransfer->state_flags & USBI_TRANSFER_CANCELLING) usbi_warn(ctx, "A cancellation for an in-flight transfer hasn't completed but closing the device handle"); else usbi_err(ctx, "A cancellation hasn't even been scheduled on the transfer for which the device is closing"); } + usbi_mutex_unlock(&itransfer->lock); /* remove from the list of in-flight transfers and make sure * we don't accidentally use the device handle in the future * (or that such accesses will be easily caught and identified as a crash) */ - usbi_mutex_lock(&itransfer->lock); list_del(&itransfer->list); transfer->dev_handle = NULL; - usbi_mutex_unlock(&itransfer->lock); /* it is up to the user to free up the actual transfer struct. this is * just making sure that we don't attempt to process the transfer after @@ -1358,8 +1378,6 @@ static void do_close(struct libusb_context *ctx, } usbi_mutex_unlock(&ctx->flying_transfers_lock); - libusb_unlock_events(ctx); - usbi_mutex_lock(&ctx->open_devs_lock); list_del(&dev_handle->list); usbi_mutex_unlock(&ctx->open_devs_lock); @@ -1370,7 +1388,7 @@ static void do_close(struct libusb_context *ctx, free(dev_handle); } -/** \ingroup dev +/** \ingroup libusb_dev * Close a device handle. Should be called on all open handles before your * application exits. * @@ -1379,11 +1397,12 @@ static void do_close(struct libusb_context *ctx, * * This is a non-blocking function; no requests are sent over the bus. * - * \param dev_handle the handle to close + * \param dev_handle the device handle to close */ void API_EXPORTED libusb_close(libusb_device_handle *dev_handle) { struct libusb_context *ctx; + int handling_events; int pending_events; if (!dev_handle) @@ -1391,43 +1410,50 @@ void API_EXPORTED libusb_close(libusb_device_handle *dev_handle) usbi_dbg(""); ctx = HANDLE_CTX(dev_handle); + handling_events = usbi_handling_events(ctx); /* Similarly to libusb_open(), we want to interrupt all event handlers * at this point. More importantly, we want to perform the actual close of * the device while holding the event handling lock (preventing any other * thread from doing event handling) because we will be removing a file - * descriptor from the polling loop. */ + * descriptor from the polling loop. If this is being called by the current + * event handler, we can bypass the interruption code because we already + * hold the event handling lock. */ - /* Record that we are closing a device. - * Only signal an event if there are no prior pending events. */ - usbi_mutex_lock(&ctx->event_data_lock); - pending_events = usbi_pending_events(ctx); - ctx->device_close++; - if (!pending_events) - usbi_signal_event(ctx); - usbi_mutex_unlock(&ctx->event_data_lock); + if (!handling_events) { + /* Record that we are closing a device. + * Only signal an event if there are no prior pending events. */ + usbi_mutex_lock(&ctx->event_data_lock); + pending_events = usbi_pending_events(ctx); + ctx->device_close++; + if (!pending_events) + usbi_signal_event(ctx); + usbi_mutex_unlock(&ctx->event_data_lock); - /* take event handling lock */ - libusb_lock_events(ctx); + /* take event handling lock */ + libusb_lock_events(ctx); + } /* Close the device */ do_close(ctx, dev_handle); - /* We're done with closing this device. - * Clear the event pipe if there are no further pending events. */ - usbi_mutex_lock(&ctx->event_data_lock); - ctx->device_close--; - pending_events = usbi_pending_events(ctx); - if (!pending_events) - usbi_clear_event(ctx); - usbi_mutex_unlock(&ctx->event_data_lock); + if (!handling_events) { + /* We're done with closing this device. + * Clear the event pipe if there are no further pending events. */ + usbi_mutex_lock(&ctx->event_data_lock); + ctx->device_close--; + pending_events = usbi_pending_events(ctx); + if (!pending_events) + usbi_clear_event(ctx); + usbi_mutex_unlock(&ctx->event_data_lock); - /* Release event handling lock and wake up event waiters */ - libusb_unlock_events(ctx); + /* Release event handling lock and wake up event waiters */ + libusb_unlock_events(ctx); + } } -/** \ingroup dev - * Get the underlying device for a handle. This function does not modify +/** \ingroup libusb_dev + * Get the underlying device for a device handle. This function does not modify * the reference count of the returned device, so do not feel compelled to * unreference it when you are done. * \param dev_handle a device handle @@ -1439,7 +1465,7 @@ libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle) return dev_handle->dev; } -/** \ingroup dev +/** \ingroup libusb_dev * Determine the bConfigurationValue of the currently active configuration. * * You could formulate your own control request to obtain this information, @@ -1452,29 +1478,29 @@ libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle) * This function will return a value of 0 in the config output * parameter if the device is in unconfigured state. * - * \param dev a device handle + * \param dev_handle a device handle * \param config output location for the bConfigurationValue of the active * configuration (only valid for return code 0) * \returns 0 on success * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected * \returns another LIBUSB_ERROR code on other failure */ -int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev, +int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev_handle, int *config) { int r = LIBUSB_ERROR_NOT_SUPPORTED; usbi_dbg(""); if (usbi_backend->get_configuration) - r = usbi_backend->get_configuration(dev, config); + r = usbi_backend->get_configuration(dev_handle, config); if (r == LIBUSB_ERROR_NOT_SUPPORTED) { uint8_t tmp = 0; usbi_dbg("falling back to control message"); - r = libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, + r = libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_CONFIGURATION, 0, 0, &tmp, 1, 1000); if (r == 0) { - usbi_err(HANDLE_CTX(dev), "zero bytes returned in ctrl transfer?"); + usbi_err(HANDLE_CTX(dev_handle), "zero bytes returned in ctrl transfer?"); r = LIBUSB_ERROR_IO; } else if (r == 1) { r = 0; @@ -1490,7 +1516,7 @@ int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev, return r; } -/** \ingroup dev +/** \ingroup libusb_dev * Set the active configuration for a device. * * The operating system may or may not have already set an active @@ -1526,7 +1552,7 @@ int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev, * * This is a blocking function. * - * \param dev a device handle + * \param dev_handle a device handle * \param configuration the bConfigurationValue of the configuration you * wish to activate, or -1 if you wish to put the device in an unconfigured * state @@ -1537,14 +1563,14 @@ int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev, * \returns another LIBUSB_ERROR code on other failure * \see libusb_set_auto_detach_kernel_driver() */ -int API_EXPORTED libusb_set_configuration(libusb_device_handle *dev, +int API_EXPORTED libusb_set_configuration(libusb_device_handle *dev_handle, int configuration) { usbi_dbg("configuration %d", configuration); - return usbi_backend->set_configuration(dev, configuration); + return usbi_backend->set_configuration(dev_handle, configuration); } -/** \ingroup dev +/** \ingroup libusb_dev * Claim an interface on a given device handle. You must claim the interface * you wish to use before you can perform I/O on any of its endpoints. * @@ -1561,7 +1587,7 @@ int API_EXPORTED libusb_set_configuration(libusb_device_handle *dev, * * This is a non-blocking function. * - * \param dev a device handle + * \param dev_handle a device handle * \param interface_number the bInterfaceNumber of the interface you * wish to claim * \returns 0 on success @@ -1572,7 +1598,7 @@ int API_EXPORTED libusb_set_configuration(libusb_device_handle *dev, * \returns a LIBUSB_ERROR code on other failure * \see libusb_set_auto_detach_kernel_driver() */ -int API_EXPORTED libusb_claim_interface(libusb_device_handle *dev, +int API_EXPORTED libusb_claim_interface(libusb_device_handle *dev_handle, int interface_number) { int r = 0; @@ -1581,23 +1607,23 @@ int API_EXPORTED libusb_claim_interface(libusb_device_handle *dev, if (interface_number >= USB_MAXINTERFACES) return LIBUSB_ERROR_INVALID_PARAM; - if (!dev->dev->attached) + if (!dev_handle->dev->attached) return LIBUSB_ERROR_NO_DEVICE; - usbi_mutex_lock(&dev->lock); - if (dev->claimed_interfaces & (1 << interface_number)) + usbi_mutex_lock(&dev_handle->lock); + if (dev_handle->claimed_interfaces & (1 << interface_number)) goto out; - r = usbi_backend->claim_interface(dev, interface_number); + r = usbi_backend->claim_interface(dev_handle, interface_number); if (r == 0) - dev->claimed_interfaces |= 1 << interface_number; + dev_handle->claimed_interfaces |= 1 << interface_number; out: - usbi_mutex_unlock(&dev->lock); + usbi_mutex_unlock(&dev_handle->lock); return r; } -/** \ingroup dev +/** \ingroup libusb_dev * Release an interface previously claimed with libusb_claim_interface(). You * should release all claimed interfaces before closing a device handle. * @@ -1607,7 +1633,7 @@ out: * If auto_detach_kernel_driver is set to 1 for dev, the kernel * driver will be re-attached after releasing the interface. * - * \param dev a device handle + * \param dev_handle a device handle * \param interface_number the bInterfaceNumber of the * previously-claimed interface * \returns 0 on success @@ -1616,7 +1642,7 @@ out: * \returns another LIBUSB_ERROR code on other failure * \see libusb_set_auto_detach_kernel_driver() */ -int API_EXPORTED libusb_release_interface(libusb_device_handle *dev, +int API_EXPORTED libusb_release_interface(libusb_device_handle *dev_handle, int interface_number) { int r; @@ -1625,22 +1651,22 @@ int API_EXPORTED libusb_release_interface(libusb_device_handle *dev, if (interface_number >= USB_MAXINTERFACES) return LIBUSB_ERROR_INVALID_PARAM; - usbi_mutex_lock(&dev->lock); - if (!(dev->claimed_interfaces & (1 << interface_number))) { + usbi_mutex_lock(&dev_handle->lock); + if (!(dev_handle->claimed_interfaces & (1 << interface_number))) { r = LIBUSB_ERROR_NOT_FOUND; goto out; } - r = usbi_backend->release_interface(dev, interface_number); + r = usbi_backend->release_interface(dev_handle, interface_number); if (r == 0) - dev->claimed_interfaces &= ~(1 << interface_number); + dev_handle->claimed_interfaces &= ~(1 << interface_number); out: - usbi_mutex_unlock(&dev->lock); + usbi_mutex_unlock(&dev_handle->lock); return r; } -/** \ingroup dev +/** \ingroup libusb_dev * Activate an alternate setting for an interface. The interface must have * been previously claimed with libusb_claim_interface(). * @@ -1650,7 +1676,7 @@ out: * * This is a blocking function. * - * \param dev a device handle + * \param dev_handle a device handle * \param interface_number the bInterfaceNumber of the * previously-claimed interface * \param alternate_setting the bAlternateSetting of the alternate @@ -1661,7 +1687,7 @@ out: * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected * \returns another LIBUSB_ERROR code on other failure */ -int API_EXPORTED libusb_set_interface_alt_setting(libusb_device_handle *dev, +int API_EXPORTED libusb_set_interface_alt_setting(libusb_device_handle *dev_handle, int interface_number, int alternate_setting) { usbi_dbg("interface %d altsetting %d", @@ -1669,23 +1695,23 @@ int API_EXPORTED libusb_set_interface_alt_setting(libusb_device_handle *dev, if (interface_number >= USB_MAXINTERFACES) return LIBUSB_ERROR_INVALID_PARAM; - usbi_mutex_lock(&dev->lock); - if (!dev->dev->attached) { - usbi_mutex_unlock(&dev->lock); + usbi_mutex_lock(&dev_handle->lock); + if (!dev_handle->dev->attached) { + usbi_mutex_unlock(&dev_handle->lock); return LIBUSB_ERROR_NO_DEVICE; } - if (!(dev->claimed_interfaces & (1 << interface_number))) { - usbi_mutex_unlock(&dev->lock); + if (!(dev_handle->claimed_interfaces & (1 << interface_number))) { + usbi_mutex_unlock(&dev_handle->lock); return LIBUSB_ERROR_NOT_FOUND; } - usbi_mutex_unlock(&dev->lock); + usbi_mutex_unlock(&dev_handle->lock); - return usbi_backend->set_interface_altsetting(dev, interface_number, + return usbi_backend->set_interface_altsetting(dev_handle, interface_number, alternate_setting); } -/** \ingroup dev +/** \ingroup libusb_dev * Clear the halt/stall condition for an endpoint. Endpoints with halt status * are unable to receive or transmit data until the halt condition is stalled. * @@ -1694,24 +1720,24 @@ int API_EXPORTED libusb_set_interface_alt_setting(libusb_device_handle *dev, * * This is a blocking function. * - * \param dev a device handle + * \param dev_handle a device handle * \param endpoint the endpoint to clear halt status * \returns 0 on success * \returns LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected * \returns another LIBUSB_ERROR code on other failure */ -int API_EXPORTED libusb_clear_halt(libusb_device_handle *dev, +int API_EXPORTED libusb_clear_halt(libusb_device_handle *dev_handle, unsigned char endpoint) { usbi_dbg("endpoint %x", endpoint); - if (!dev->dev->attached) + if (!dev_handle->dev->attached) return LIBUSB_ERROR_NO_DEVICE; - return usbi_backend->clear_halt(dev, endpoint); + return usbi_backend->clear_halt(dev_handle, endpoint); } -/** \ingroup dev +/** \ingroup libusb_dev * Perform a USB port reset to reinitialize a device. The system will attempt * to restore the previous configuration and alternate settings after the * reset has completed. @@ -1724,22 +1750,22 @@ int API_EXPORTED libusb_clear_halt(libusb_device_handle *dev, * * This is a blocking function which usually incurs a noticeable delay. * - * \param dev a handle of the device to reset + * \param dev_handle a handle of the device to reset * \returns 0 on success * \returns LIBUSB_ERROR_NOT_FOUND if re-enumeration is required, or if the * device has been disconnected * \returns another LIBUSB_ERROR code on other failure */ -int API_EXPORTED libusb_reset_device(libusb_device_handle *dev) +int API_EXPORTED libusb_reset_device(libusb_device_handle *dev_handle) { usbi_dbg(""); - if (!dev->dev->attached) + if (!dev_handle->dev->attached) return LIBUSB_ERROR_NO_DEVICE; - return usbi_backend->reset_device(dev); + return usbi_backend->reset_device(dev_handle); } -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Allocate up to num_streams usb bulk streams on the specified endpoints. This * function takes an array of endpoints rather then a single endpoint because * some protocols require that endpoints are setup with similar stream ids. @@ -1754,62 +1780,116 @@ int API_EXPORTED libusb_reset_device(libusb_device_handle *dev) * * Since version 1.0.19, \ref LIBUSB_API_VERSION >= 0x01000103 * - * \param dev a device handle + * \param dev_handle a device handle * \param num_streams number of streams to try to allocate * \param endpoints array of endpoints to allocate streams on * \param num_endpoints length of the endpoints array * \returns number of streams allocated, or a LIBUSB_ERROR code on failure */ -int API_EXPORTED libusb_alloc_streams(libusb_device_handle *dev, +int API_EXPORTED libusb_alloc_streams(libusb_device_handle *dev_handle, uint32_t num_streams, unsigned char *endpoints, int num_endpoints) { usbi_dbg("streams %u eps %d", (unsigned) num_streams, num_endpoints); - if (!dev->dev->attached) + if (!dev_handle->dev->attached) return LIBUSB_ERROR_NO_DEVICE; if (usbi_backend->alloc_streams) - return usbi_backend->alloc_streams(dev, num_streams, endpoints, + return usbi_backend->alloc_streams(dev_handle, num_streams, endpoints, num_endpoints); else return LIBUSB_ERROR_NOT_SUPPORTED; } -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Free usb bulk streams allocated with libusb_alloc_streams(). * * Note streams are automatically free-ed when releasing an interface. * * Since version 1.0.19, \ref LIBUSB_API_VERSION >= 0x01000103 * - * \param dev a device handle + * \param dev_handle a device handle * \param endpoints array of endpoints to free streams on * \param num_endpoints length of the endpoints array * \returns LIBUSB_SUCCESS, or a LIBUSB_ERROR code on failure */ -int API_EXPORTED libusb_free_streams(libusb_device_handle *dev, +int API_EXPORTED libusb_free_streams(libusb_device_handle *dev_handle, unsigned char *endpoints, int num_endpoints) { usbi_dbg("eps %d", num_endpoints); - if (!dev->dev->attached) + if (!dev_handle->dev->attached) return LIBUSB_ERROR_NO_DEVICE; if (usbi_backend->free_streams) - return usbi_backend->free_streams(dev, endpoints, + return usbi_backend->free_streams(dev_handle, endpoints, num_endpoints); else return LIBUSB_ERROR_NOT_SUPPORTED; } -/** \ingroup dev +/** \ingroup libusb_asyncio + * Attempts to allocate a block of persistent DMA memory suitable for transfers + * against the given device. If successful, will return a block of memory + * that is suitable for use as "buffer" in \ref libusb_transfer against this + * device. Using this memory instead of regular memory means that the host + * controller can use DMA directly into the buffer to increase performance, and + * also that transfers can no longer fail due to kernel memory fragmentation. + * + * Note that this means you should not modify this memory (or even data on + * the same cache lines) when a transfer is in progress, although it is legal + * to have several transfers going on within the same memory block. + * + * Will return NULL on failure. Many systems do not support such zerocopy + * and will always return NULL. Memory allocated with this function must be + * freed with \ref libusb_dev_mem_free. Specifically, this means that the + * flag \ref LIBUSB_TRANSFER_FREE_BUFFER cannot be used to free memory allocated + * with this function. + * + * Since version 1.0.21, \ref LIBUSB_API_VERSION >= 0x01000105 + * + * \param dev_handle a device handle + * \param length size of desired data buffer + * \returns a pointer to the newly allocated memory, or NULL on failure + */ +DEFAULT_VISIBILITY +unsigned char * LIBUSB_CALL libusb_dev_mem_alloc(libusb_device_handle *dev_handle, + size_t length) +{ + if (!dev_handle->dev->attached) + return NULL; + + if (usbi_backend->dev_mem_alloc) + return usbi_backend->dev_mem_alloc(dev_handle, length); + else + return NULL; +} + +/** \ingroup libusb_asyncio + * Free device memory allocated with libusb_dev_mem_alloc(). + * + * \param dev_handle a device handle + * \param buffer pointer to the previously allocated memory + * \param length size of previously allocated memory + * \returns LIBUSB_SUCCESS, or a LIBUSB_ERROR code on failure + */ +int API_EXPORTED libusb_dev_mem_free(libusb_device_handle *dev_handle, + unsigned char *buffer, size_t length) +{ + if (usbi_backend->dev_mem_free) + return usbi_backend->dev_mem_free(dev_handle, buffer, length); + else + return LIBUSB_ERROR_NOT_SUPPORTED; +} + +/** \ingroup libusb_dev * Determine if a kernel driver is active on an interface. If a kernel driver * is active, you cannot claim the interface, and libusb will be unable to * perform I/O. * * This functionality is not available on Windows. * - * \param dev a device handle + * \param dev_handle a device handle * \param interface_number the interface to check * \returns 0 if no kernel driver is active * \returns 1 if a kernel driver is active @@ -1819,21 +1899,21 @@ int API_EXPORTED libusb_free_streams(libusb_device_handle *dev, * \returns another LIBUSB_ERROR code on other failure * \see libusb_detach_kernel_driver() */ -int API_EXPORTED libusb_kernel_driver_active(libusb_device_handle *dev, +int API_EXPORTED libusb_kernel_driver_active(libusb_device_handle *dev_handle, int interface_number) { usbi_dbg("interface %d", interface_number); - if (!dev->dev->attached) + if (!dev_handle->dev->attached) return LIBUSB_ERROR_NO_DEVICE; if (usbi_backend->kernel_driver_active) - return usbi_backend->kernel_driver_active(dev, interface_number); + return usbi_backend->kernel_driver_active(dev_handle, interface_number); else return LIBUSB_ERROR_NOT_SUPPORTED; } -/** \ingroup dev +/** \ingroup libusb_dev * Detach a kernel driver from an interface. If successful, you will then be * able to claim the interface and perform I/O. * @@ -1843,7 +1923,7 @@ int API_EXPORTED libusb_kernel_driver_active(libusb_device_handle *dev, * driver, if this driver is already attached to the device, this call will * not detach it and return LIBUSB_ERROR_NOT_FOUND. * - * \param dev a device handle + * \param dev_handle a device handle * \param interface_number the interface to detach the driver from * \returns 0 on success * \returns LIBUSB_ERROR_NOT_FOUND if no kernel driver was active @@ -1854,28 +1934,28 @@ int API_EXPORTED libusb_kernel_driver_active(libusb_device_handle *dev, * \returns another LIBUSB_ERROR code on other failure * \see libusb_kernel_driver_active() */ -int API_EXPORTED libusb_detach_kernel_driver(libusb_device_handle *dev, +int API_EXPORTED libusb_detach_kernel_driver(libusb_device_handle *dev_handle, int interface_number) { usbi_dbg("interface %d", interface_number); - if (!dev->dev->attached) + if (!dev_handle->dev->attached) return LIBUSB_ERROR_NO_DEVICE; if (usbi_backend->detach_kernel_driver) - return usbi_backend->detach_kernel_driver(dev, interface_number); + return usbi_backend->detach_kernel_driver(dev_handle, interface_number); else return LIBUSB_ERROR_NOT_SUPPORTED; } -/** \ingroup dev +/** \ingroup libusb_dev * Re-attach an interface's kernel driver, which was previously detached * using libusb_detach_kernel_driver(). This call is only effective on * Linux and returns LIBUSB_ERROR_NOT_SUPPORTED on all other platforms. * * This functionality is not available on Darwin or Windows. * - * \param dev a device handle + * \param dev_handle a device handle * \param interface_number the interface to attach the driver from * \returns 0 on success * \returns LIBUSB_ERROR_NOT_FOUND if no kernel driver was active @@ -1888,21 +1968,21 @@ int API_EXPORTED libusb_detach_kernel_driver(libusb_device_handle *dev, * \returns another LIBUSB_ERROR code on other failure * \see libusb_kernel_driver_active() */ -int API_EXPORTED libusb_attach_kernel_driver(libusb_device_handle *dev, +int API_EXPORTED libusb_attach_kernel_driver(libusb_device_handle *dev_handle, int interface_number) { usbi_dbg("interface %d", interface_number); - if (!dev->dev->attached) + if (!dev_handle->dev->attached) return LIBUSB_ERROR_NO_DEVICE; if (usbi_backend->attach_kernel_driver) - return usbi_backend->attach_kernel_driver(dev, interface_number); + return usbi_backend->attach_kernel_driver(dev_handle, interface_number); else return LIBUSB_ERROR_NOT_SUPPORTED; } -/** \ingroup dev +/** \ingroup libusb_dev * Enable/disable libusb's automatic kernel driver detachment. When this is * enabled libusb will automatically detach the kernel driver on an interface * when claiming the interface, and attach it when releasing the interface. @@ -1914,7 +1994,7 @@ int API_EXPORTED libusb_attach_kernel_driver(libusb_device_handle *dev, * this function will return LIBUSB_ERROR_NOT_SUPPORTED, and libusb will * continue as if this function was never called. * - * \param dev a device handle + * \param dev_handle a device handle * \param enable whether to enable or disable auto kernel driver detachment * * \returns LIBUSB_SUCCESS on success @@ -1925,16 +2005,16 @@ int API_EXPORTED libusb_attach_kernel_driver(libusb_device_handle *dev, * \see libusb_set_configuration() */ int API_EXPORTED libusb_set_auto_detach_kernel_driver( - libusb_device_handle *dev, int enable) + libusb_device_handle *dev_handle, int enable) { if (!(usbi_backend->caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER)) return LIBUSB_ERROR_NOT_SUPPORTED; - dev->auto_detach_kernel_driver = enable; + dev_handle->auto_detach_kernel_driver = enable; return LIBUSB_SUCCESS; } -/** \ingroup lib +/** \ingroup libusb_lib * Set log message verbosity. * * The default level is LIBUSB_LOG_LEVEL_NONE, which means no messages are ever @@ -1966,7 +2046,7 @@ void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level) ctx->debug = level; } -/** \ingroup lib +/** \ingroup libusb_lib * Initialize libusb. This function must be called before calling any other * libusb function. * @@ -1977,7 +2057,7 @@ void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level) * \param context Optional output location for context pointer. * Only valid on return code 0. * \returns 0 on success, or a LIBUSB_ERROR code on failure - * \see contexts + * \see libusb_contexts */ int API_EXPORTED libusb_init(libusb_context **context) { @@ -2026,9 +2106,9 @@ int API_EXPORTED libusb_init(libusb_context **context) usbi_dbg("libusb v%u.%u.%u.%u%s", libusb_version_internal.major, libusb_version_internal.minor, libusb_version_internal.micro, libusb_version_internal.nano, libusb_version_internal.rc); - usbi_mutex_init(&ctx->usb_devs_lock, NULL); - usbi_mutex_init(&ctx->open_devs_lock, NULL); - usbi_mutex_init(&ctx->hotplug_cbs_lock, NULL); + usbi_mutex_init(&ctx->usb_devs_lock); + usbi_mutex_init(&ctx->open_devs_lock); + usbi_mutex_init(&ctx->hotplug_cbs_lock); list_init(&ctx->usb_devs); list_init(&ctx->open_devs); list_init(&ctx->hotplug_cbs); @@ -2088,7 +2168,7 @@ err_unlock: return r; } -/** \ingroup lib +/** \ingroup libusb_lib * Deinitialize libusb. Should be called after closing all open devices and * before your application terminates. * \param ctx the context to deinitialize, or NULL for the default context @@ -2159,7 +2239,7 @@ void API_EXPORTED libusb_exit(struct libusb_context *ctx) free(ctx); } -/** \ingroup misc +/** \ingroup libusb_misc * Check at runtime if the loaded library has a given capability. * This call should be performed after \ref libusb_init(), to ensure the * backend has updated its capability set. @@ -2348,7 +2428,7 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, "libusb: %s [%s] ", prefix, function); } - if (header_len < 0 || header_len >= sizeof(buf)) { + if (header_len < 0 || header_len >= (int)sizeof(buf)) { /* Somehow snprintf failed to write to the buffer, * remove the header so something useful is output. */ header_len = 0; @@ -2357,7 +2437,7 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, buf[header_len] = '\0'; text_len = vsnprintf(buf + header_len, sizeof(buf) - header_len, format, args); - if (text_len < 0 || text_len + header_len >= sizeof(buf)) { + if (text_len < 0 || text_len + header_len >= (int)sizeof(buf)) { /* Truncated log output. On some platforms a -1 return value means * that the output was truncated. */ text_len = sizeof(buf) - header_len; @@ -2381,7 +2461,7 @@ void usbi_log(struct libusb_context *ctx, enum libusb_log_level level, va_end (args); } -/** \ingroup misc +/** \ingroup libusb_misc * Returns a constant NULL-terminated string with the ASCII name of a libusb * error or transfer status code. The caller must not free() the returned * string. @@ -2441,7 +2521,7 @@ DEFAULT_VISIBILITY const char * LIBUSB_CALL libusb_error_name(int error_code) } } -/** \ingroup misc +/** \ingroup libusb_misc * Returns a pointer to const struct libusb_version with the version * (major, minor, micro, nano and rc) of the running library. */ diff --git a/Externals/libusb/libusb/descriptor.c b/Externals/libusb/libusb/descriptor.c index b9046577b5..4c9435fffe 100644 --- a/Externals/libusb/libusb/descriptor.c +++ b/Externals/libusb/libusb/descriptor.c @@ -35,7 +35,7 @@ #define ENDPOINT_DESC_LENGTH 7 #define ENDPOINT_AUDIO_DESC_LENGTH 9 -/** @defgroup desc USB descriptors +/** @defgroup libusb_desc USB descriptors * This page details how to examine the various standard USB descriptors * for detected devices */ @@ -94,8 +94,7 @@ int usbi_parse_descriptor(const unsigned char *source, const char *descriptor, static void clear_endpoint(struct libusb_endpoint_descriptor *endpoint) { - if (endpoint->extra) - free((unsigned char *) endpoint->extra); + free((void *) endpoint->extra); } static int parse_endpoint(struct libusb_context *ctx, @@ -198,19 +197,17 @@ static void clear_interface(struct libusb_interface *usb_interface) struct libusb_interface_descriptor *ifp = (struct libusb_interface_descriptor *) usb_interface->altsetting + i; - if (ifp->extra) - free((void *) ifp->extra); + free((void *) ifp->extra); if (ifp->endpoint) { for (j = 0; j < ifp->bNumEndpoints; j++) clear_endpoint((struct libusb_endpoint_descriptor *) - ifp->endpoint + j); - free((void *) ifp->endpoint); + ifp->endpoint + j); } + free((void *) ifp->endpoint); } - free((void *) usb_interface->altsetting); - usb_interface->altsetting = NULL; } - + free((void *) usb_interface->altsetting); + usb_interface->altsetting = NULL; } static int parse_interface(libusb_context *ctx, @@ -222,7 +219,6 @@ static int parse_interface(libusb_context *ctx, int r; int parsed = 0; int interface_number = -1; - size_t tmp; struct usb_descriptor_header header; struct libusb_interface_descriptor *ifp; unsigned char *begin; @@ -323,15 +319,13 @@ static int parse_interface(libusb_context *ctx, if (ifp->bNumEndpoints > 0) { struct libusb_endpoint_descriptor *endpoint; - tmp = ifp->bNumEndpoints * sizeof(struct libusb_endpoint_descriptor); - endpoint = malloc(tmp); + endpoint = calloc(ifp->bNumEndpoints, sizeof(struct libusb_endpoint_descriptor)); ifp->endpoint = endpoint; if (!endpoint) { r = LIBUSB_ERROR_NO_MEM; goto err; } - memset(endpoint, 0, tmp); for (i = 0; i < ifp->bNumEndpoints; i++) { r = parse_endpoint(ctx, endpoint + i, buffer, size, host_endian); @@ -364,15 +358,14 @@ err: static void clear_configuration(struct libusb_config_descriptor *config) { + int i; if (config->interface) { - int i; for (i = 0; i < config->bNumInterfaces; i++) clear_interface((struct libusb_interface *) - config->interface + i); - free((void *) config->interface); + config->interface + i); } - if (config->extra) - free((void *) config->extra); + free((void *) config->interface); + free((void *) config->extra); } static int parse_configuration(struct libusb_context *ctx, @@ -381,7 +374,6 @@ static int parse_configuration(struct libusb_context *ctx, { int i; int r; - size_t tmp; struct usb_descriptor_header header; struct libusb_interface *usb_interface; @@ -411,13 +403,11 @@ static int parse_configuration(struct libusb_context *ctx, return LIBUSB_ERROR_IO; } - tmp = config->bNumInterfaces * sizeof(struct libusb_interface); - usb_interface = malloc(tmp); + usb_interface = calloc(config->bNumInterfaces, sizeof(struct libusb_interface)); config->interface = usb_interface; - if (!config->interface) + if (!usb_interface) return LIBUSB_ERROR_NO_MEM; - memset(usb_interface, 0, tmp); buffer += config->bLength; size -= config->bLength; @@ -538,7 +528,7 @@ int usbi_device_cache_descriptor(libusb_device *dev) return LIBUSB_SUCCESS; } -/** \ingroup desc +/** \ingroup libusb_desc * Get the USB device descriptor for a given device. * * This is a non-blocking function; the device descriptor is cached in memory. @@ -559,7 +549,7 @@ int API_EXPORTED libusb_get_device_descriptor(libusb_device *dev, return 0; } -/** \ingroup desc +/** \ingroup libusb_desc * Get the USB configuration descriptor for the currently active configuration. * This is a non-blocking function which does not involve any requests being * sent to the device. @@ -606,7 +596,7 @@ int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev, return r; } -/** \ingroup desc +/** \ingroup libusb_desc * Get a USB configuration descriptor based on its index. * This is a non-blocking function which does not involve any requests being * sent to the device. @@ -689,7 +679,7 @@ int usbi_get_config_index_by_value(struct libusb_device *dev, return 0; } -/** \ingroup desc +/** \ingroup libusb_desc * Get a USB configuration descriptor with a specific bConfigurationValue. * This is a non-blocking function which does not involve any requests being * sent to the device. @@ -729,7 +719,7 @@ int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev, return libusb_get_config_descriptor(dev, (uint8_t) idx, config); } -/** \ingroup desc +/** \ingroup libusb_desc * Free a configuration descriptor obtained from * libusb_get_active_config_descriptor() or libusb_get_config_descriptor(). * It is safe to call this function with a NULL config parameter, in which @@ -747,7 +737,7 @@ void API_EXPORTED libusb_free_config_descriptor( free(config); } -/** \ingroup desc +/** \ingroup libusb_desc * Get an endpoints superspeed endpoint companion descriptor (if any) * * \param ctx the context to operate on, or NULL for the default context @@ -797,7 +787,7 @@ int API_EXPORTED libusb_get_ss_endpoint_companion_descriptor( return LIBUSB_ERROR_NOT_FOUND; } -/** \ingroup desc +/** \ingroup libusb_desc * Free a superspeed endpoint companion descriptor obtained from * libusb_get_ss_endpoint_companion_descriptor(). * It is safe to call this function with a NULL ep_comp parameter, in which @@ -890,18 +880,18 @@ static int parse_bos(struct libusb_context *ctx, return LIBUSB_SUCCESS; } -/** \ingroup desc +/** \ingroup libusb_desc * Get a Binary Object Store (BOS) descriptor * This is a BLOCKING function, which will send requests to the device. * - * \param handle the handle of an open libusb device + * \param dev_handle the handle of an open libusb device * \param bos output location for the BOS descriptor. Only valid if 0 was returned. * Must be freed with \ref libusb_free_bos_descriptor() after use. * \returns 0 on success * \returns LIBUSB_ERROR_NOT_FOUND if the device doesn't have a BOS descriptor * \returns another LIBUSB_ERROR code on error */ -int API_EXPORTED libusb_get_bos_descriptor(libusb_device_handle *handle, +int API_EXPORTED libusb_get_bos_descriptor(libusb_device_handle *dev_handle, struct libusb_bos_descriptor **bos) { struct libusb_bos_descriptor _bos; @@ -912,15 +902,15 @@ int API_EXPORTED libusb_get_bos_descriptor(libusb_device_handle *handle, /* Read the BOS. This generates 2 requests on the bus, * one for the header, and one for the full BOS */ - r = libusb_get_descriptor(handle, LIBUSB_DT_BOS, 0, bos_header, + r = libusb_get_descriptor(dev_handle, LIBUSB_DT_BOS, 0, bos_header, LIBUSB_DT_BOS_SIZE); if (r < 0) { if (r != LIBUSB_ERROR_PIPE) - usbi_err(handle->dev->ctx, "failed to read BOS (%d)", r); + usbi_err(HANDLE_CTX(dev_handle), "failed to read BOS (%d)", r); return r; } if (r < LIBUSB_DT_BOS_SIZE) { - usbi_err(handle->dev->ctx, "short BOS read %d/%d", + usbi_err(HANDLE_CTX(dev_handle), "short BOS read %d/%d", r, LIBUSB_DT_BOS_SIZE); return LIBUSB_ERROR_IO; } @@ -932,18 +922,18 @@ int API_EXPORTED libusb_get_bos_descriptor(libusb_device_handle *handle, if (bos_data == NULL) return LIBUSB_ERROR_NO_MEM; - r = libusb_get_descriptor(handle, LIBUSB_DT_BOS, 0, bos_data, + r = libusb_get_descriptor(dev_handle, LIBUSB_DT_BOS, 0, bos_data, _bos.wTotalLength); if (r >= 0) - r = parse_bos(handle->dev->ctx, bos, bos_data, r, host_endian); + r = parse_bos(HANDLE_CTX(dev_handle), bos, bos_data, r, host_endian); else - usbi_err(handle->dev->ctx, "failed to read BOS (%d)", r); + usbi_err(HANDLE_CTX(dev_handle), "failed to read BOS (%d)", r); free(bos_data); return r; } -/** \ingroup desc +/** \ingroup libusb_desc * Free a BOS descriptor obtained from libusb_get_bos_descriptor(). * It is safe to call this function with a NULL bos parameter, in which * case the function simply returns. @@ -962,7 +952,7 @@ void API_EXPORTED libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos) free(bos); } -/** \ingroup desc +/** \ingroup libusb_desc * Get an USB 2.0 Extension descriptor * * \param ctx the context to operate on, or NULL for the default context @@ -1006,7 +996,7 @@ int API_EXPORTED libusb_get_usb_2_0_extension_descriptor( return LIBUSB_SUCCESS; } -/** \ingroup desc +/** \ingroup libusb_desc * Free a USB 2.0 Extension descriptor obtained from * libusb_get_usb_2_0_extension_descriptor(). * It is safe to call this function with a NULL usb_2_0_extension parameter, @@ -1020,7 +1010,7 @@ void API_EXPORTED libusb_free_usb_2_0_extension_descriptor( free(usb_2_0_extension); } -/** \ingroup desc +/** \ingroup libusb_desc * Get a SuperSpeed USB Device Capability descriptor * * \param ctx the context to operate on, or NULL for the default context @@ -1064,7 +1054,7 @@ int API_EXPORTED libusb_get_ss_usb_device_capability_descriptor( return LIBUSB_SUCCESS; } -/** \ingroup desc +/** \ingroup libusb_desc * Free a SuperSpeed USB Device Capability descriptor obtained from * libusb_get_ss_usb_device_capability_descriptor(). * It is safe to call this function with a NULL ss_usb_device_cap @@ -1078,7 +1068,7 @@ void API_EXPORTED libusb_free_ss_usb_device_capability_descriptor( free(ss_usb_device_cap); } -/** \ingroup desc +/** \ingroup libusb_desc * Get a Container ID descriptor * * \param ctx the context to operate on, or NULL for the default context @@ -1121,7 +1111,7 @@ int API_EXPORTED libusb_get_container_id_descriptor(struct libusb_context *ctx, return LIBUSB_SUCCESS; } -/** \ingroup desc +/** \ingroup libusb_desc * Free a Container ID descriptor obtained from * libusb_get_container_id_descriptor(). * It is safe to call this function with a NULL container_id parameter, @@ -1135,19 +1125,19 @@ void API_EXPORTED libusb_free_container_id_descriptor( free(container_id); } -/** \ingroup desc +/** \ingroup libusb_desc * Retrieve a string descriptor in C style ASCII. * * Wrapper around libusb_get_string_descriptor(). Uses the first language * supported by the device. * - * \param dev a device handle + * \param dev_handle a device handle * \param desc_index the index of the descriptor to retrieve * \param data output buffer for ASCII string descriptor * \param length size of data buffer * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure */ -int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev, +int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev_handle, uint8_t desc_index, unsigned char *data, int length) { unsigned char tbuf[255]; /* Some devices choke on size > 255 */ @@ -1166,7 +1156,7 @@ int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev, if (desc_index == 0) return LIBUSB_ERROR_INVALID_PARAM; - r = libusb_get_string_descriptor(dev, 0, 0, tbuf, sizeof(tbuf)); + r = libusb_get_string_descriptor(dev_handle, 0, 0, tbuf, sizeof(tbuf)); if (r < 0) return r; @@ -1175,7 +1165,7 @@ int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev, langid = tbuf[2] | (tbuf[3] << 8); - r = libusb_get_string_descriptor(dev, desc_index, langid, tbuf, + r = libusb_get_string_descriptor(dev_handle, desc_index, langid, tbuf, sizeof(tbuf)); if (r < 0) return r; diff --git a/Externals/libusb/libusb/hotplug.c b/Externals/libusb/libusb/hotplug.c index 8dc185f881..bbfd6e79a1 100644 --- a/Externals/libusb/libusb/hotplug.c +++ b/Externals/libusb/libusb/hotplug.c @@ -34,14 +34,14 @@ #include "hotplug.h" /** - * @defgroup hotplug Device hotplug event notification + * @defgroup libusb_hotplug Device hotplug event notification * This page details how to use the libusb hotplug interface, where available. * * Be mindful that not all platforms currently implement hotplug notification and * that you should first call on \ref libusb_has_capability() with parameter * \ref LIBUSB_CAP_HAS_HOTPLUG to confirm that hotplug support is available. * - * \page hotplug Device hotplug event notification + * \page libusb_hotplug Device hotplug event notification * * \section hotplug_intro Introduction * @@ -55,7 +55,7 @@ * * To receive hotplug notification you register a callback by calling * \ref libusb_hotplug_register_callback(). This function will optionally return - * a handle that can be passed to \ref libusb_hotplug_deregister_callback(). + * a callback handle that can be passed to \ref libusb_hotplug_deregister_callback(). * * A callback function must return an int (0 or 1) indicating whether the callback is * expecting additional events. Returning 0 will rearm the callback and 1 will cause @@ -75,40 +75,47 @@ * * Note: If you receive notification that a device has left and you have any * a libusb_device_handles for the device it is up to you to call libusb_close() - * on each handle to free up any remaining resources associated with the device. + * on each device handle to free up any remaining resources associated with the device. * Once a device has left any libusb_device_handle associated with the device * are invalid and will remain so even if the device comes back. * * When handling a LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED event it is considered - * safe to call any libusb function that takes a libusb_device. On the other hand, - * when handling a LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT event the only safe function + * safe to call any libusb function that takes a libusb_device. It also safe to + * open a device and submit asynchronous transfers. However, most other functions + * that take a libusb_device_handle are not safe to call. Examples of such + * functions are any of the \ref libusb_syncio "synchronous API" functions or the blocking + * functions that retrieve various \ref libusb_desc "USB descriptors". These functions must + * be used outside of the context of the hotplug callback. + * + * When handling a LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT event the only safe function * is libusb_get_device_descriptor(). * * The following code provides an example of the usage of the hotplug interface: \code #include #include +#include #include static int count = 0; int hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev, libusb_hotplug_event event, void *user_data) { - static libusb_device_handle *handle = NULL; + static libusb_device_handle *dev_handle = NULL; struct libusb_device_descriptor desc; int rc; (void)libusb_get_device_descriptor(dev, &desc); if (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == event) { - rc = libusb_open(dev, &handle); + rc = libusb_open(dev, &dev_handle); if (LIBUSB_SUCCESS != rc) { printf("Could not open USB device\n"); } } else if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == event) { - if (handle) { - libusb_close(handle); - handle = NULL; + if (dev_handle) { + libusb_close(dev_handle); + dev_handle = NULL; } } else { printf("Unhandled event %d\n", event); @@ -119,7 +126,7 @@ int hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev, } int main (void) { - libusb_hotplug_callback_handle handle; + libusb_hotplug_callback_handle callback_handle; int rc; libusb_init(NULL); @@ -127,7 +134,7 @@ int main (void) { rc = libusb_hotplug_register_callback(NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0, 0x045a, 0x5005, LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, NULL, - &handle); + &callback_handle); if (LIBUSB_SUCCESS != rc) { printf("Error creating a hotplug callback\n"); libusb_exit(NULL); @@ -136,10 +143,10 @@ int main (void) { while (count < 2) { libusb_handle_events_completed(NULL, NULL); - usleep(10000); + nanosleep(&(struct timespec){0, 10000000UL}, NULL); } - libusb_hotplug_deregister_callback(NULL, handle); + libusb_hotplug_deregister_callback(NULL, callback_handle); libusb_exit(NULL); return 0; @@ -231,7 +238,7 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx, libusb_hotplug_event events, libusb_hotplug_flag flags, int vendor_id, int product_id, int dev_class, libusb_hotplug_callback_fn cb_fn, void *user_data, - libusb_hotplug_callback_handle *handle) + libusb_hotplug_callback_handle *callback_handle) { libusb_hotplug_callback *new_callback; static int handle_id = 1; @@ -298,15 +305,14 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx, } - if (handle) { - *handle = new_callback->handle; - } + if (callback_handle) + *callback_handle = new_callback->handle; return LIBUSB_SUCCESS; } void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx, - libusb_hotplug_callback_handle handle) + libusb_hotplug_callback_handle callback_handle) { struct libusb_hotplug_callback *hotplug_cb; @@ -320,7 +326,7 @@ void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx usbi_mutex_lock(&ctx->hotplug_cbs_lock); list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) { - if (handle == hotplug_cb->handle) { + if (callback_handle == hotplug_cb->handle) { /* Mark this callback for deregistration */ hotplug_cb->needs_free = 1; } diff --git a/Externals/libusb/libusb/io.c b/Externals/libusb/libusb/io.c index 279288cf14..bf2b5fa428 100644 --- a/Externals/libusb/libusb/io.c +++ b/Externals/libusb/libusb/io.c @@ -41,7 +41,7 @@ #include "hotplug.h" /** - * \page io Synchronous and asynchronous device I/O + * \page libusb_io Synchronous and asynchronous device I/O * * \section io_intro Introduction * @@ -55,8 +55,8 @@ * * Once you have read through the following discussion, you should consult the * detailed API documentation pages for the details: - * - \ref syncio - * - \ref asyncio + * - \ref libusb_syncio + * - \ref libusb_asyncio * * \section theory Transfers at a logical level * @@ -97,7 +97,7 @@ \code unsigned char data[4]; int actual_length; -int r = libusb_bulk_transfer(handle, LIBUSB_ENDPOINT_IN, data, sizeof(data), &actual_length, 0); +int r = libusb_bulk_transfer(dev_handle, LIBUSB_ENDPOINT_IN, data, sizeof(data), &actual_length, 0); if (r == 0 && actual_length == sizeof(data)) { // results of the transaction can now be found in the data buffer // parse them here and report button press @@ -124,7 +124,7 @@ if (r == 0 && actual_length == sizeof(data)) { * request has been submitted. * * For details on how to use the synchronous API, see the - * \ref syncio "synchronous I/O API documentation" pages. + * \ref libusb_syncio "synchronous I/O API documentation" pages. * * \section async The asynchronous interface * @@ -165,12 +165,12 @@ if (r == 0 && actual_length == sizeof(data)) { * calls to the asynchronous interface. * * For details on how to use the asynchronous API, see the - * \ref asyncio "asynchronous I/O API" documentation pages. + * \ref libusb_asyncio "asynchronous I/O API" documentation pages. */ /** - * \page packetoverflow Packets and overflows + * \page libusb_packetoverflow Packets and overflows * * \section packets Packet abstraction * @@ -212,13 +212,13 @@ if (r == 0 && actual_length == sizeof(data)) { */ /** - * @defgroup asyncio Asynchronous device I/O + * @defgroup libusb_asyncio Asynchronous device I/O * * This page details libusb's asynchronous (non-blocking) API for USB device * I/O. This interface is very powerful but is also quite complex - you will * need to read this page carefully to understand the necessary considerations * and issues surrounding use of this interface. Simplistic applications - * may wish to consider the \ref syncio "synchronous I/O API" instead. + * may wish to consider the \ref libusb_syncio "synchronous I/O API" instead. * * The asynchronous interface is built around the idea of separating transfer * submission and handling of transfer completion (the synchronous model @@ -293,6 +293,12 @@ if (r == 0 && actual_length == sizeof(data)) { * success or failure reason, number of bytes of data transferred, etc. See * the libusb_transfer structure documentation for more information. * + * Important Note: The user-specified callback is called from an event + * handling context. It is therefore important that no calls are made into + * libusb that will attempt to perform any event handling. Examples of such + * functions are any listed in the \ref libusb_syncio "synchronous API" and any of + * the blocking functions that retrieve \ref libusb_desc "USB descriptors". + * * \subsection Deallocation * * When a transfer has completed (i.e. the callback function has been invoked), @@ -337,7 +343,7 @@ if (r == 0 && actual_length == sizeof(data)) { * your application may submit a request for data on an IN endpoint which is * smaller than the data that the device wishes to send. In some circumstances * this will cause an overflow, which is a nasty condition to deal with. See - * the \ref packetoverflow page for discussion. + * the \ref libusb_packetoverflow page for discussion. * * \section asyncctrl Considerations for control transfers * @@ -528,7 +534,7 @@ if (r == 0 && actual_length == sizeof(data)) { * below for details. * * If you prefer a single threaded approach with a single central event loop, - * see the \ref poll "polling and timing" section for how to integrate libusb + * see the \ref libusb_poll "polling and timing" section for how to integrate libusb * into your application's main event loop. * * \section eventthread Using an event handling thread @@ -555,18 +561,18 @@ void *event_thread_func(void *ctx) * libusb_handle_events() will not return. * * There are 2 different ways of dealing with this, depending on if your - * application uses libusb' \ref hotplug "hotplug" support or not. + * application uses libusb' \ref libusb_hotplug "hotplug" support or not. * * Applications which do not use hotplug support, should not start the event * thread until after their first call to libusb_open(), and should stop the * thread when closing the last open device as follows: \code -void my_close_handle(libusb_device_handle *handle) +void my_close_handle(libusb_device_handle *dev_handle) { if (open_devs == 1) event_thread_run = 0; - libusb_close(handle); // This wakes up libusb_handle_events() + libusb_close(dev_handle); // This wakes up libusb_handle_events() if (open_devs == 1) pthread_join(event_thread); @@ -580,7 +586,7 @@ void my_close_handle(libusb_device_handle *handle) * should stop the thread at program exit as follows: \code void my_libusb_exit(void) -{ +{ event_thread_run = 0; libusb_hotplug_deregister_callback(ctx, hotplug_cb_handle); // This wakes up libusb_handle_events() pthread_join(event_thread); @@ -590,12 +596,12 @@ void my_libusb_exit(void) */ /** - * @defgroup poll Polling and timing + * @defgroup libusb_poll Polling and timing * * This page documents libusb's functions for polling events and timing. * These functions are only necessary for users of the - * \ref asyncio "asynchronous API". If you are only using the simpler - * \ref syncio "synchronous API" then you do not need to ever call these + * \ref libusb_asyncio "asynchronous API". If you are only using the simpler + * \ref libusb_syncio "synchronous API" then you do not need to ever call these * functions. * * The justification for the functionality described here has already been @@ -620,7 +626,7 @@ void my_libusb_exit(void) * descriptors in your main event loop, you must also consider that libusb * sometimes needs to be called into at fixed points in time even when there * is no file descriptor activity, see \ref polltime details. - * + * * In order to know precisely when libusb needs to be called into, libusb * offers you a set of pollable file descriptors and information about when * the next timeout expires. @@ -647,7 +653,7 @@ while (user_has_not_requested_exit) * sets of file descriptors or handling timeouts. libusb_handle_events() will * handle those details internally. * - * \section pollmain The more advanced option + * \section libusb_pollmain The more advanced option * * \note This functionality is currently only available on Unix-like platforms. * On Windows, libusb_get_pollfds() simply returns NULL. Applications which @@ -762,10 +768,10 @@ while (user has not requested application exit) { * entities are added to solve these problems. You do not need to be concerned * with these entities otherwise. * - * See the extra documentation: \ref mtasync + * See the extra documentation: \ref libusb_mtasync */ -/** \page mtasync Multi-threaded applications and asynchronous I/O +/** \page libusb_mtasync Multi-threaded applications and asynchronous I/O * * libusb is a thread-safe library, but extra considerations must be applied * to applications which interact with libusb from multiple threads. @@ -773,8 +779,8 @@ while (user has not requested application exit) { * The underlying issue that must be addressed is that all libusb I/O * revolves around monitoring file descriptors through the poll()/select() * system calls. This is directly exposed at the - * \ref asyncio "asynchronous interface" but it is important to note that the - * \ref syncio "synchronous interface" is implemented on top of the + * \ref libusb_asyncio "asynchronous interface" but it is important to note that the + * \ref libusb_syncio "synchronous interface" is implemented on top of the * asynchonrous interface, therefore the same considerations apply. * * The issue is that if two or more threads are concurrently calling poll() @@ -1101,7 +1107,7 @@ printf("completed!\n"); * (without implementing the rules and locking semantics documented above) * and another trying to send a synchronous USB transfer, you will end up with * two threads monitoring the same descriptors, and the above-described - * undesirable behaviour occuring. The solution is for your polling thread to + * undesirable behaviour occurring. The solution is for your polling thread to * play by the rules; the synchronous I/O functions do so, and this will result * in them getting along in perfect harmony. * @@ -1118,11 +1124,12 @@ int usbi_io_init(struct libusb_context *ctx) { int r; - usbi_mutex_init(&ctx->flying_transfers_lock, NULL); - usbi_mutex_init_recursive(&ctx->events_lock, NULL); - usbi_mutex_init(&ctx->event_waiters_lock, NULL); - usbi_cond_init(&ctx->event_waiters_cond, NULL); - usbi_mutex_init(&ctx->event_data_lock, NULL); + usbi_mutex_init(&ctx->flying_transfers_lock); + usbi_mutex_init(&ctx->events_lock); + usbi_mutex_init(&ctx->event_waiters_lock); + usbi_cond_init(&ctx->event_waiters_cond); + usbi_mutex_init(&ctx->event_data_lock); + usbi_tls_key_create(&ctx->event_handling_key); list_init(&ctx->flying_transfers); list_init(&ctx->ipollfds); list_init(&ctx->hotplug_msgs); @@ -1169,6 +1176,7 @@ err: usbi_mutex_destroy(&ctx->event_waiters_lock); usbi_cond_destroy(&ctx->event_waiters_cond); usbi_mutex_destroy(&ctx->event_data_lock); + usbi_tls_key_delete(ctx->event_handling_key); return r; } @@ -1188,6 +1196,7 @@ void usbi_io_exit(struct libusb_context *ctx) usbi_mutex_destroy(&ctx->event_waiters_lock); usbi_cond_destroy(&ctx->event_waiters_cond); usbi_mutex_destroy(&ctx->event_data_lock); + usbi_tls_key_delete(ctx->event_handling_key); if (ctx->pollfds) free(ctx->pollfds); } @@ -1221,7 +1230,7 @@ static int calculate_timeout(struct usbi_transfer *transfer) return 0; } -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Allocate a libusb transfer with a specified number of isochronous packet * descriptors. The returned transfer is pre-initialized for you. When the new * transfer is no longer needed, it should be freed with @@ -1259,14 +1268,13 @@ struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer( return NULL; itransfer->num_iso_packets = iso_packets; - usbi_mutex_init(&itransfer->lock, NULL); - usbi_mutex_init(&itransfer->flags_lock, NULL); + usbi_mutex_init(&itransfer->lock); transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); usbi_dbg("transfer %p", transfer); return transfer; } -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Free a transfer structure. This should be called for all transfers * allocated with libusb_alloc_transfer(). * @@ -1295,7 +1303,6 @@ void API_EXPORTED libusb_free_transfer(struct libusb_transfer *transfer) itransfer = LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer); usbi_mutex_destroy(&itransfer->lock); - usbi_mutex_destroy(&itransfer->flags_lock); free(itransfer); } @@ -1330,8 +1337,8 @@ static int arm_timerfd_for_next_timeout(struct libusb_context *ctx) if (!timerisset(cur_tv)) goto disarm; - /* act on first transfer that is not already cancelled */ - if (!(transfer->flags & USBI_TRANSFER_TIMEOUT_HANDLED)) { + /* act on first transfer that has not already been handled */ + if (!(transfer->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT))) { int r; const struct itimerspec it = { {0, 0}, { cur_tv->tv_sec, cur_tv->tv_usec * 1000 } }; @@ -1349,7 +1356,7 @@ disarm: #else static int arm_timerfd_for_next_timeout(struct libusb_context *ctx) { - (void)ctx; + UNUSED(ctx); return 0; } #endif @@ -1362,10 +1369,12 @@ static int add_to_flying_list(struct usbi_transfer *transfer) struct usbi_transfer *cur; struct timeval *timeout = &transfer->timeout; struct libusb_context *ctx = ITRANSFER_CTX(transfer); - int r = 0; + int r; int first = 1; - usbi_mutex_lock(&ctx->flying_transfers_lock); + r = calculate_timeout(transfer); + if (r) + return r; /* if we have no other flying transfers, start the list with this one */ if (list_empty(&ctx->flying_transfers)) { @@ -1419,7 +1428,6 @@ out: if (r) list_del(&transfer->list); - usbi_mutex_unlock(&ctx->flying_transfers_lock); return r; } @@ -1444,7 +1452,7 @@ static int remove_from_flying_list(struct usbi_transfer *transfer) return r; } -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Submit a transfer. This function will fire off the USB transfer and then * return immediately. * @@ -1454,72 +1462,88 @@ static int remove_from_flying_list(struct usbi_transfer *transfer) * \returns LIBUSB_ERROR_BUSY if the transfer has already been submitted. * \returns LIBUSB_ERROR_NOT_SUPPORTED if the transfer flags are not supported * by the operating system. + * \returns LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than + * the operating system and/or hardware can support * \returns another LIBUSB_ERROR code on other failure */ int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer) { struct usbi_transfer *itransfer = LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer); - int remove = 0; + struct libusb_context *ctx = TRANSFER_CTX(transfer); int r; usbi_dbg("transfer %p", transfer); + + /* + * Important note on locking, this function takes / releases locks + * in the following order: + * take flying_transfers_lock + * take itransfer->lock + * clear transfer + * add to flying_transfers list + * release flying_transfers_lock + * submit transfer + * release itransfer->lock + * if submit failed: + * take flying_transfers_lock + * remove from flying_transfers list + * release flying_transfers_lock + * + * Note that it takes locks in the order a-b and then releases them + * in the same order a-b. This is somewhat unusual but not wrong, + * release order is not important as long as *all* locks are released + * before re-acquiring any locks. + * + * This means that the ordering of first releasing itransfer->lock + * and then re-acquiring the flying_transfers_list on error is + * important and must not be changed! + * + * This is done this way because when we take both locks we must always + * take flying_transfers_lock first to avoid ab-ba style deadlocks with + * the timeout handling and usbi_handle_disconnect paths. + * + * And we cannot release itransfer->lock before the submission is + * complete otherwise timeout handling for transfers with short + * timeouts may run before submission. + */ + usbi_mutex_lock(&ctx->flying_transfers_lock); usbi_mutex_lock(&itransfer->lock); - usbi_mutex_lock(&itransfer->flags_lock); - if (itransfer->flags & USBI_TRANSFER_IN_FLIGHT) { - r = LIBUSB_ERROR_BUSY; - goto out; + if (itransfer->state_flags & USBI_TRANSFER_IN_FLIGHT) { + usbi_mutex_unlock(&ctx->flying_transfers_lock); + usbi_mutex_unlock(&itransfer->lock); + return LIBUSB_ERROR_BUSY; } itransfer->transferred = 0; - itransfer->flags = 0; - r = calculate_timeout(itransfer); - if (r < 0) { - r = LIBUSB_ERROR_OTHER; - goto out; - } - itransfer->flags |= USBI_TRANSFER_SUBMITTING; - usbi_mutex_unlock(&itransfer->flags_lock); - + itransfer->state_flags = 0; + itransfer->timeout_flags = 0; r = add_to_flying_list(itransfer); if (r) { - usbi_mutex_lock(&itransfer->flags_lock); - itransfer->flags = 0; - goto out; + usbi_mutex_unlock(&ctx->flying_transfers_lock); + usbi_mutex_unlock(&itransfer->lock); + return r; } + /* + * We must release the flying transfers lock here, because with + * some backends the submit_transfer method is synchroneous. + */ + usbi_mutex_unlock(&ctx->flying_transfers_lock); - /* keep a reference to this device */ - libusb_ref_device(transfer->dev_handle->dev); r = usbi_backend->submit_transfer(itransfer); - - usbi_mutex_lock(&itransfer->flags_lock); - itransfer->flags &= ~USBI_TRANSFER_SUBMITTING; if (r == LIBUSB_SUCCESS) { - /* check for two possible special conditions: - * 1) device disconnect occurred immediately after submission - * 2) transfer completed before we got here to update the flags - */ - if (itransfer->flags & USBI_TRANSFER_DEVICE_DISAPPEARED) { - usbi_backend->clear_transfer_priv(itransfer); - remove = 1; - r = LIBUSB_ERROR_NO_DEVICE; - } - else if (!(itransfer->flags & USBI_TRANSFER_COMPLETED)) { - itransfer->flags |= USBI_TRANSFER_IN_FLIGHT; - } - } else { - remove = 1; - } -out: - usbi_mutex_unlock(&itransfer->flags_lock); - if (remove) { - libusb_unref_device(transfer->dev_handle->dev); - remove_from_flying_list(itransfer); + itransfer->state_flags |= USBI_TRANSFER_IN_FLIGHT; + /* keep a reference to this device */ + libusb_ref_device(transfer->dev_handle->dev); } usbi_mutex_unlock(&itransfer->lock); + + if (r != LIBUSB_SUCCESS) + remove_from_flying_list(itransfer); + return r; } -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Asynchronously cancel a previously submitted transfer. * This function returns immediately, but this does not indicate cancellation * is complete. Your callback function will be invoked at some later time @@ -1541,9 +1565,8 @@ int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer) usbi_dbg("transfer %p", transfer ); usbi_mutex_lock(&itransfer->lock); - usbi_mutex_lock(&itransfer->flags_lock); - if (!(itransfer->flags & USBI_TRANSFER_IN_FLIGHT) - || (itransfer->flags & USBI_TRANSFER_CANCELLING)) { + if (!(itransfer->state_flags & USBI_TRANSFER_IN_FLIGHT) + || (itransfer->state_flags & USBI_TRANSFER_CANCELLING)) { r = LIBUSB_ERROR_NOT_FOUND; goto out; } @@ -1557,18 +1580,17 @@ int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer) usbi_dbg("cancel transfer failed error %d", r); if (r == LIBUSB_ERROR_NO_DEVICE) - itransfer->flags |= USBI_TRANSFER_DEVICE_DISAPPEARED; + itransfer->state_flags |= USBI_TRANSFER_DEVICE_DISAPPEARED; } - itransfer->flags |= USBI_TRANSFER_CANCELLING; + itransfer->state_flags |= USBI_TRANSFER_CANCELLING; out: - usbi_mutex_unlock(&itransfer->flags_lock); usbi_mutex_unlock(&itransfer->lock); return r; } -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Set a transfers bulk stream id. Note users are advised to use * libusb_fill_bulk_stream_transfer() instead of calling this function * directly. @@ -1588,7 +1610,7 @@ void API_EXPORTED libusb_transfer_set_stream_id( itransfer->stream_id = stream_id; } -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Get a transfers bulk stream id. * * Since version 1.0.19, \ref LIBUSB_API_VERSION >= 0x01000103 @@ -1618,7 +1640,7 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_device_handle *handle = transfer->dev_handle; + struct libusb_device_handle *dev_handle = transfer->dev_handle; uint8_t flags; int r; @@ -1626,10 +1648,9 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, if (r < 0) usbi_err(ITRANSFER_CTX(itransfer), "failed to set timer for next timeout, errno=%d", errno); - usbi_mutex_lock(&itransfer->flags_lock); - itransfer->flags &= ~USBI_TRANSFER_IN_FLIGHT; - itransfer->flags |= USBI_TRANSFER_COMPLETED; - usbi_mutex_unlock(&itransfer->flags_lock); + usbi_mutex_lock(&itransfer->lock); + itransfer->state_flags &= ~USBI_TRANSFER_IN_FLIGHT; + usbi_mutex_unlock(&itransfer->lock); if (status == LIBUSB_TRANSFER_COMPLETED && transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { @@ -1652,7 +1673,7 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, * this point. */ if (flags & LIBUSB_TRANSFER_FREE_TRANSFER) libusb_free_transfer(transfer); - libusb_unref_device(handle->dev); + libusb_unref_device(dev_handle->dev); return r; } @@ -1664,8 +1685,15 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, * will attempt to take the lock. */ int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer) { + struct libusb_context *ctx = ITRANSFER_CTX(transfer); + uint8_t timed_out; + + usbi_mutex_lock(&ctx->flying_transfers_lock); + timed_out = transfer->timeout_flags & USBI_TRANSFER_TIMED_OUT; + usbi_mutex_unlock(&ctx->flying_transfers_lock); + /* if the URB was cancelled due to timeout, report timeout to the user */ - if (transfer->flags & USBI_TRANSFER_TIMED_OUT) { + if (timed_out) { usbi_dbg("detected timeout cancellation"); return usbi_handle_transfer_completion(transfer, LIBUSB_TRANSFER_TIMED_OUT); } @@ -1690,7 +1718,7 @@ void usbi_signal_transfer_completion(struct usbi_transfer *transfer) usbi_mutex_unlock(&ctx->event_data_lock); } -/** \ingroup poll +/** \ingroup libusb_poll * Attempt to acquire the event handling lock. This lock is used to ensure that * only one thread is monitoring libusb event sources at any one time. * @@ -1707,7 +1735,7 @@ void usbi_signal_transfer_completion(struct usbi_transfer *transfer) * \param ctx the context to operate on, or NULL for the default context * \returns 0 if the lock was obtained successfully * \returns 1 if the lock was not obtained (i.e. another thread holds the lock) - * \ref mtasync + * \ref libusb_mtasync */ int API_EXPORTED libusb_try_lock_events(libusb_context *ctx) { @@ -1733,7 +1761,7 @@ int API_EXPORTED libusb_try_lock_events(libusb_context *ctx) return 0; } -/** \ingroup poll +/** \ingroup libusb_poll * Acquire the event handling lock, blocking until successful acquisition if * it is contended. This lock is used to ensure that only one thread is * monitoring libusb event sources at any one time. @@ -1749,7 +1777,7 @@ int API_EXPORTED libusb_try_lock_events(libusb_context *ctx) * as soon as possible. * * \param ctx the context to operate on, or NULL for the default context - * \ref mtasync + * \ref libusb_mtasync */ void API_EXPORTED libusb_lock_events(libusb_context *ctx) { @@ -1758,13 +1786,13 @@ void API_EXPORTED libusb_lock_events(libusb_context *ctx) ctx->event_handler_active = 1; } -/** \ingroup poll +/** \ingroup libusb_poll * Release the lock previously acquired with libusb_try_lock_events() or * libusb_lock_events(). Releasing this lock will wake up any threads blocked * on libusb_wait_for_event(). * * \param ctx the context to operate on, or NULL for the default context - * \ref mtasync + * \ref libusb_mtasync */ void API_EXPORTED libusb_unlock_events(libusb_context *ctx) { @@ -1780,7 +1808,7 @@ void API_EXPORTED libusb_unlock_events(libusb_context *ctx) usbi_mutex_unlock(&ctx->event_waiters_lock); } -/** \ingroup poll +/** \ingroup libusb_poll * Determine if it is still OK for this thread to be doing event handling. * * Sometimes, libusb needs to temporarily pause all event handlers, and this @@ -1788,7 +1816,7 @@ void API_EXPORTED libusb_unlock_events(libusb_context *ctx) * this is the case. * * If this function instructs your thread to give up the events lock, you - * should just continue the usual logic that is documented in \ref mtasync. + * should just continue the usual logic that is documented in \ref libusb_mtasync. * On the next iteration, your thread will fail to obtain the events lock, * and will hence become an event waiter. * @@ -1820,14 +1848,14 @@ int API_EXPORTED libusb_event_handling_ok(libusb_context *ctx) } -/** \ingroup poll +/** \ingroup libusb_poll * Determine if an active thread is handling events (i.e. if anyone is holding * the event handling lock). * * \param ctx the context to operate on, or NULL for the default context * \returns 1 if a thread is handling events * \returns 0 if there are no threads currently handling events - * \ref mtasync + * \ref libusb_mtasync */ int API_EXPORTED libusb_event_handler_active(libusb_context *ctx) { @@ -1847,7 +1875,30 @@ int API_EXPORTED libusb_event_handler_active(libusb_context *ctx) return ctx->event_handler_active; } -/** \ingroup poll +/** \ingroup libusb_poll + * Interrupt any active thread that is handling events. This is mainly useful + * for interrupting a dedicated event handling thread when an application + * wishes to call libusb_exit(). + * + * Since version 1.0.21, \ref LIBUSB_API_VERSION >= 0x01000105 + * + * \param ctx the context to operate on, or NULL for the default context + * \ref libusb_mtasync + */ +void API_EXPORTED libusb_interrupt_event_handler(libusb_context *ctx) +{ + USBI_GET_CONTEXT(ctx); + + usbi_dbg(""); + usbi_mutex_lock(&ctx->event_data_lock); + if (!usbi_pending_events(ctx)) { + ctx->event_flags |= USBI_EVENT_USER_INTERRUPT; + usbi_signal_event(ctx); + } + usbi_mutex_unlock(&ctx->event_data_lock); +} + +/** \ingroup libusb_poll * Acquire the event waiters lock. This lock is designed to be obtained under * the situation where you want to be aware when events are completed, but * some other thread is event handling so calling libusb_handle_events() is not @@ -1864,7 +1915,7 @@ int API_EXPORTED libusb_event_handler_active(libusb_context *ctx) * locking. * * \param ctx the context to operate on, or NULL for the default context - * \ref mtasync + * \ref libusb_mtasync */ void API_EXPORTED libusb_lock_event_waiters(libusb_context *ctx) { @@ -1872,10 +1923,10 @@ void API_EXPORTED libusb_lock_event_waiters(libusb_context *ctx) usbi_mutex_lock(&ctx->event_waiters_lock); } -/** \ingroup poll +/** \ingroup libusb_poll * Release the event waiters lock. * \param ctx the context to operate on, or NULL for the default context - * \ref mtasync + * \ref libusb_mtasync */ void API_EXPORTED libusb_unlock_event_waiters(libusb_context *ctx) { @@ -1883,7 +1934,7 @@ void API_EXPORTED libusb_unlock_event_waiters(libusb_context *ctx) usbi_mutex_unlock(&ctx->event_waiters_lock); } -/** \ingroup poll +/** \ingroup libusb_poll * Wait for another thread to signal completion of an event. Must be called * with the event waiters lock held, see libusb_lock_event_waiters(). * @@ -1906,11 +1957,10 @@ void API_EXPORTED libusb_unlock_event_waiters(libusb_context *ctx) * indicates unlimited timeout. * \returns 0 after a transfer completes or another thread stops event handling * \returns 1 if the timeout expired - * \ref mtasync + * \ref libusb_mtasync */ int API_EXPORTED libusb_wait_for_event(libusb_context *ctx, struct timeval *tv) { - struct timespec timeout; int r; USBI_GET_CONTEXT(ctx); @@ -1919,22 +1969,13 @@ int API_EXPORTED libusb_wait_for_event(libusb_context *ctx, struct timeval *tv) return 0; } - r = usbi_backend->clock_gettime(USBI_CLOCK_REALTIME, &timeout); - if (r < 0) { - usbi_err(ctx, "failed to read realtime clock, error %d", errno); - return LIBUSB_ERROR_OTHER; - } - - timeout.tv_sec += tv->tv_sec; - timeout.tv_nsec += tv->tv_usec * 1000; - while (timeout.tv_nsec >= 1000000000) { - timeout.tv_nsec -= 1000000000; - timeout.tv_sec++; - } - r = usbi_cond_timedwait(&ctx->event_waiters_cond, - &ctx->event_waiters_lock, &timeout); - return (r == ETIMEDOUT); + &ctx->event_waiters_lock, tv); + + if (r < 0) + return r; + else + return (r == ETIMEDOUT); } static void handle_timeout(struct usbi_transfer *itransfer) @@ -1943,10 +1984,10 @@ static void handle_timeout(struct usbi_transfer *itransfer) USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); int r; - itransfer->flags |= USBI_TRANSFER_TIMEOUT_HANDLED; + itransfer->timeout_flags |= USBI_TRANSFER_TIMEOUT_HANDLED; r = libusb_cancel_transfer(transfer); - if (r == 0) - itransfer->flags |= USBI_TRANSFER_TIMED_OUT; + if (r == LIBUSB_SUCCESS) + itransfer->timeout_flags |= USBI_TRANSFER_TIMED_OUT; else usbi_warn(TRANSFER_CTX(transfer), "async cancel failed %d errno=%d", r, errno); @@ -1979,7 +2020,7 @@ static int handle_timeouts_locked(struct libusb_context *ctx) return 0; /* ignore timeouts we've already handled */ - if (transfer->flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT)) + if (transfer->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT)) continue; /* if transfer has non-expired timeout, nothing more to do */ @@ -2038,6 +2079,12 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv) int timeout_ms; int special_event; + /* prevent attempts to recursively handle events (e.g. calling into + * libusb_handle_events() from within a hotplug or transfer callback) */ + if (usbi_handling_events(ctx)) + return LIBUSB_ERROR_BUSY; + usbi_start_event_handling(ctx); + /* there are certain fds that libusb uses internally, currently: * * 1) event pipe @@ -2055,7 +2102,7 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv) /* only reallocate the poll fds when the list of poll fds has been modified * since the last poll, otherwise reuse them to save the additional overhead */ usbi_mutex_lock(&ctx->event_data_lock); - if (ctx->pollfds_modified) { + if (ctx->event_flags & USBI_EVENT_POLLFDS_MODIFIED) { usbi_dbg("poll fds modified, reallocating"); if (ctx->pollfds) { @@ -2070,7 +2117,8 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv) ctx->pollfds = calloc(ctx->pollfds_cnt, sizeof(*ctx->pollfds)); if (!ctx->pollfds) { usbi_mutex_unlock(&ctx->event_data_lock); - return LIBUSB_ERROR_NO_MEM; + r = LIBUSB_ERROR_NO_MEM; + goto done; } list_for_each_entry(ipollfd, &ctx->ipollfds, list, struct usbi_pollfd) { @@ -2081,7 +2129,7 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv) } /* reset the flag now that we have the updated list */ - ctx->pollfds_modified = 0; + ctx->event_flags &= ~USBI_EVENT_POLLFDS_MODIFIED; /* if no further pending events, clear the event pipe so that we do * not immediately return from poll */ @@ -2102,13 +2150,18 @@ redo_poll: usbi_dbg("poll() %d fds with timeout in %dms", nfds, timeout_ms); r = usbi_poll(fds, nfds, timeout_ms); usbi_dbg("poll() returned %d", r); - if (r == 0) - return handle_timeouts(ctx); - else if (r == -1 && errno == EINTR) - return LIBUSB_ERROR_INTERRUPTED; + if (r == 0) { + r = handle_timeouts(ctx); + goto done; + } + else if (r == -1 && errno == EINTR) { + r = LIBUSB_ERROR_INTERRUPTED; + goto done; + } else if (r < 0) { usbi_err(ctx, "poll failed %d err=%d", r, errno); - return LIBUSB_ERROR_IO; + r = LIBUSB_ERROR_IO; + goto done; } special_event = 0; @@ -2125,9 +2178,14 @@ redo_poll: usbi_mutex_lock(&ctx->event_data_lock); /* check if someone added a new poll fd */ - if (ctx->pollfds_modified) + if (ctx->event_flags & USBI_EVENT_POLLFDS_MODIFIED) usbi_dbg("someone updated the poll fds"); + if (ctx->event_flags & USBI_EVENT_USER_INTERRUPT) { + usbi_dbg("someone purposely interrupted"); + ctx->event_flags &= ~USBI_EVENT_USER_INTERRUPT; + } + /* check if someone is closing a device */ if (ctx->device_close) usbi_dbg("someone is closing a device"); @@ -2171,7 +2229,7 @@ redo_poll: if (ret) { /* return error code */ r = ret; - goto handled; + goto done; } if (0 == --r) @@ -2190,7 +2248,7 @@ redo_poll: if (ret < 0) { /* return error code */ r = ret; - goto handled; + goto done; } if (0 == --r) @@ -2208,6 +2266,8 @@ handled: goto redo_poll; } +done: + usbi_end_event_handling(ctx); return r; } @@ -2238,7 +2298,7 @@ static int get_next_timeout(libusb_context *ctx, struct timeval *tv, return 0; } -/** \ingroup poll +/** \ingroup libusb_poll * Handle any pending events. * * libusb determines "pending events" by checking if any timeouts have expired @@ -2262,7 +2322,7 @@ static int get_next_timeout(libusb_context *ctx, struct timeval *tv, * timeval struct for non-blocking mode * \param completed pointer to completion integer to check, or NULL * \returns 0 on success, or a LIBUSB_ERROR code on failure - * \ref mtasync + * \ref libusb_mtasync */ int API_EXPORTED libusb_handle_events_timeout_completed(libusb_context *ctx, struct timeval *tv, int *completed) @@ -2317,7 +2377,7 @@ already_done: return 0; } -/** \ingroup poll +/** \ingroup libusb_poll * Handle any pending events * * Like libusb_handle_events_timeout_completed(), but without the completed @@ -2339,7 +2399,7 @@ int API_EXPORTED libusb_handle_events_timeout(libusb_context *ctx, return libusb_handle_events_timeout_completed(ctx, tv, NULL); } -/** \ingroup poll +/** \ingroup libusb_poll * Handle any pending events in blocking mode. There is currently a timeout * hardcoded at 60 seconds but we plan to make it unlimited in future. For * finer control over whether this function is blocking or non-blocking, or @@ -2361,7 +2421,7 @@ int API_EXPORTED libusb_handle_events(libusb_context *ctx) return libusb_handle_events_timeout_completed(ctx, &tv, NULL); } -/** \ingroup poll +/** \ingroup libusb_poll * Handle any pending events in blocking mode. * * Like libusb_handle_events(), with the addition of a completed parameter @@ -2373,7 +2433,7 @@ int API_EXPORTED libusb_handle_events(libusb_context *ctx) * \param ctx the context to operate on, or NULL for the default context * \param completed pointer to completion integer to check, or NULL * \returns 0 on success, or a LIBUSB_ERROR code on failure - * \ref mtasync + * \ref libusb_mtasync */ int API_EXPORTED libusb_handle_events_completed(libusb_context *ctx, int *completed) @@ -2384,7 +2444,7 @@ int API_EXPORTED libusb_handle_events_completed(libusb_context *ctx, return libusb_handle_events_timeout_completed(ctx, &tv, completed); } -/** \ingroup poll +/** \ingroup libusb_poll * Handle any pending events by polling file descriptors, without checking if * any other threads are already doing so. Must be called with the event lock * held, see libusb_lock_events(). @@ -2399,7 +2459,7 @@ int API_EXPORTED libusb_handle_events_completed(libusb_context *ctx, * \param tv the maximum time to block waiting for events, or zero for * non-blocking mode * \returns 0 on success, or a LIBUSB_ERROR code on failure - * \ref mtasync + * \ref libusb_mtasync */ int API_EXPORTED libusb_handle_events_locked(libusb_context *ctx, struct timeval *tv) @@ -2417,12 +2477,12 @@ int API_EXPORTED libusb_handle_events_locked(libusb_context *ctx, return handle_events(ctx, &poll_timeout); } -/** \ingroup poll +/** \ingroup libusb_poll * Determines whether your application must apply special timing considerations * when monitoring libusb's file descriptors. * * This function is only useful for applications which retrieve and poll - * libusb's file descriptors in their own main loop (\ref pollmain). + * libusb's file descriptors in their own main loop (\ref libusb_pollmain). * * Ordinarily, libusb's event handler needs to be called into at specific * moments in time (in addition to times when there is activity on the file @@ -2443,7 +2503,7 @@ int API_EXPORTED libusb_handle_events_locked(libusb_context *ctx, * \returns 0 if you must call into libusb at times determined by * libusb_get_next_timeout(), or 1 if all timeout events are handled internally * or through regular activity on the file descriptors. - * \ref pollmain "Polling libusb file descriptors for event handling" + * \ref libusb_pollmain "Polling libusb file descriptors for event handling" */ int API_EXPORTED libusb_pollfds_handle_timeouts(libusb_context *ctx) { @@ -2451,12 +2511,12 @@ int API_EXPORTED libusb_pollfds_handle_timeouts(libusb_context *ctx) USBI_GET_CONTEXT(ctx); return usbi_using_timerfd(ctx); #else - (void)ctx; + UNUSED(ctx); return 0; #endif } -/** \ingroup poll +/** \ingroup libusb_poll * Determine the next internal timeout that libusb needs to handle. You only * need to use this function if you are calling poll() or select() or similar * on libusb's file descriptors yourself - you do not need to use it if you @@ -2506,7 +2566,7 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx, /* find next transfer which hasn't already been processed as timed out */ list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) { - if (transfer->flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT)) + if (transfer->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT)) continue; /* if we've reached transfers of infinte timeout, we're done looking */ @@ -2541,7 +2601,7 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx, return 1; } -/** \ingroup poll +/** \ingroup libusb_poll * Register notification functions for file descriptor additions/removals. * These functions will be invoked for every new or removed file descriptor * that libusb uses as an event source. @@ -2583,7 +2643,7 @@ static void usbi_fd_notification(struct libusb_context *ctx) /* Record that there is a new poll fd. * Only signal an event if there are no prior pending events. */ pending_events = usbi_pending_events(ctx); - ctx->pollfds_modified = 1; + ctx->event_flags |= USBI_EVENT_POLLFDS_MODIFIED; if (!pending_events) usbi_signal_event(ctx); } @@ -2640,7 +2700,7 @@ void usbi_remove_pollfd(struct libusb_context *ctx, int fd) ctx->fd_removed_cb(fd, ctx->fd_cb_user_data); } -/** \ingroup poll +/** \ingroup libusb_poll * Retrieve a list of file descriptors that should be polled by your main loop * as libusb event sources. * @@ -2685,7 +2745,7 @@ out: #endif } -/** \ingroup poll +/** \ingroup libusb_poll * Free a list of libusb_pollfd structures. This should be called for all * pollfd lists allocated with libusb_get_pollfds(). * @@ -2708,13 +2768,13 @@ void API_EXPORTED libusb_free_pollfds(const struct libusb_pollfd **pollfds) * device. This function ensures transfers get cancelled appropriately. * Callers of this function must hold the events_lock. */ -void usbi_handle_disconnect(struct libusb_device_handle *handle) +void usbi_handle_disconnect(struct libusb_device_handle *dev_handle) { struct usbi_transfer *cur; struct usbi_transfer *to_cancel; usbi_dbg("device %d.%d", - handle->dev->bus_number, handle->dev->device_address); + dev_handle->dev->bus_number, dev_handle->dev->device_address); /* terminate all pending transfers with the LIBUSB_TRANSFER_NO_DEVICE * status code. @@ -2723,27 +2783,26 @@ void usbi_handle_disconnect(struct libusb_device_handle *handle) * possible scenarios: * 1. the transfer is currently in-flight, in which case we terminate the * transfer here - * 2. the transfer is not in-flight (or is but hasn't been marked as such), - * in which case we record that the device disappeared and this will be - * handled by libusb_submit_transfer() + * 2. the transfer has been added to the flying transfer list by + * libusb_submit_transfer, has failed to submit and + * libusb_submit_transfer is waiting for us to release the + * flying_transfers_lock to remove it, so we ignore it */ while (1) { to_cancel = NULL; - usbi_mutex_lock(&HANDLE_CTX(handle)->flying_transfers_lock); - list_for_each_entry(cur, &HANDLE_CTX(handle)->flying_transfers, list, struct usbi_transfer) - if (USBI_TRANSFER_TO_LIBUSB_TRANSFER(cur)->dev_handle == handle) { - usbi_mutex_lock(&cur->flags_lock); - if (cur->flags & USBI_TRANSFER_IN_FLIGHT) + usbi_mutex_lock(&HANDLE_CTX(dev_handle)->flying_transfers_lock); + list_for_each_entry(cur, &HANDLE_CTX(dev_handle)->flying_transfers, list, struct usbi_transfer) + if (USBI_TRANSFER_TO_LIBUSB_TRANSFER(cur)->dev_handle == dev_handle) { + usbi_mutex_lock(&cur->lock); + if (cur->state_flags & USBI_TRANSFER_IN_FLIGHT) to_cancel = cur; - else - cur->flags |= USBI_TRANSFER_DEVICE_DISAPPEARED; - usbi_mutex_unlock(&cur->flags_lock); + usbi_mutex_unlock(&cur->lock); if (to_cancel) break; } - usbi_mutex_unlock(&HANDLE_CTX(handle)->flying_transfers_lock); + usbi_mutex_unlock(&HANDLE_CTX(dev_handle)->flying_transfers_lock); if (!to_cancel) break; diff --git a/Externals/libusb/libusb/libusb-1.0.def b/Externals/libusb/libusb/libusb-1.0.def index cbcf3e9f08..2443d9bef4 100644 --- a/Externals/libusb/libusb/libusb-1.0.def +++ b/Externals/libusb/libusb/libusb-1.0.def @@ -20,6 +20,10 @@ EXPORTS libusb_control_transfer@32 = libusb_control_transfer libusb_detach_kernel_driver libusb_detach_kernel_driver@8 = libusb_detach_kernel_driver + libusb_dev_mem_alloc + libusb_dev_mem_alloc@8 = libusb_dev_mem_alloc + libusb_dev_mem_free + libusb_dev_mem_free@12 = libusb_dev_mem_free libusb_error_name libusb_error_name@4 = libusb_error_name libusb_event_handler_active @@ -36,6 +40,8 @@ EXPORTS libusb_free_container_id_descriptor@4 = libusb_free_container_id_descriptor libusb_free_device_list libusb_free_device_list@8 = libusb_free_device_list + libusb_free_pollfds + libusb_free_pollfds@4 = libusb_free_pollfds libusb_free_ss_endpoint_companion_descriptor libusb_free_ss_endpoint_companion_descriptor@4 = libusb_free_ss_endpoint_companion_descriptor libusb_free_ss_usb_device_capability_descriptor @@ -80,8 +86,6 @@ EXPORTS libusb_get_parent@4 = libusb_get_parent libusb_get_pollfds libusb_get_pollfds@4 = libusb_get_pollfds - libusb_free_pollfds - libusb_free_pollfds@4 = libusb_free_pollfds libusb_get_port_number libusb_get_port_number@4 = libusb_get_port_number libusb_get_port_numbers @@ -116,14 +120,16 @@ EXPORTS libusb_hotplug_register_callback@36 = libusb_hotplug_register_callback libusb_init libusb_init@4 = libusb_init + libusb_interrupt_event_handler + libusb_interrupt_event_handler@4 = libusb_interrupt_event_handler libusb_interrupt_transfer libusb_interrupt_transfer@24 = libusb_interrupt_transfer libusb_kernel_driver_active libusb_kernel_driver_active@8 = libusb_kernel_driver_active - libusb_lock_event_waiters - libusb_lock_event_waiters@4 = libusb_lock_event_waiters libusb_lock_events libusb_lock_events@4 = libusb_lock_events + libusb_lock_event_waiters + libusb_lock_event_waiters@4 = libusb_lock_event_waiters libusb_open libusb_open@8 = libusb_open libusb_open_device_with_vid_pid @@ -144,10 +150,10 @@ EXPORTS libusb_set_debug@8 = libusb_set_debug libusb_set_interface_alt_setting libusb_set_interface_alt_setting@12 = libusb_set_interface_alt_setting - libusb_set_pollfd_notifiers - libusb_set_pollfd_notifiers@16 = libusb_set_pollfd_notifiers libusb_setlocale libusb_setlocale@4 = libusb_setlocale + libusb_set_pollfd_notifiers + libusb_set_pollfd_notifiers@16 = libusb_set_pollfd_notifiers libusb_strerror libusb_strerror@4 = libusb_strerror libusb_submit_transfer @@ -158,10 +164,10 @@ EXPORTS libusb_transfer_set_stream_id@8 = libusb_transfer_set_stream_id libusb_try_lock_events libusb_try_lock_events@4 = libusb_try_lock_events - libusb_unlock_event_waiters - libusb_unlock_event_waiters@4 = libusb_unlock_event_waiters libusb_unlock_events libusb_unlock_events@4 = libusb_unlock_events + libusb_unlock_event_waiters + libusb_unlock_event_waiters@4 = libusb_unlock_event_waiters libusb_unref_device libusb_unref_device@4 = libusb_unref_device libusb_wait_for_event diff --git a/Externals/libusb/libusb/libusb.h b/Externals/libusb/libusb/libusb.h index 513945f054..f73e31cc26 100644 --- a/Externals/libusb/libusb/libusb.h +++ b/Externals/libusb/libusb/libusb.h @@ -84,7 +84,7 @@ typedef unsigned __int32 uint32_t; #endif /* __GNUC__ */ /** \def LIBUSB_CALL - * \ingroup misc + * \ingroup libusb_misc * libusb's Windows calling convention. * * Under Windows, the selection of available compilers and configurations @@ -122,7 +122,7 @@ typedef unsigned __int32 uint32_t; #endif /** \def LIBUSB_API_VERSION - * \ingroup misc + * \ingroup libusb_misc * libusb's API version. * * Since version 1.0.13, to help with feature detection, libusb defines @@ -141,7 +141,7 @@ typedef unsigned __int32 uint32_t; * Internally, LIBUSB_API_VERSION is defined as follows: * (libusb major << 24) | (libusb minor << 16) | (16 bit incremental) */ -#define LIBUSB_API_VERSION 0x01000104 +#define LIBUSB_API_VERSION 0x01000105 /* The following is kept for compatibility, but will be deprecated in the future */ #define LIBUSBX_API_VERSION LIBUSB_API_VERSION @@ -151,7 +151,7 @@ extern "C" { #endif /** - * \ingroup misc + * \ingroup libusb_misc * Convert a 16-bit value from host-endian to little-endian format. On * little endian systems, this function does nothing. On big endian systems, * the bytes are swapped. @@ -170,7 +170,7 @@ static inline uint16_t libusb_cpu_to_le16(const uint16_t x) } /** \def libusb_le16_to_cpu - * \ingroup misc + * \ingroup libusb_misc * Convert a 16-bit value from little-endian to host-endian format. On * little endian systems, this function does nothing. On big endian systems, * the bytes are swapped. @@ -181,7 +181,7 @@ static inline uint16_t libusb_cpu_to_le16(const uint16_t x) /* standard USB stuff */ -/** \ingroup desc +/** \ingroup libusb_desc * Device and/or Interface Class codes */ enum libusb_class_code { /** In the context of a \ref libusb_device_descriptor "device descriptor", @@ -243,7 +243,7 @@ enum libusb_class_code { LIBUSB_CLASS_VENDOR_SPEC = 0xff }; -/** \ingroup desc +/** \ingroup libusb_desc * Descriptor types as defined by the USB specification. */ enum libusb_descriptor_type { /** Device descriptor. See libusb_device_descriptor. */ @@ -311,7 +311,7 @@ enum libusb_descriptor_type { #define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */ #define LIBUSB_ENDPOINT_DIR_MASK 0x80 -/** \ingroup desc +/** \ingroup libusb_desc * Endpoint direction. Values for bit 7 of the * \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme. */ @@ -325,7 +325,7 @@ enum libusb_endpoint_direction { #define LIBUSB_TRANSFER_TYPE_MASK 0x03 /* in bmAttributes */ -/** \ingroup desc +/** \ingroup libusb_desc * Endpoint transfer type. Values for bits 0:1 of the * \ref libusb_endpoint_descriptor::bmAttributes "endpoint attributes" field. */ @@ -346,7 +346,7 @@ enum libusb_transfer_type { LIBUSB_TRANSFER_TYPE_BULK_STREAM = 4, }; -/** \ingroup misc +/** \ingroup libusb_misc * Standard requests, as defined in table 9-5 of the USB 3.0 specifications */ enum libusb_standard_request { /** Request status of the specific recipient */ @@ -394,7 +394,7 @@ enum libusb_standard_request { LIBUSB_SET_ISOCH_DELAY = 0x31, }; -/** \ingroup misc +/** \ingroup libusb_misc * Request type bits of the * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control * transfers. */ @@ -412,7 +412,7 @@ enum libusb_request_type { LIBUSB_REQUEST_TYPE_RESERVED = (0x03 << 5) }; -/** \ingroup misc +/** \ingroup libusb_misc * Recipient bits of the * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control * transfers. Values 4 through 31 are reserved. */ @@ -432,7 +432,7 @@ enum libusb_request_recipient { #define LIBUSB_ISO_SYNC_TYPE_MASK 0x0C -/** \ingroup desc +/** \ingroup libusb_desc * Synchronization type for isochronous endpoints. Values for bits 2:3 of the * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in * libusb_endpoint_descriptor. @@ -453,7 +453,7 @@ enum libusb_iso_sync_type { #define LIBUSB_ISO_USAGE_TYPE_MASK 0x30 -/** \ingroup desc +/** \ingroup libusb_desc * Usage type for isochronous endpoints. Values for bits 4:5 of the * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in * libusb_endpoint_descriptor. @@ -469,7 +469,7 @@ enum libusb_iso_usage_type { LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 2, }; -/** \ingroup desc +/** \ingroup libusb_desc * A structure representing the standard USB device descriptor. This * descriptor is documented in section 9.6.1 of the USB 3.0 specification. * All multiple-byte fields are represented in host-endian format. @@ -523,7 +523,7 @@ struct libusb_device_descriptor { uint8_t bNumConfigurations; }; -/** \ingroup desc +/** \ingroup libusb_desc * A structure representing the standard USB endpoint descriptor. This * descriptor is documented in section 9.6.6 of the USB 3.0 specification. * All multiple-byte fields are represented in host-endian format. @@ -573,7 +573,7 @@ struct libusb_endpoint_descriptor { int extra_length; }; -/** \ingroup desc +/** \ingroup libusb_desc * A structure representing the standard USB interface descriptor. This * descriptor is documented in section 9.6.5 of the USB 3.0 specification. * All multiple-byte fields are represented in host-endian format. @@ -623,7 +623,7 @@ struct libusb_interface_descriptor { int extra_length; }; -/** \ingroup desc +/** \ingroup libusb_desc * A collection of alternate settings for a particular USB interface. */ struct libusb_interface { @@ -635,7 +635,7 @@ struct libusb_interface { int num_altsetting; }; -/** \ingroup desc +/** \ingroup libusb_desc * A structure representing the standard USB configuration descriptor. This * descriptor is documented in section 9.6.3 of the USB 3.0 specification. * All multiple-byte fields are represented in host-endian format. @@ -682,7 +682,7 @@ struct libusb_config_descriptor { int extra_length; }; -/** \ingroup desc +/** \ingroup libusb_desc * A structure representing the superspeed endpoint companion * descriptor. This descriptor is documented in section 9.6.7 of * the USB 3.0 specification. All multiple-byte fields are represented in @@ -700,7 +700,7 @@ struct libusb_ss_endpoint_companion_descriptor { /** The maximum number of packets the endpoint can send or - * recieve as part of a burst. */ + * receive as part of a burst. */ uint8_t bMaxBurst; /** In bulk EP: bits 4:0 represents the maximum number of @@ -714,7 +714,7 @@ struct libusb_ss_endpoint_companion_descriptor { uint16_t wBytesPerInterval; }; -/** \ingroup desc +/** \ingroup libusb_desc * A generic representation of a BOS Device Capability descriptor. It is * advised to check bDevCapabilityType and call the matching * libusb_get_*_descriptor function to get a structure fully matching the type. @@ -738,7 +738,7 @@ struct libusb_bos_dev_capability_descriptor { ; }; -/** \ingroup desc +/** \ingroup libusb_desc * A structure representing the Binary Device Object Store (BOS) descriptor. * This descriptor is documented in section 9.6.2 of the USB 3.0 specification. * All multiple-byte fields are represented in host-endian format. @@ -769,7 +769,7 @@ struct libusb_bos_descriptor { ; }; -/** \ingroup desc +/** \ingroup libusb_desc * A structure representing the USB 2.0 Extension descriptor * This descriptor is documented in section 9.6.2.1 of the USB 3.0 specification. * All multiple-byte fields are represented in host-endian format. @@ -795,7 +795,7 @@ struct libusb_usb_2_0_extension_descriptor { uint32_t bmAttributes; }; -/** \ingroup desc +/** \ingroup libusb_desc * A structure representing the SuperSpeed USB Device Capability descriptor * This descriptor is documented in section 9.6.2.2 of the USB 3.0 specification. * All multiple-byte fields are represented in host-endian format. @@ -837,7 +837,7 @@ struct libusb_ss_usb_device_capability_descriptor { uint16_t bU2DevExitLat; }; -/** \ingroup desc +/** \ingroup libusb_desc * A structure representing the Container ID descriptor. * This descriptor is documented in section 9.6.2.3 of the USB 3.0 specification. * All multiple-byte fields, except UUIDs, are represented in host-endian format. @@ -863,7 +863,7 @@ struct libusb_container_id_descriptor { uint8_t ContainerID[16]; }; -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Setup packet for control transfers. */ struct libusb_control_setup { /** Request type. Bits 0:4 determine recipient, see @@ -899,7 +899,7 @@ struct libusb_context; struct libusb_device; struct libusb_device_handle; -/** \ingroup lib +/** \ingroup libusb_lib * Structure providing the version of the libusb runtime */ struct libusb_version { @@ -922,7 +922,7 @@ struct libusb_version { const char* describe; }; -/** \ingroup lib +/** \ingroup libusb_lib * Structure representing a libusb session. The concept of individual libusb * sessions allows for your program to use two libraries (or dynamically * load two modules) which both independently use libusb. This will prevent @@ -937,11 +937,11 @@ struct libusb_version { * every function call where a context is required. The default context * will be used. * - * For more information, see \ref contexts. + * For more information, see \ref libusb_contexts. */ typedef struct libusb_context libusb_context; -/** \ingroup dev +/** \ingroup libusb_dev * Structure representing a USB device detected on the system. This is an * opaque type for which you are only ever provided with a pointer, usually * originating from libusb_get_device_list(). @@ -959,7 +959,7 @@ typedef struct libusb_context libusb_context; typedef struct libusb_device libusb_device; -/** \ingroup dev +/** \ingroup libusb_dev * Structure representing a handle on a USB device. This is an opaque type for * which you are only ever provided with a pointer, usually originating from * libusb_open(). @@ -969,7 +969,7 @@ typedef struct libusb_device libusb_device; */ typedef struct libusb_device_handle libusb_device_handle; -/** \ingroup dev +/** \ingroup libusb_dev * Speed codes. Indicates the speed at which the device is operating. */ enum libusb_speed { @@ -989,7 +989,7 @@ enum libusb_speed { LIBUSB_SPEED_SUPER = 4, }; -/** \ingroup dev +/** \ingroup libusb_dev * Supported speeds (wSpeedSupported) bitfield. Indicates what * speeds the device supports. */ @@ -1007,7 +1007,7 @@ enum libusb_supported_speed { LIBUSB_SUPER_SPEED_OPERATION = 8, }; -/** \ingroup dev +/** \ingroup libusb_dev * Masks for the bits of the * \ref libusb_usb_2_0_extension_descriptor::bmAttributes "bmAttributes" field * of the USB 2.0 Extension descriptor. @@ -1017,7 +1017,7 @@ enum libusb_usb_2_0_extension_attributes { LIBUSB_BM_LPM_SUPPORT = 2, }; -/** \ingroup dev +/** \ingroup libusb_dev * Masks for the bits of the * \ref libusb_ss_usb_device_capability_descriptor::bmAttributes "bmAttributes" field * field of the SuperSpeed USB Device Capability descriptor. @@ -1027,7 +1027,7 @@ enum libusb_ss_usb_device_capability_attributes { LIBUSB_BM_LTM_SUPPORT = 2, }; -/** \ingroup dev +/** \ingroup libusb_dev * USB capability types */ enum libusb_bos_type { @@ -1044,7 +1044,7 @@ enum libusb_bos_type { LIBUSB_BT_CONTAINER_ID = 4, }; -/** \ingroup misc +/** \ingroup libusb_misc * Error codes. Most libusb functions return 0 on success or one of these * codes on failure. * You can call libusb_error_name() to retrieve a string representation of an @@ -1101,7 +1101,7 @@ enum libusb_error { /* Total number of error codes in enum libusb_error */ #define LIBUSB_ERROR_COUNT 14 -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Transfer status codes */ enum libusb_transfer_status { /** Transfer completed without error. Note that this does not indicate @@ -1131,13 +1131,16 @@ enum libusb_transfer_status { when adding new status codes here. */ }; -/** \ingroup asyncio +/** \ingroup libusb_asyncio * libusb_transfer.flags values */ enum libusb_transfer_flags { /** Report short frames as errors */ LIBUSB_TRANSFER_SHORT_NOT_OK = 1<<0, - /** Automatically free() transfer buffer during libusb_free_transfer() */ + /** Automatically free() transfer buffer during libusb_free_transfer(). + * Note that buffers allocated with libusb_dev_mem_alloc() should not + * be attempted freed in this way, since free() is not an appropriate + * way to release such memory. */ LIBUSB_TRANSFER_FREE_BUFFER = 1<<1, /** Automatically call libusb_free_transfer() after callback returns. @@ -1172,7 +1175,7 @@ enum libusb_transfer_flags { LIBUSB_TRANSFER_ADD_ZERO_PACKET = 1 << 3, }; -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Isochronous packet descriptor. */ struct libusb_iso_packet_descriptor { /** Length of data to request in this packet */ @@ -1187,18 +1190,18 @@ struct libusb_iso_packet_descriptor { struct libusb_transfer; -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Asynchronous transfer callback function type. When submitting asynchronous * transfers, you pass a pointer to a callback function of this type via the * \ref libusb_transfer::callback "callback" member of the libusb_transfer * structure. libusb will call this function later, when the transfer has - * completed or failed. See \ref asyncio for more information. + * completed or failed. See \ref libusb_asyncio for more information. * \param transfer The libusb_transfer struct the callback function is being * notified about. */ typedef void (LIBUSB_CALL *libusb_transfer_cb_fn)(struct libusb_transfer *transfer); -/** \ingroup asyncio +/** \ingroup libusb_asyncio * The generic USB transfer structure. The user populates this structure and * then submits it in order to request a transfer. After the transfer has * completed, the library populates the transfer with the results and passes @@ -1262,7 +1265,7 @@ struct libusb_transfer { ; }; -/** \ingroup misc +/** \ingroup libusb_misc * Capabilities supported by an instance of libusb on the current running * platform. Test if the loaded library supports a given capability by calling * \ref libusb_has_capability(). @@ -1282,7 +1285,7 @@ enum libusb_capability { LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER = 0x0101 }; -/** \ingroup lib +/** \ingroup libusb_lib * Log message levels. * - LIBUSB_LOG_LEVEL_NONE (0) : no messages ever printed by the library (default) * - LIBUSB_LOG_LEVEL_ERROR (1) : error messages are printed to stderr @@ -1334,7 +1337,7 @@ int LIBUSB_CALL libusb_get_ss_endpoint_companion_descriptor( struct libusb_ss_endpoint_companion_descriptor **ep_comp); void LIBUSB_CALL libusb_free_ss_endpoint_companion_descriptor( struct libusb_ss_endpoint_companion_descriptor *ep_comp); -int LIBUSB_CALL libusb_get_bos_descriptor(libusb_device_handle *handle, +int LIBUSB_CALL libusb_get_bos_descriptor(libusb_device_handle *dev_handle, struct libusb_bos_descriptor **bos); void LIBUSB_CALL libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos); int LIBUSB_CALL libusb_get_usb_2_0_extension_descriptor( @@ -1367,43 +1370,48 @@ int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev, int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev, unsigned char endpoint); -int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **handle); +int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **dev_handle); void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle); libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle); -int LIBUSB_CALL libusb_set_configuration(libusb_device_handle *dev, +int LIBUSB_CALL libusb_set_configuration(libusb_device_handle *dev_handle, int configuration); -int LIBUSB_CALL libusb_claim_interface(libusb_device_handle *dev, +int LIBUSB_CALL libusb_claim_interface(libusb_device_handle *dev_handle, int interface_number); -int LIBUSB_CALL libusb_release_interface(libusb_device_handle *dev, +int LIBUSB_CALL libusb_release_interface(libusb_device_handle *dev_handle, int interface_number); libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid( libusb_context *ctx, uint16_t vendor_id, uint16_t product_id); -int LIBUSB_CALL libusb_set_interface_alt_setting(libusb_device_handle *dev, +int LIBUSB_CALL libusb_set_interface_alt_setting(libusb_device_handle *dev_handle, int interface_number, int alternate_setting); -int LIBUSB_CALL libusb_clear_halt(libusb_device_handle *dev, +int LIBUSB_CALL libusb_clear_halt(libusb_device_handle *dev_handle, unsigned char endpoint); -int LIBUSB_CALL libusb_reset_device(libusb_device_handle *dev); +int LIBUSB_CALL libusb_reset_device(libusb_device_handle *dev_handle); -int LIBUSB_CALL libusb_alloc_streams(libusb_device_handle *dev, +int LIBUSB_CALL libusb_alloc_streams(libusb_device_handle *dev_handle, uint32_t num_streams, unsigned char *endpoints, int num_endpoints); -int LIBUSB_CALL libusb_free_streams(libusb_device_handle *dev, +int LIBUSB_CALL libusb_free_streams(libusb_device_handle *dev_handle, unsigned char *endpoints, int num_endpoints); -int LIBUSB_CALL libusb_kernel_driver_active(libusb_device_handle *dev, +unsigned char * LIBUSB_CALL libusb_dev_mem_alloc(libusb_device_handle *dev_handle, + size_t length); +int LIBUSB_CALL libusb_dev_mem_free(libusb_device_handle *dev_handle, + unsigned char *buffer, size_t length); + +int LIBUSB_CALL libusb_kernel_driver_active(libusb_device_handle *dev_handle, int interface_number); -int LIBUSB_CALL libusb_detach_kernel_driver(libusb_device_handle *dev, +int LIBUSB_CALL libusb_detach_kernel_driver(libusb_device_handle *dev_handle, int interface_number); -int LIBUSB_CALL libusb_attach_kernel_driver(libusb_device_handle *dev, +int LIBUSB_CALL libusb_attach_kernel_driver(libusb_device_handle *dev_handle, int interface_number); int LIBUSB_CALL libusb_set_auto_detach_kernel_driver( - libusb_device_handle *dev, int enable); + libusb_device_handle *dev_handle, int enable); /* async I/O */ -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Get the data section of a control transfer. This convenience function is here * to remind you that the data does not start until 8 bytes into the actual * buffer, as the setup packet comes first. @@ -1421,7 +1429,7 @@ static inline unsigned char *libusb_control_transfer_get_data( return transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE; } -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Get the control setup packet of a control transfer. This convenience * function is here to remind you that the control setup occupies the first * 8 bytes of the transfer data buffer. @@ -1439,7 +1447,7 @@ static inline struct libusb_control_setup *libusb_control_transfer_get_setup( return (struct libusb_control_setup *)(void *) transfer->buffer; } -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Helper function to populate the setup packet (first 8 bytes of the data * buffer) for a control transfer. The wIndex, wValue and wLength values should * be given in host-endian byte order. @@ -1483,7 +1491,7 @@ void LIBUSB_CALL libusb_transfer_set_stream_id( uint32_t LIBUSB_CALL libusb_transfer_get_stream_id( struct libusb_transfer *transfer); -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Helper function to populate the required \ref libusb_transfer fields * for a control transfer. * @@ -1529,7 +1537,7 @@ static inline void libusb_fill_control_transfer( transfer->callback = callback; } -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Helper function to populate the required \ref libusb_transfer fields * for a bulk transfer. * @@ -1557,7 +1565,7 @@ static inline void libusb_fill_bulk_transfer(struct libusb_transfer *transfer, transfer->callback = callback; } -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Helper function to populate the required \ref libusb_transfer fields * for a bulk transfer using bulk streams. * @@ -1585,7 +1593,7 @@ static inline void libusb_fill_bulk_stream_transfer( libusb_transfer_set_stream_id(transfer, stream_id); } -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Helper function to populate the required \ref libusb_transfer fields * for an interrupt transfer. * @@ -1613,7 +1621,7 @@ static inline void libusb_fill_interrupt_transfer( transfer->callback = callback; } -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Helper function to populate the required \ref libusb_transfer fields * for an isochronous transfer. * @@ -1643,7 +1651,7 @@ static inline void libusb_fill_iso_transfer(struct libusb_transfer *transfer, transfer->callback = callback; } -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Convenience function to set the length of all packets in an isochronous * transfer, based on the num_iso_packets field in the transfer structure. * @@ -1659,7 +1667,7 @@ static inline void libusb_set_iso_packet_lengths( transfer->iso_packet_desc[i].length = length; } -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Convenience function to locate the position of an isochronous packet * within the buffer of an isochronous transfer. * @@ -1698,7 +1706,7 @@ static inline unsigned char *libusb_get_iso_packet_buffer( return transfer->buffer + offset; } -/** \ingroup asyncio +/** \ingroup libusb_asyncio * Convenience function to locate the position of an isochronous packet * within the buffer of an isochronous transfer, for transfers where each * packet is of identical size. @@ -1749,33 +1757,33 @@ int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle *dev_handle, unsigned char endpoint, unsigned char *data, int length, int *actual_length, unsigned int timeout); -/** \ingroup desc +/** \ingroup libusb_desc * Retrieve a descriptor from the default control pipe. * This is a convenience function which formulates the appropriate control * message to retrieve the descriptor. * - * \param dev a device handle + * \param dev_handle a device handle * \param desc_type the descriptor type, see \ref libusb_descriptor_type * \param desc_index the index of the descriptor to retrieve * \param data output buffer for descriptor * \param length size of data buffer * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure */ -static inline int libusb_get_descriptor(libusb_device_handle *dev, +static inline int libusb_get_descriptor(libusb_device_handle *dev_handle, uint8_t desc_type, uint8_t desc_index, unsigned char *data, int length) { - return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, + return libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR, (uint16_t) ((desc_type << 8) | desc_index), 0, data, (uint16_t) length, 1000); } -/** \ingroup desc +/** \ingroup libusb_desc * Retrieve a descriptor from a device. * This is a convenience function which formulates the appropriate control * message to retrieve the descriptor. The string returned is Unicode, as * detailed in the USB specifications. * - * \param dev a device handle + * \param dev_handle a device handle * \param desc_index the index of the descriptor to retrieve * \param langid the language ID for the string descriptor * \param data output buffer for descriptor @@ -1783,15 +1791,15 @@ static inline int libusb_get_descriptor(libusb_device_handle *dev, * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure * \see libusb_get_string_descriptor_ascii() */ -static inline int libusb_get_string_descriptor(libusb_device_handle *dev, +static inline int libusb_get_string_descriptor(libusb_device_handle *dev_handle, uint8_t desc_index, uint16_t langid, unsigned char *data, int length) { - return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, + return libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR, (uint16_t)((LIBUSB_DT_STRING << 8) | desc_index), langid, data, (uint16_t) length, 1000); } -int LIBUSB_CALL libusb_get_string_descriptor_ascii(libusb_device_handle *dev, +int LIBUSB_CALL libusb_get_string_descriptor_ascii(libusb_device_handle *dev_handle, uint8_t desc_index, unsigned char *data, int length); /* polling and timeouts */ @@ -1801,6 +1809,7 @@ void LIBUSB_CALL libusb_lock_events(libusb_context *ctx); void LIBUSB_CALL libusb_unlock_events(libusb_context *ctx); int LIBUSB_CALL libusb_event_handling_ok(libusb_context *ctx); int LIBUSB_CALL libusb_event_handler_active(libusb_context *ctx); +void LIBUSB_CALL libusb_interrupt_event_handler(libusb_context *ctx); void LIBUSB_CALL libusb_lock_event_waiters(libusb_context *ctx); void LIBUSB_CALL libusb_unlock_event_waiters(libusb_context *ctx); int LIBUSB_CALL libusb_wait_for_event(libusb_context *ctx, struct timeval *tv); @@ -1817,7 +1826,7 @@ int LIBUSB_CALL libusb_pollfds_handle_timeouts(libusb_context *ctx); int LIBUSB_CALL libusb_get_next_timeout(libusb_context *ctx, struct timeval *tv); -/** \ingroup poll +/** \ingroup libusb_poll * File descriptor for polling */ struct libusb_pollfd { @@ -1831,7 +1840,7 @@ struct libusb_pollfd { short events; }; -/** \ingroup poll +/** \ingroup libusb_poll * Callback function, invoked when a new file descriptor should be added * to the set of file descriptors monitored for events. * \param fd the new file descriptor @@ -1844,7 +1853,7 @@ struct libusb_pollfd { typedef void (LIBUSB_CALL *libusb_pollfd_added_cb)(int fd, short events, void *user_data); -/** \ingroup poll +/** \ingroup libusb_poll * Callback function, invoked when a file descriptor should be removed from * the set of file descriptors being monitored for events. After returning * from this callback, do not use that file descriptor again. @@ -1862,7 +1871,7 @@ void LIBUSB_CALL libusb_set_pollfd_notifiers(libusb_context *ctx, libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, void *user_data); -/** \ingroup hotplug +/** \ingroup libusb_hotplug * Callback handle. * * Callbacks handles are generated by libusb_hotplug_register_callback() @@ -1872,11 +1881,11 @@ void LIBUSB_CALL libusb_set_pollfd_notifiers(libusb_context *ctx, * * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 * - * For more information, see \ref hotplug. + * For more information, see \ref libusb_hotplug. */ typedef int libusb_hotplug_callback_handle; -/** \ingroup hotplug +/** \ingroup libusb_hotplug * * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 * @@ -1889,7 +1898,7 @@ typedef enum { LIBUSB_HOTPLUG_ENUMERATE = 1<<0, } libusb_hotplug_flag; -/** \ingroup hotplug +/** \ingroup libusb_hotplug * * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 * @@ -1904,11 +1913,11 @@ typedef enum { LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT = 0x02, } libusb_hotplug_event; -/** \ingroup hotplug +/** \ingroup libusb_hotplug * Wildcard matching for hotplug events */ #define LIBUSB_HOTPLUG_MATCH_ANY -1 -/** \ingroup hotplug +/** \ingroup libusb_hotplug * Hotplug callback function type. When requesting hotplug event notifications, * you pass a pointer to a callback function of this type. * @@ -1916,7 +1925,7 @@ typedef enum { * recommended the callback do minimal processing before returning. * * libusb will call this function later, when a matching event had happened on - * a matching device. See \ref hotplug for more information. + * a matching device. See \ref libusb_hotplug for more information. * * It is safe to call either libusb_hotplug_register_callback() or * libusb_hotplug_deregister_callback() from within a callback function. @@ -1935,7 +1944,7 @@ typedef int (LIBUSB_CALL *libusb_hotplug_callback_fn)(libusb_context *ctx, libusb_hotplug_event event, void *user_data); -/** \ingroup hotplug +/** \ingroup libusb_hotplug * Register a hotplug callback function * * Register a callback with the libusb_context. The callback will fire @@ -1966,7 +1975,7 @@ typedef int (LIBUSB_CALL *libusb_hotplug_callback_fn)(libusb_context *ctx, * \param[in] dev_class the device class to match or \ref LIBUSB_HOTPLUG_MATCH_ANY * \param[in] cb_fn the function to be invoked on a matching event/device * \param[in] user_data user data to pass to the callback function - * \param[out] handle pointer to store the handle of the allocated callback (can be NULL) + * \param[out] callback_handle pointer to store the handle of the allocated callback (can be NULL) * \returns LIBUSB_SUCCESS on success LIBUSB_ERROR code on failure */ int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context *ctx, @@ -1976,9 +1985,9 @@ int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context *ctx, int dev_class, libusb_hotplug_callback_fn cb_fn, void *user_data, - libusb_hotplug_callback_handle *handle); + libusb_hotplug_callback_handle *callback_handle); -/** \ingroup hotplug +/** \ingroup libusb_hotplug * Deregisters a hotplug callback. * * Deregister a callback from a libusb_context. This function is safe to call from within @@ -1987,10 +1996,10 @@ int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context *ctx, * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 * * \param[in] ctx context this callback is registered with - * \param[in] handle the handle of the callback to deregister + * \param[in] callback_handle the handle of the callback to deregister */ void LIBUSB_CALL libusb_hotplug_deregister_callback(libusb_context *ctx, - libusb_hotplug_callback_handle handle); + libusb_hotplug_callback_handle callback_handle); #ifdef __cplusplus } diff --git a/Externals/libusb/libusb/libusbi.h b/Externals/libusb/libusb/libusbi.h index 822612e560..cc0906c199 100644 --- a/Externals/libusb/libusb/libusbi.h +++ b/Externals/libusb/libusb/libusbi.h @@ -52,14 +52,14 @@ extern "C" { #endif -#define DEVICE_DESC_LENGTH 18 +#define DEVICE_DESC_LENGTH 18 #define USB_MAXENDPOINTS 32 #define USB_MAXINTERFACES 32 #define USB_MAXCONFIG 8 /* Backend specific capabilities */ -#define USBI_CAP_HAS_HID_ACCESS 0x00010000 +#define USBI_CAP_HAS_HID_ACCESS 0x00010000 #define USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER 0x00020000 /* Maximum number of bytes in a log line */ @@ -68,10 +68,10 @@ extern "C" { #define USBI_LOG_LINE_END "\n" /* The following is used to silence warnings for unused variables */ -#define UNUSED(var) do { (void)(var); } while(0) +#define UNUSED(var) do { (void)(var); } while(0) #if !defined(ARRAYSIZE) -#define ARRAYSIZE(array) (sizeof(array)/sizeof(array[0])) +#define ARRAYSIZE(array) (sizeof(array) / sizeof(array[0])) #endif struct list_head { @@ -96,14 +96,14 @@ struct list_head { * type - the type of the first parameter */ #define list_for_each_entry(pos, head, member, type) \ - for (pos = list_entry((head)->next, type, member); \ - &pos->member != (head); \ + for (pos = list_entry((head)->next, type, member); \ + &pos->member != (head); \ pos = list_entry(pos->member.next, type, member)) -#define list_for_each_entry_safe(pos, n, head, member, type) \ - for (pos = list_entry((head)->next, type, member), \ - n = list_entry(pos->member.next, type, member); \ - &pos->member != (head); \ +#define list_for_each_entry_safe(pos, n, head, member, type) \ + for (pos = list_entry((head)->next, type, member), \ + n = list_entry(pos->member.next, type, member); \ + &pos->member != (head); \ pos = n, n = list_entry(n->member.next, type, member)) #define list_empty(entry) ((entry)->next == (entry)) @@ -147,9 +147,9 @@ static inline void *usbi_reallocf(void *ptr, size_t size) return ret; } -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *mptr = (ptr); \ - (type *)( (char *)mptr - offsetof(type,member) );}) +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *mptr = (ptr); \ + (type *)( (char *)mptr - offsetof(type,member) );}) #ifndef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) @@ -160,13 +160,19 @@ static inline void *usbi_reallocf(void *ptr, size_t size) #define TIMESPEC_IS_SET(ts) ((ts)->tv_sec != 0 || (ts)->tv_nsec != 0) +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +#define TIMEVAL_TV_SEC_TYPE long +#else +#define TIMEVAL_TV_SEC_TYPE time_t +#endif + /* Some platforms don't have this define */ #ifndef TIMESPEC_TO_TIMEVAL -#define TIMESPEC_TO_TIMEVAL(tv, ts) \ - do { \ - (tv)->tv_sec = (ts)->tv_sec; \ - (tv)->tv_usec = (ts)->tv_nsec / 1000; \ - } while (0) +#define TIMESPEC_TO_TIMEVAL(tv, ts) \ + do { \ + (tv)->tv_sec = (TIMEVAL_TV_SEC_TYPE) (ts)->tv_sec; \ + (tv)->tv_usec = (ts)->tv_nsec / 1000; \ + } while (0) #endif void usbi_log(struct libusb_context *ctx, enum libusb_log_level level, @@ -192,49 +198,54 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, #else /* !defined(_MSC_VER) || _MSC_VER >= 1400 */ #ifdef ENABLE_LOGGING -#define LOG_BODY(ctxt, level) \ -{ \ - va_list args; \ - va_start (args, format); \ - usbi_log_v(ctxt, level, "", format, args); \ - va_end(args); \ +#define LOG_BODY(ctxt, level) \ +{ \ + va_list args; \ + va_start(args, format); \ + usbi_log_v(ctxt, level, "", format, args); \ + va_end(args); \ } #else -#define LOG_BODY(ctxt, level) do { (void)(ctxt); } while(0) +#define LOG_BODY(ctxt, level) \ +{ \ + (void)(ctxt); \ +} #endif -static inline void usbi_info(struct libusb_context *ctx, const char *format, - ...) - LOG_BODY(ctx,LIBUSB_LOG_LEVEL_INFO) -static inline void usbi_warn(struct libusb_context *ctx, const char *format, - ...) - LOG_BODY(ctx,LIBUSB_LOG_LEVEL_WARNING) -static inline void usbi_err( struct libusb_context *ctx, const char *format, - ...) - LOG_BODY(ctx,LIBUSB_LOG_LEVEL_ERROR) +static inline void usbi_info(struct libusb_context *ctx, const char *format, ...) + LOG_BODY(ctx, LIBUSB_LOG_LEVEL_INFO) +static inline void usbi_warn(struct libusb_context *ctx, const char *format, ...) + LOG_BODY(ctx, LIBUSB_LOG_LEVEL_WARNING) +static inline void usbi_err(struct libusb_context *ctx, const char *format, ...) + LOG_BODY(ctx, LIBUSB_LOG_LEVEL_ERROR) static inline void usbi_dbg(const char *format, ...) - LOG_BODY(NULL,LIBUSB_LOG_LEVEL_DEBUG) + LOG_BODY(NULL, LIBUSB_LOG_LEVEL_DEBUG) #endif /* !defined(_MSC_VER) || _MSC_VER >= 1400 */ -#define USBI_GET_CONTEXT(ctx) if (!(ctx)) (ctx) = usbi_default_context -#define DEVICE_CTX(dev) ((dev)->ctx) -#define HANDLE_CTX(handle) (DEVICE_CTX((handle)->dev)) -#define TRANSFER_CTX(transfer) (HANDLE_CTX((transfer)->dev_handle)) +#define USBI_GET_CONTEXT(ctx) \ + do { \ + if (!(ctx)) \ + (ctx) = usbi_default_context; \ + } while(0) + +#define DEVICE_CTX(dev) ((dev)->ctx) +#define HANDLE_CTX(handle) (DEVICE_CTX((handle)->dev)) +#define TRANSFER_CTX(transfer) (HANDLE_CTX((transfer)->dev_handle)) #define ITRANSFER_CTX(transfer) \ (TRANSFER_CTX(USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer))) -#define IS_EPIN(ep) (0 != ((ep) & LIBUSB_ENDPOINT_IN)) -#define IS_EPOUT(ep) (!IS_EPIN(ep)) -#define IS_XFERIN(xfer) (0 != ((xfer)->endpoint & LIBUSB_ENDPOINT_IN)) -#define IS_XFEROUT(xfer) (!IS_XFERIN(xfer)) +#define IS_EPIN(ep) (0 != ((ep) & LIBUSB_ENDPOINT_IN)) +#define IS_EPOUT(ep) (!IS_EPIN(ep)) +#define IS_XFERIN(xfer) (0 != ((xfer)->endpoint & LIBUSB_ENDPOINT_IN)) +#define IS_XFEROUT(xfer) (!IS_XFERIN(xfer)) /* Internal abstraction for thread synchronization */ #if defined(THREADS_POSIX) #include "os/threads_posix.h" #elif defined(OS_WINDOWS) || defined(OS_WINCE) -#include +#include "os/threads_windows.h" #endif extern struct libusb_context *usbi_default_context; @@ -266,6 +277,8 @@ struct libusb_context { * the list, URBs that will time out later are placed after, and urbs with * infinite timeout are always placed at the very end. */ struct list_head flying_transfers; + /* Note paths taking both this and usbi_transfer->lock must always + * take this lock first */ usbi_mutex_t flying_transfers_lock; /* user callbacks for pollfd changes */ @@ -279,6 +292,10 @@ struct libusb_context { /* used to see if there is an active thread doing event handling */ int event_handler_active; + /* A thread-local storage key to track which thread is performing event + * handling */ + usbi_tls_key_t event_handling_key; + /* used to wait for event completion in threads other than the one that is * event handling */ usbi_mutex_t event_waiters_lock; @@ -287,18 +304,19 @@ struct libusb_context { /* A lock to protect internal context event data. */ usbi_mutex_t event_data_lock; + /* A bitmask of flags that are set to indicate specific events that need to + * be handled. Protected by event_data_lock. */ + unsigned int event_flags; + /* A counter that is set when we want to interrupt and prevent event handling, * in order to safely close a device. Protected by event_data_lock. */ unsigned int device_close; /* list and count of poll fds and an array of poll fd structures that is - * (re)allocated as necessary prior to polling, and a flag to indicate - * when the list of poll fds has changed since the last poll. - * Protected by event_data_lock. */ + * (re)allocated as necessary prior to polling. Protected by event_data_lock. */ struct list_head ipollfds; struct pollfd *pollfds; POLL_NFDS_TYPE pollfds_cnt; - unsigned int pollfds_modified; /* A list of pending hotplug messages. Protected by event_data_lock. */ struct list_head hotplug_msgs; @@ -315,9 +333,27 @@ struct libusb_context { struct list_head list; }; +enum usbi_event_flags { + /* The list of pollfds has been modified */ + USBI_EVENT_POLLFDS_MODIFIED = 1 << 0, + + /* The user has interrupted the event handler */ + USBI_EVENT_USER_INTERRUPT = 1 << 1, +}; + +/* Macros for managing event handling state */ +#define usbi_handling_events(ctx) \ + (usbi_tls_key_get((ctx)->event_handling_key) != NULL) + +#define usbi_start_event_handling(ctx) \ + usbi_tls_key_set((ctx)->event_handling_key, ctx) + +#define usbi_end_event_handling(ctx) \ + usbi_tls_key_set((ctx)->event_handling_key, NULL) + /* Update the following macro if new event sources are added */ #define usbi_pending_events(ctx) \ - ((ctx)->device_close || (ctx)->pollfds_modified \ + ((ctx)->event_flags || (ctx)->device_close \ || !list_empty(&(ctx)->hotplug_msgs) || !list_empty(&(ctx)->completed_transfers)) #ifdef USBI_TIMERFD_AVAILABLE @@ -353,7 +389,11 @@ struct libusb_device { #else [0] /* non-standard, but usually working code */ #endif +#if defined(OS_SUNOS) + __attribute__ ((aligned (8))); +#else ; +#endif }; struct libusb_device_handle { @@ -370,12 +410,16 @@ struct libusb_device_handle { #else [0] /* non-standard, but usually working code */ #endif +#if defined(OS_SUNOS) + __attribute__ ((aligned (8))); +#else ; +#endif }; enum { - USBI_CLOCK_MONOTONIC, - USBI_CLOCK_REALTIME + USBI_CLOCK_MONOTONIC, + USBI_CLOCK_REALTIME }; /* in-memory transfer layout: @@ -398,7 +442,8 @@ struct usbi_transfer { struct timeval timeout; int transferred; uint32_t stream_id; - uint8_t flags; + uint8_t state_flags; /* Protected by usbi_transfer->lock */ + uint8_t timeout_flags; /* Protected by the flying_stransfers_lock */ /* this lock is held during libusb_submit_transfer() and * libusb_cancel_transfer() (allowing the OS backend to prevent duplicate @@ -406,45 +451,39 @@ struct usbi_transfer { * should also take this lock in the handle_events path, to prevent the user * cancelling the transfer from another thread while you are processing * its completion (presumably there would be races within your OS backend - * if this were possible). */ + * if this were possible). + * Note paths taking both this and the flying_transfers_lock must + * always take the flying_transfers_lock first */ usbi_mutex_t lock; - - /* this lock should be held whenever viewing or modifying flags - * relating to the transfer state */ - usbi_mutex_t flags_lock; }; -enum usbi_transfer_flags { - /* The transfer has timed out */ - USBI_TRANSFER_TIMED_OUT = 1 << 0, - - /* Set by backend submit_transfer() if the OS handles timeout */ - USBI_TRANSFER_OS_HANDLES_TIMEOUT = 1 << 1, +enum usbi_transfer_state_flags { + /* Transfer successfully submitted by backend */ + USBI_TRANSFER_IN_FLIGHT = 1 << 0, /* Cancellation was requested via libusb_cancel_transfer() */ - USBI_TRANSFER_CANCELLING = 1 << 2, + USBI_TRANSFER_CANCELLING = 1 << 1, /* Operation on the transfer failed because the device disappeared */ - USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 3, - - /* Transfer is currently being submitted */ - USBI_TRANSFER_SUBMITTING = 1 << 4, - - /* Transfer successfully submitted by backend */ - USBI_TRANSFER_IN_FLIGHT = 1 << 5, - - /* Completion handler has run */ - USBI_TRANSFER_COMPLETED = 1 << 6, - - /* The transfer timeout has been handled */ - USBI_TRANSFER_TIMEOUT_HANDLED = 1 << 7, + USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 2, }; -#define USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer) \ - ((struct libusb_transfer *)(((unsigned char *)(transfer)) \ +enum usbi_transfer_timeout_flags { + /* Set by backend submit_transfer() if the OS handles timeout */ + USBI_TRANSFER_OS_HANDLES_TIMEOUT = 1 << 0, + + /* The transfer timeout has been handled */ + USBI_TRANSFER_TIMEOUT_HANDLED = 1 << 1, + + /* The transfer timeout was successfully processed */ + USBI_TRANSFER_TIMED_OUT = 1 << 2, +}; + +#define USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer) \ + ((struct libusb_transfer *)(((unsigned char *)(transfer)) \ + sizeof(struct usbi_transfer))) -#define LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer) \ - ((struct usbi_transfer *)(((unsigned char *)(transfer)) \ +#define LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer) \ + ((struct usbi_transfer *)(((unsigned char *)(transfer)) \ - sizeof(struct usbi_transfer))) static inline void *usbi_transfer_get_os_priv(struct usbi_transfer *transfer) @@ -459,8 +498,8 @@ static inline void *usbi_transfer_get_os_priv(struct usbi_transfer *transfer) /* All standard descriptors have these 2 fields in common */ struct usb_descriptor_header { - uint8_t bLength; - uint8_t bDescriptorType; + uint8_t bLength; + uint8_t bDescriptorType; }; /* shared data and functions */ @@ -473,7 +512,7 @@ struct libusb_device *usbi_alloc_device(struct libusb_context *ctx, struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx, unsigned long session_id); int usbi_sanitize_device(struct libusb_device *dev); -void usbi_handle_disconnect(struct libusb_device_handle *handle); +void usbi_handle_disconnect(struct libusb_device_handle *dev_handle); int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, enum libusb_transfer_status status); @@ -493,7 +532,8 @@ int usbi_signal_event(struct libusb_context *ctx); int usbi_clear_event(struct libusb_context *ctx); /* Internal abstraction for poll (needs struct usbi_transfer on Windows) */ -#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) || defined(OS_NETBSD) || defined(OS_HAIKU) +#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) || defined(OS_NETBSD) ||\ + defined(OS_HAIKU) || defined(OS_SUNOS) #include #include "os/poll_posix.h" #elif defined(OS_WINDOWS) || defined(OS_WINCE) @@ -670,7 +710,7 @@ struct usbi_os_backend { * Do not worry about freeing the handle on failed open, the upper layers * do this for you. */ - int (*open)(struct libusb_device_handle *handle); + int (*open)(struct libusb_device_handle *dev_handle); /* Close a device such that the handle cannot be used again. Your backend * should destroy any resources that were allocated in the open path. @@ -680,7 +720,7 @@ struct usbi_os_backend { * * This function is called when the user closes a device handle. */ - void (*close)(struct libusb_device_handle *handle); + void (*close)(struct libusb_device_handle *dev_handle); /* Retrieve the device descriptor from a device. * @@ -787,7 +827,7 @@ struct usbi_os_backend { * blocking * - another LIBUSB_ERROR code on other failure. */ - int (*get_configuration)(struct libusb_device_handle *handle, int *config); + int (*get_configuration)(struct libusb_device_handle *dev_handle, int *config); /* Set the active configuration for a device. * @@ -804,7 +844,7 @@ struct usbi_os_backend { * was opened * - another LIBUSB_ERROR code on other failure. */ - int (*set_configuration)(struct libusb_device_handle *handle, int config); + int (*set_configuration)(struct libusb_device_handle *dev_handle, int config); /* Claim an interface. When claimed, the application can then perform * I/O to an interface's endpoints. @@ -823,7 +863,7 @@ struct usbi_os_backend { * was opened * - another LIBUSB_ERROR code on other failure */ - int (*claim_interface)(struct libusb_device_handle *handle, int interface_number); + int (*claim_interface)(struct libusb_device_handle *dev_handle, int interface_number); /* Release a previously claimed interface. * @@ -840,7 +880,7 @@ struct usbi_os_backend { * was opened * - another LIBUSB_ERROR code on other failure */ - int (*release_interface)(struct libusb_device_handle *handle, int interface_number); + int (*release_interface)(struct libusb_device_handle *dev_handle, int interface_number); /* Set the alternate setting for an interface. * @@ -856,7 +896,7 @@ struct usbi_os_backend { * was opened * - another LIBUSB_ERROR code on other failure */ - int (*set_interface_altsetting)(struct libusb_device_handle *handle, + int (*set_interface_altsetting)(struct libusb_device_handle *dev_handle, int interface_number, int altsetting); /* Clear a halt/stall condition on an endpoint. @@ -870,12 +910,12 @@ struct usbi_os_backend { * was opened * - another LIBUSB_ERROR code on other failure */ - int (*clear_halt)(struct libusb_device_handle *handle, + int (*clear_halt)(struct libusb_device_handle *dev_handle, unsigned char endpoint); /* Perform a USB port reset to reinitialize a device. * - * If possible, the handle should still be usable after the reset + * If possible, the device handle should still be usable after the reset * completes, assuming that the device descriptors did not change during * reset and all previous interface state can be restored. * @@ -889,16 +929,26 @@ struct usbi_os_backend { * has been disconnected since it was opened * - another LIBUSB_ERROR code on other failure */ - int (*reset_device)(struct libusb_device_handle *handle); + int (*reset_device)(struct libusb_device_handle *dev_handle); /* Alloc num_streams usb3 bulk streams on the passed in endpoints */ - int (*alloc_streams)(struct libusb_device_handle *handle, + int (*alloc_streams)(struct libusb_device_handle *dev_handle, uint32_t num_streams, unsigned char *endpoints, int num_endpoints); /* Free usb3 bulk streams allocated with alloc_streams */ - int (*free_streams)(struct libusb_device_handle *handle, + int (*free_streams)(struct libusb_device_handle *dev_handle, unsigned char *endpoints, int num_endpoints); + /* Allocate persistent DMA memory for the given device, suitable for + * zerocopy. May return NULL on failure. Optional to implement. + */ + unsigned char *(*dev_mem_alloc)(struct libusb_device_handle *handle, + size_t len); + + /* Free memory allocated by dev_mem_alloc. */ + int (*dev_mem_free)(struct libusb_device_handle *handle, + unsigned char *buffer, size_t len); + /* Determine if a kernel driver is active on an interface. Optional. * * The presence of a kernel driver on an interface indicates that any @@ -911,7 +961,7 @@ struct usbi_os_backend { * was opened * - another LIBUSB_ERROR code on other failure */ - int (*kernel_driver_active)(struct libusb_device_handle *handle, + int (*kernel_driver_active)(struct libusb_device_handle *dev_handle, int interface_number); /* Detach a kernel driver from an interface. Optional. @@ -927,7 +977,7 @@ struct usbi_os_backend { * was opened * - another LIBUSB_ERROR code on other failure */ - int (*detach_kernel_driver)(struct libusb_device_handle *handle, + int (*detach_kernel_driver)(struct libusb_device_handle *dev_handle, int interface_number); /* Attach a kernel driver to an interface. Optional. @@ -944,7 +994,7 @@ struct usbi_os_backend { * preventing reattachment * - another LIBUSB_ERROR code on other failure */ - int (*attach_kernel_driver)(struct libusb_device_handle *handle, + int (*attach_kernel_driver)(struct libusb_device_handle *dev_handle, int interface_number); /* Destroy a device. Optional. @@ -1089,8 +1139,10 @@ 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; +extern const struct usbi_os_backend sunos_backend; extern struct list_head active_contexts_list; extern usbi_mutex_static_t active_contexts_lock; diff --git a/Externals/libusb/libusb/os/darwin_usb.c b/Externals/libusb/libusb/os/darwin_usb.c index 67945091ff..c2285cd7cb 100644 --- a/Externals/libusb/libusb/os/darwin_usb.c +++ b/Externals/libusb/libusb/os/darwin_usb.c @@ -1,7 +1,7 @@ /* -*- Mode: C; indent-tabs-mode:nil -*- */ /* * darwin backend for libusb 1.0 - * Copyright © 2008-2014 Nathan Hjelm + * Copyright © 2008-2016 Nathan Hjelm * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,6 +19,7 @@ */ #include "config.h" +#include #include #include #include @@ -28,7 +29,7 @@ #include #include #include -#include +#include #include #include @@ -36,24 +37,43 @@ #include #include -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 && MAC_OS_X_VERSION_MIN_REQUIRED < 101200 #include #endif +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101200 +/* Apple deprecated the darwin atomics in 10.12 in favor of C11 atomics */ +#include +#define libusb_darwin_atomic_fetch_add(x, y) atomic_fetch_add(x, y) + +_Atomic int32_t initCount = ATOMIC_VAR_INIT(0); +#else +/* use darwin atomics if the target is older than 10.12 */ +#include + +/* OSAtomicAdd32Barrier returns the new value */ +#define libusb_darwin_atomic_fetch_add(x, y) (OSAtomicAdd32Barrier(y, x) - y) + +static volatile int32_t initCount = 0; +#endif + #include "darwin_usb.h" /* async event thread */ static pthread_mutex_t libusb_darwin_at_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t libusb_darwin_at_cond = PTHREAD_COND_INITIALIZER; +static pthread_once_t darwin_init_once = PTHREAD_ONCE_INIT; + static clock_serv_t clock_realtime; static clock_serv_t clock_monotonic; static CFRunLoopRef libusb_darwin_acfl = NULL; /* event cf loop */ -static volatile int32_t initCount = 0; +static CFRunLoopSourceRef libusb_darwin_acfls = NULL; /* shutdown signal for event cf loop */ static usbi_mutex_t darwin_cached_devices_lock = PTHREAD_MUTEX_INITIALIZER; static struct list_head darwin_cached_devices = {&darwin_cached_devices, &darwin_cached_devices}; +static char *darwin_device_class = kIOUSBDeviceClassName; #define DARWIN_CACHED_DEVICE(a) ((struct darwin_cached_device *) (((struct darwin_device_priv *)((a)->os_priv))->dev)) @@ -189,7 +209,7 @@ static int ep_to_pipeRef(struct libusb_device_handle *dev_handle, uint8_t ep, ui } static int usb_setup_device_iterator (io_iterator_t *deviceIterator, UInt32 location) { - CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName); + CFMutableDictionaryRef matchingDict = IOServiceMatching(darwin_device_class); if (!matchingDict) return kIOReturnError; @@ -234,6 +254,27 @@ static int get_ioregistry_value_number (io_service_t service, CFStringRef proper return ret; } +static int get_ioregistry_value_data (io_service_t service, CFStringRef property, ssize_t size, void *p) { + CFTypeRef cfData = IORegistryEntryCreateCFProperty (service, property, kCFAllocatorDefault, 0); + int ret = 0; + + if (cfData) { + if (CFGetTypeID (cfData) == CFDataGetTypeID ()) { + CFIndex length = CFDataGetLength (cfData); + if (length < size) { + size = length; + } + + CFDataGetBytes (cfData, CFRangeMake(0, size), p); + ret = 1; + } + + CFRelease (cfData); + } + + return ret; +} + static usb_device_t **darwin_device_from_service (io_service_t service) { io_cf_plugin_ref_t *plugInInterface = NULL; @@ -344,19 +385,24 @@ static void *darwin_event_thread_main (void *arg0) { struct libusb_context *ctx = (struct libusb_context *)arg0; CFRunLoopRef runloop; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 /* Set this thread's name, so it can be seen in the debugger and crash reports. */ -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 pthread_setname_np ("org.libusb.device-hotplug"); +#endif +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 && MAC_OS_X_VERSION_MIN_REQUIRED < 101200 /* Tell the Objective-C garbage collector about this thread. This is required because, unlike NSThreads, pthreads are not automatically registered. Although we don't use - Objective-C, we use CoreFoundation, which does. */ + Objective-C, we use CoreFoundation, which does. + Garbage collection support was entirely removed in 10.12, + so don't bother there. */ objc_registerThreadWithCollector(); #endif /* hotplug (device arrival/removal) sources */ + CFRunLoopSourceContext libusb_shutdown_cfsourcectx; CFRunLoopSourceRef libusb_notification_cfsource; io_notification_port_t libusb_notification_port; io_iterator_t libusb_rem_device_iterator; @@ -367,6 +413,13 @@ static void *darwin_event_thread_main (void *arg0) { runloop = CFRunLoopGetCurrent (); CFRetain (runloop); + /* add the shutdown cfsource to the run loop */ + memset(&libusb_shutdown_cfsourcectx, 0, sizeof(libusb_shutdown_cfsourcectx)); + libusb_shutdown_cfsourcectx.info = runloop; + libusb_shutdown_cfsourcectx.perform = (void (*)(void *))CFRunLoopStop; + libusb_darwin_acfls = CFRunLoopSourceCreate(NULL, 0, &libusb_shutdown_cfsourcectx); + CFRunLoopAddSource(runloop, libusb_darwin_acfls, kCFRunLoopDefaultMode); + /* add the notification port to the run loop */ libusb_notification_port = IONotificationPortCreate (kIOMasterPortDefault); libusb_notification_cfsource = IONotificationPortGetRunLoopSource (libusb_notification_port); @@ -374,7 +427,7 @@ static void *darwin_event_thread_main (void *arg0) { /* create notifications for removed devices */ kresult = IOServiceAddMatchingNotification (libusb_notification_port, kIOTerminatedNotification, - IOServiceMatching(kIOUSBDeviceClassName), + IOServiceMatching(darwin_device_class), darwin_devices_detached, ctx, &libusb_rem_device_iterator); @@ -386,7 +439,7 @@ static void *darwin_event_thread_main (void *arg0) { /* create notifications for attached devices */ kresult = IOServiceAddMatchingNotification(libusb_notification_port, kIOFirstMatchNotification, - IOServiceMatching(kIOUSBDeviceClassName), + IOServiceMatching(darwin_device_class), darwin_devices_attached, ctx, &libusb_add_device_iterator); @@ -416,6 +469,9 @@ static void *darwin_event_thread_main (void *arg0) { /* remove the notification cfsource */ CFRunLoopRemoveSource(runloop, libusb_notification_cfsource, kCFRunLoopDefaultMode); + /* remove the shutdown cfsource */ + CFRunLoopRemoveSource(runloop, libusb_darwin_acfls, kCFRunLoopDefaultMode); + /* delete notification port */ IONotificationPortDestroy (libusb_notification_port); @@ -423,8 +479,10 @@ static void *darwin_event_thread_main (void *arg0) { IOObjectRelease (libusb_rem_device_iterator); IOObjectRelease (libusb_add_device_iterator); + CFRelease (libusb_darwin_acfls); CFRelease (runloop); + libusb_darwin_acfls = NULL; libusb_darwin_acfl = NULL; pthread_exit (NULL); @@ -441,16 +499,37 @@ static void __attribute__((destructor)) _darwin_finalize(void) { usbi_mutex_unlock(&darwin_cached_devices_lock); } +static void darwin_check_version (void) { + /* adjust for changes in the USB stack in xnu 15 */ + int sysctl_args[] = {CTL_KERN, KERN_OSRELEASE}; + long version; + char version_string[256] = {'\0',}; + size_t length = 256; + + sysctl(sysctl_args, 2, version_string, &length, NULL, 0); + + errno = 0; + version = strtol (version_string, NULL, 10); + if (0 == errno && version >= 15) { + darwin_device_class = "IOUSBHostDevice"; + } +} + static int darwin_init(struct libusb_context *ctx) { host_name_port_t host_self; int rc; + rc = pthread_once (&darwin_init_once, darwin_check_version); + if (rc) { + return LIBUSB_ERROR_OTHER; + } + rc = darwin_scan_devices (ctx); if (LIBUSB_SUCCESS != rc) { return rc; } - if (OSAtomicIncrement32Barrier(&initCount) == 1) { + if (libusb_darwin_atomic_fetch_add (&initCount, 1) == 0) { /* create the clocks that will be used */ host_self = mach_host_self(); @@ -470,12 +549,13 @@ static int darwin_init(struct libusb_context *ctx) { } static void darwin_exit (void) { - if (OSAtomicDecrement32Barrier(&initCount) == 0) { + if (libusb_darwin_atomic_fetch_add (&initCount, -1) == 1) { mach_port_deallocate(mach_task_self(), clock_realtime); mach_port_deallocate(mach_task_self(), clock_monotonic); /* stop the event runloop and wait for the thread to terminate. */ - CFRunLoopStop (libusb_darwin_acfl); + CFRunLoopSourceSignal(libusb_darwin_acfls); + CFRunLoopWakeUp (libusb_darwin_acfl); pthread_join (libusb_darwin_at, NULL); } } @@ -570,6 +650,14 @@ static int darwin_check_configuration (struct libusb_context *ctx, struct darwin return LIBUSB_ERROR_OTHER; /* no configurations at this speed so we can't use it */ } + /* checking the configuration of a root hub simulation takes ~1 s in 10.11. the device is + not usable anyway */ + if (0x05ac == dev->dev_descriptor.idVendor && 0x8005 == dev->dev_descriptor.idProduct) { + usbi_dbg ("ignoring configuration on root hub simulation"); + dev->active_config = 0; + return 0; + } + /* find the first configuration */ kresult = (*darwin_device)->GetConfigurationDescriptorPtr (darwin_device, 0, &configDesc); dev->first_config = (kIOReturnSuccess == kresult) ? configDesc->bConfigurationValue : 1; @@ -710,7 +798,7 @@ static int darwin_cache_device_descriptor (struct libusb_context *ctx, struct da if (kIOReturnSuccess != ret) { usbi_dbg("kernel responded with code: 0x%08x. sleeping for %d ms before trying again", ret, delay/1000); /* sleep for a little while before trying again */ - usleep (delay); + nanosleep(&(struct timespec){delay / 1000000, (delay * 1000) % 1000000000UL}, NULL); } } while (kIOReturnSuccess != ret && retries--); @@ -760,6 +848,24 @@ static int darwin_cache_device_descriptor (struct libusb_context *ctx, struct da return LIBUSB_SUCCESS; } +static int get_device_port (io_service_t service, UInt8 *port) { + kern_return_t result; + io_service_t parent; + int ret = 0; + + if (get_ioregistry_value_number (service, CFSTR("PortNum"), kCFNumberSInt8Type, port)) { + return 1; + } + + result = IORegistryEntryGetParentEntry (service, kIOServicePlane, &parent); + if (kIOReturnSuccess == result) { + ret = get_ioregistry_value_data (parent, CFSTR("port"), 1, port); + IOObjectRelease (parent); + } + + return ret; +} + static int darwin_get_cached_device(struct libusb_context *ctx, io_service_t service, struct darwin_cached_device **cached_out) { struct darwin_cached_device *new_device; @@ -772,7 +878,9 @@ static int darwin_get_cached_device(struct libusb_context *ctx, io_service_t ser /* get some info from the io registry */ (void) get_ioregistry_value_number (service, CFSTR("sessionID"), kCFNumberSInt64Type, &sessionID); - (void) get_ioregistry_value_number (service, CFSTR("PortNum"), kCFNumberSInt8Type, &port); + if (!get_device_port (service, &port)) { + usbi_dbg("could not get connected port number"); + } usbi_dbg("finding cached device for sessionID 0x%" PRIx64, sessionID); @@ -1111,7 +1219,7 @@ static int get_endpoints (struct libusb_device_handle *dev_handle, int iface) { u_int8_t numep, direction, number; u_int8_t dont_care1, dont_care3; u_int16_t dont_care2; - int i; + int rc; usbi_dbg ("building table of endpoints."); @@ -1123,19 +1231,36 @@ static int get_endpoints (struct libusb_device_handle *dev_handle, int iface) { } /* iterate through pipe references */ - for (i = 1 ; i <= numep ; i++) { + for (int i = 1 ; i <= numep ; i++) { kresult = (*(cInterface->interface))->GetPipeProperties(cInterface->interface, i, &direction, &number, &dont_care1, &dont_care2, &dont_care3); if (kresult != kIOReturnSuccess) { - usbi_err (HANDLE_CTX (dev_handle), "error getting pipe information for pipe %d: %s", i, darwin_error_str(kresult)); + /* probably a buggy device. try to get the endpoint address from the descriptors */ + struct libusb_config_descriptor *config; + const struct libusb_endpoint_descriptor *endpoint_desc; + UInt8 alt_setting; - return darwin_to_libusb (kresult); + kresult = (*(cInterface->interface))->GetAlternateSetting (cInterface->interface, &alt_setting); + if (kresult) { + usbi_err (HANDLE_CTX (dev_handle), "can't get alternate setting for interface"); + return darwin_to_libusb (kresult); + } + + rc = libusb_get_active_config_descriptor (dev_handle->dev, &config); + if (LIBUSB_SUCCESS != rc) { + return rc; + } + + endpoint_desc = config->interface[iface].altsetting[alt_setting].endpoint + i - 1; + + cInterface->endpoint_addrs[i - 1] = endpoint_desc->bEndpointAddress; + } else { + cInterface->endpoint_addrs[i - 1] = (((kUSBIn == direction) << kUSBRqDirnShift) | (number & LIBUSB_ENDPOINT_ADDRESS_MASK)); } - usbi_dbg ("interface: %i pipe %i: dir: %i number: %i", iface, i, direction, number); - - cInterface->endpoint_addrs[i - 1] = (((kUSBIn == direction) << kUSBRqDirnShift) | (number & LIBUSB_ENDPOINT_ADDRESS_MASK)); + usbi_dbg ("interface: %i pipe %i: dir: %i number: %i", iface, i, cInterface->endpoint_addrs[i - 1] >> kUSBRqDirnShift, + cInterface->endpoint_addrs[i - 1] & LIBUSB_ENDPOINT_ADDRESS_MASK); } cInterface->num_endpoints = numep; @@ -1275,7 +1400,7 @@ static int darwin_release_interface(struct libusb_device_handle *dev_handle, int if (kresult != kIOReturnSuccess) usbi_warn (HANDLE_CTX (dev_handle), "Release: %s", darwin_error_str(kresult)); - cInterface->interface = IO_OBJECT_NULL; + cInterface->interface = (usb_interface_t **) IO_OBJECT_NULL; return darwin_to_libusb (kresult); } @@ -1407,14 +1532,14 @@ static int darwin_kernel_driver_active(struct libusb_device_handle *dev_handle, /* attaching/detaching kernel drivers is not currently supported (maybe in the future?) */ static int darwin_attach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) { - (void)dev_handle; - (void)interface; + UNUSED(dev_handle); + UNUSED(interface); return LIBUSB_ERROR_NOT_SUPPORTED; } static int darwin_detach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) { - (void)dev_handle; - (void)interface; + UNUSED(dev_handle); + UNUSED(interface); return LIBUSB_ERROR_NOT_SUPPORTED; } @@ -1471,7 +1596,7 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer) { ret = (*(cInterface->interface))->WritePipeAsync(cInterface->interface, pipeRef, transfer->buffer, transfer->length, darwin_async_io_callback, itransfer); } else { - itransfer->flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT; + itransfer->timeout_flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT; if (IS_XFERIN(transfer)) ret = (*(cInterface->interface))->ReadPipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer, @@ -1503,7 +1628,7 @@ static int submit_stream_transfer(struct usbi_transfer *itransfer) { return LIBUSB_ERROR_NOT_FOUND; } - itransfer->flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT; + itransfer->timeout_flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT; if (IS_XFERIN(transfer)) ret = (*(cInterface->interface))->ReadStreamsPipeAsyncTO(cInterface->interface, pipeRef, itransfer->stream_id, @@ -1619,7 +1744,7 @@ static int submit_control_transfer(struct usbi_transfer *itransfer) { bzero(&tpriv->req, sizeof(tpriv->req)); - /* IOUSBDeviceInterface expects the request in cpu endianess */ + /* IOUSBDeviceInterface expects the request in cpu endianness */ tpriv->req.bmRequestType = setup->bmRequestType; tpriv->req.bRequest = setup->bRequest; /* these values should be in bus order from libusb_fill_control_setup */ @@ -1631,7 +1756,7 @@ static int submit_control_transfer(struct usbi_transfer *itransfer) { tpriv->req.completionTimeout = transfer->timeout; tpriv->req.noDataTimeout = transfer->timeout; - itransfer->flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT; + itransfer->timeout_flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT; /* all transfers in libusb-1.0 are async */ @@ -1780,7 +1905,7 @@ static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0) } static int darwin_transfer_status (struct usbi_transfer *itransfer, kern_return_t result) { - if (itransfer->flags & USBI_TRANSFER_TIMED_OUT) + if (itransfer->timeout_flags & USBI_TRANSFER_TIMED_OUT) result = kIOUSBTransactionTimeout; switch (result) { @@ -1797,7 +1922,7 @@ static int darwin_transfer_status (struct usbi_transfer *itransfer, kern_return_ return LIBUSB_TRANSFER_OVERFLOW; case kIOUSBTransactionTimeout: usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: timed out"); - itransfer->flags |= USBI_TRANSFER_TIMED_OUT; + itransfer->timeout_flags |= USBI_TRANSFER_TIMED_OUT; return LIBUSB_TRANSFER_TIMED_OUT; default: usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: %s (value = 0x%08x)", darwin_error_str (result), result); diff --git a/Externals/libusb/libusb/os/darwin_usb.h b/Externals/libusb/libusb/os/darwin_usb.h index 4cf28bf655..118043421a 100644 --- a/Externals/libusb/libusb/os/darwin_usb.h +++ b/Externals/libusb/libusb/os/darwin_usb.h @@ -1,6 +1,6 @@ /* * darwin backend for libusb 1.0 - * Copyright © 2008-2013 Nathan Hjelm + * Copyright © 2008-2015 Nathan Hjelm * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -28,7 +28,13 @@ #include /* IOUSBInterfaceInferface */ -#if defined (kIOUSBInterfaceInterfaceID550) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9 +#if defined (kIOUSBInterfaceInterfaceID700) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9 + +#define usb_interface_t IOUSBInterfaceInterface700 +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID700 +#define InterfaceVersion 700 + +#elif defined (kIOUSBInterfaceInterfaceID550) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9 #define usb_interface_t IOUSBInterfaceInterface550 #define InterfaceInterfaceID kIOUSBInterfaceInterfaceID550 diff --git a/Externals/libusb/libusb/os/haiku_pollfs.cpp b/Externals/libusb/libusb/os/haiku_pollfs.cpp new file mode 100644 index 0000000000..e0c7713206 --- /dev/null +++ b/Externals/libusb/libusb/os/haiku_pollfs.cpp @@ -0,0 +1,367 @@ +/* + * Copyright 2007-2008, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ + +#include "haiku_usb.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class WatchedEntry { +public: + WatchedEntry(BMessenger *, entry_ref *); + ~WatchedEntry(); + bool EntryCreated(entry_ref *ref); + bool EntryRemoved(ino_t node); + bool InitCheck(); + +private: + BMessenger* fMessenger; + node_ref fNode; + bool fIsDirectory; + USBDevice* fDevice; + WatchedEntry* fEntries; + WatchedEntry* fLink; + bool fInitCheck; +}; + + +class RosterLooper : public BLooper { +public: + RosterLooper(USBRoster *); + void Stop(); + virtual void MessageReceived(BMessage *); + bool InitCheck(); + +private: + USBRoster* fRoster; + WatchedEntry* fRoot; + BMessenger* fMessenger; + bool fInitCheck; +}; + + +WatchedEntry::WatchedEntry(BMessenger *messenger, entry_ref *ref) + : fMessenger(messenger), + fIsDirectory(false), + fDevice(NULL), + fEntries(NULL), + fLink(NULL), + fInitCheck(false) +{ + BEntry entry(ref); + entry.GetNodeRef(&fNode); + + BDirectory directory; + if (entry.IsDirectory() && directory.SetTo(ref) >= B_OK) { + fIsDirectory = true; + + while (directory.GetNextEntry(&entry) >= B_OK) { + if (entry.GetRef(ref) < B_OK) + continue; + + WatchedEntry *child = new(std::nothrow) WatchedEntry(fMessenger, ref); + if (child == NULL) + continue; + if (child->InitCheck() == false) { + delete child; + continue; + } + + child->fLink = fEntries; + fEntries = child; + } + + watch_node(&fNode, B_WATCH_DIRECTORY, *fMessenger); + } + else { + if (strncmp(ref->name, "raw", 3) == 0) + return; + + BPath path, parent_path; + entry.GetPath(&path); + fDevice = new(std::nothrow) USBDevice(path.Path()); + if (fDevice != NULL && fDevice->InitCheck() == true) { + // Add this new device to each active context's device list + struct libusb_context *ctx; + unsigned long session_id = (unsigned long)&fDevice; + + usbi_mutex_lock(&active_contexts_lock); + list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) { + struct libusb_device *dev = usbi_get_device_by_session_id(ctx, session_id); + if (dev) { + usbi_dbg("using previously allocated device with location %lu", session_id); + libusb_unref_device(dev); + continue; + } + usbi_dbg("allocating new device with location %lu", session_id); + dev = usbi_alloc_device(ctx, session_id); + if (!dev) { + usbi_dbg("device allocation failed"); + continue; + } + *((USBDevice **)dev->os_priv) = fDevice; + + // Calculate pseudo-device-address + int addr, tmp; + if (strcmp(path.Leaf(), "hub") == 0) + tmp = 100; //Random Number + else + sscanf(path.Leaf(), "%d", &tmp); + addr = tmp + 1; + path.GetParent(&parent_path); + while (strcmp(parent_path.Leaf(), "usb") != 0) { + sscanf(parent_path.Leaf(), "%d", &tmp); + addr += tmp + 1; + parent_path.GetParent(&parent_path); + } + sscanf(path.Path(), "/dev/bus/usb/%d", &dev->bus_number); + dev->device_address = addr - (dev->bus_number + 1); + + if (usbi_sanitize_device(dev) < 0) { + usbi_dbg("device sanitization failed"); + libusb_unref_device(dev); + continue; + } + usbi_connect_device(dev); + } + usbi_mutex_unlock(&active_contexts_lock); + } + else if (fDevice) { + delete fDevice; + fDevice = NULL; + return; + } + } + fInitCheck = true; +} + + +WatchedEntry::~WatchedEntry() +{ + if (fIsDirectory) { + watch_node(&fNode, B_STOP_WATCHING, *fMessenger); + + WatchedEntry *child = fEntries; + while (child) { + WatchedEntry *next = child->fLink; + delete child; + child = next; + } + } + + if (fDevice) { + // Remove this device from each active context's device list + struct libusb_context *ctx; + struct libusb_device *dev; + unsigned long session_id = (unsigned long)&fDevice; + + usbi_mutex_lock(&active_contexts_lock); + list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) { + dev = usbi_get_device_by_session_id(ctx, session_id); + if (dev != NULL) { + usbi_disconnect_device(dev); + libusb_unref_device(dev); + } else { + usbi_dbg("device with location %lu not found", session_id); + } + } + usbi_mutex_static_unlock(&active_contexts_lock); + delete fDevice; + } +} + + +bool +WatchedEntry::EntryCreated(entry_ref *ref) +{ + if (!fIsDirectory) + return false; + + if (ref->directory != fNode.node) { + WatchedEntry *child = fEntries; + while (child) { + if (child->EntryCreated(ref)) + return true; + child = child->fLink; + } + return false; + } + + WatchedEntry *child = new(std::nothrow) WatchedEntry(fMessenger, ref); + if (child == NULL) + return false; + child->fLink = fEntries; + fEntries = child; + return true; +} + + +bool +WatchedEntry::EntryRemoved(ino_t node) +{ + if (!fIsDirectory) + return false; + + WatchedEntry *child = fEntries; + WatchedEntry *lastChild = NULL; + while (child) { + if (child->fNode.node == node) { + if (lastChild) + lastChild->fLink = child->fLink; + else + fEntries = child->fLink; + delete child; + return true; + } + + if (child->EntryRemoved(node)) + return true; + + lastChild = child; + child = child->fLink; + } + return false; +} + + +bool +WatchedEntry::InitCheck() +{ + return fInitCheck; +} + + +RosterLooper::RosterLooper(USBRoster *roster) + : BLooper("LibusbRoster Looper"), + fRoster(roster), + fRoot(NULL), + fMessenger(NULL), + fInitCheck(false) +{ + BEntry entry("/dev/bus/usb"); + if (!entry.Exists()) { + usbi_err(NULL, "usb_raw not published"); + return; + } + + Run(); + fMessenger = new(std::nothrow) BMessenger(this); + if (fMessenger == NULL) { + usbi_err(NULL, "error creating BMessenger object"); + return; + } + + if (Lock()) { + entry_ref ref; + entry.GetRef(&ref); + fRoot = new(std::nothrow) WatchedEntry(fMessenger, &ref); + Unlock(); + if (fRoot == NULL) + return; + if (fRoot->InitCheck() == false) { + delete fRoot; + fRoot = NULL; + return; + } + } + fInitCheck = true; +} + + +void +RosterLooper::Stop() +{ + Lock(); + delete fRoot; + delete fMessenger; + Quit(); +} + + +void +RosterLooper::MessageReceived(BMessage *message) +{ + int32 opcode; + if (message->FindInt32("opcode", &opcode) < B_OK) + return; + + switch (opcode) { + case B_ENTRY_CREATED: + { + dev_t device; + ino_t directory; + const char *name; + if (message->FindInt32("device", &device) < B_OK || + message->FindInt64("directory", &directory) < B_OK || + message->FindString("name", &name) < B_OK) + break; + + entry_ref ref(device, directory, name); + fRoot->EntryCreated(&ref); + break; + } + case B_ENTRY_REMOVED: + { + ino_t node; + if (message->FindInt64("node", &node) < B_OK) + break; + fRoot->EntryRemoved(node); + break; + } + } +} + + +bool +RosterLooper::InitCheck() +{ + return fInitCheck; +} + + +USBRoster::USBRoster() + : fLooper(NULL) +{ +} + + +USBRoster::~USBRoster() +{ + Stop(); +} + + +int +USBRoster::Start() +{ + if (fLooper == NULL) { + fLooper = new(std::nothrow) RosterLooper(this); + if (fLooper == NULL || ((RosterLooper *)fLooper)->InitCheck() == false) { + if (fLooper) + fLooper = NULL; + return LIBUSB_ERROR_OTHER; + } + } + return LIBUSB_SUCCESS; +} + + +void +USBRoster::Stop() +{ + if (fLooper) { + ((RosterLooper *)fLooper)->Stop(); + fLooper = NULL; + } +} diff --git a/Externals/libusb/libusb/os/haiku_usb.h b/Externals/libusb/libusb/os/haiku_usb.h new file mode 100644 index 0000000000..d51ae9eae8 --- /dev/null +++ b/Externals/libusb/libusb/os/haiku_usb.h @@ -0,0 +1,112 @@ +/* + * Haiku Backend for libusb + * Copyright © 2014 Akshay Jaggi + * + * 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 +#include +#include +#include +#include +#include "libusbi.h" +#include "haiku_usb_raw.h" + +using namespace std; + +class USBDevice; +class USBDeviceHandle; +class USBTransfer; + +class USBDevice { +public: + USBDevice(const char *); + virtual ~USBDevice(); + const char* Location() const; + uint8 CountConfigurations() const; + const usb_device_descriptor* Descriptor() const; + const usb_configuration_descriptor* ConfigurationDescriptor(uint32) const; + const usb_configuration_descriptor* ActiveConfiguration() const; + uint8 EndpointToIndex(uint8) const; + uint8 EndpointToInterface(uint8) const; + int ClaimInterface(int); + int ReleaseInterface(int); + int CheckInterfacesFree(int); + int SetActiveConfiguration(int); + int ActiveConfigurationIndex() const; + bool InitCheck(); +private: + int Initialise(); + unsigned int fClaimedInterfaces; // Max Interfaces can be 32. Using a bitmask + usb_device_descriptor fDeviceDescriptor; + unsigned char** fConfigurationDescriptors; + int fActiveConfiguration; + char* fPath; + map fConfigToIndex; + map* fEndpointToIndex; + map* fEndpointToInterface; + bool fInitCheck; +}; + +class USBDeviceHandle { +public: + USBDeviceHandle(USBDevice *dev); + virtual ~USBDeviceHandle(); + int ClaimInterface(int); + int ReleaseInterface(int); + int SetConfiguration(int); + int SetAltSetting(int, int); + status_t SubmitTransfer(struct usbi_transfer *); + status_t CancelTransfer(USBTransfer *); + bool InitCheck(); +private: + int fRawFD; + static status_t TransfersThread(void *); + void TransfersWorker(); + USBDevice* fUSBDevice; + unsigned int fClaimedInterfaces; + BList fTransfers; + BLocker fTransfersLock; + sem_id fTransfersSem; + thread_id fTransfersThread; + bool fInitCheck; +}; + +class USBTransfer { +public: + USBTransfer(struct usbi_transfer *, USBDevice *); + virtual ~USBTransfer(); + void Do(int); + struct usbi_transfer* UsbiTransfer(); + void SetCancelled(); + bool IsCancelled(); +private: + struct usbi_transfer* fUsbiTransfer; + struct libusb_transfer* fLibusbTransfer; + USBDevice* fUSBDevice; + BLocker fStatusLock; + bool fCancelled; +}; + +class USBRoster { +public: + USBRoster(); + virtual ~USBRoster(); + int Start(); + void Stop(); +private: + void* fLooper; +}; diff --git a/Externals/libusb/libusb/os/haiku_usb_backend.cpp b/Externals/libusb/libusb/os/haiku_usb_backend.cpp new file mode 100644 index 0000000000..d3de8cc080 --- /dev/null +++ b/Externals/libusb/libusb/os/haiku_usb_backend.cpp @@ -0,0 +1,517 @@ +/* + * Haiku Backend for libusb + * Copyright © 2014 Akshay Jaggi + * + * 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 +#include +#include +#include +#include + +#include "haiku_usb.h" + +int _errno_to_libusb(int status) +{ + return status; +} + +USBTransfer::USBTransfer(struct usbi_transfer *itransfer, USBDevice *device) +{ + fUsbiTransfer = itransfer; + fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + fUSBDevice = device; + fCancelled = false; +} + +USBTransfer::~USBTransfer() +{ +} + +struct usbi_transfer * +USBTransfer::UsbiTransfer() +{ + return fUsbiTransfer; +} + +void +USBTransfer::SetCancelled() +{ + fCancelled = true; +} + +bool +USBTransfer::IsCancelled() +{ + return fCancelled; +} + +void +USBTransfer::Do(int fRawFD) +{ + switch (fLibusbTransfer->type) { + case LIBUSB_TRANSFER_TYPE_CONTROL: + { + struct libusb_control_setup *setup = (struct libusb_control_setup *)fLibusbTransfer->buffer; + usb_raw_command command; + command.control.request_type = setup->bmRequestType; + command.control.request = setup->bRequest; + command.control.value = setup->wValue; + command.control.index = setup->wIndex; + command.control.length = setup->wLength; + command.control.data = fLibusbTransfer->buffer + LIBUSB_CONTROL_SETUP_SIZE; + if (fCancelled) + break; + if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command, sizeof(command)) || + command.control.status != B_USB_RAW_STATUS_SUCCESS) { + fUsbiTransfer->transferred = -1; + usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed control transfer"); + break; + } + fUsbiTransfer->transferred = command.control.length; + } + break; + case LIBUSB_TRANSFER_TYPE_BULK: + case LIBUSB_TRANSFER_TYPE_INTERRUPT: + { + usb_raw_command command; + command.transfer.interface = fUSBDevice->EndpointToInterface(fLibusbTransfer->endpoint); + command.transfer.endpoint = fUSBDevice->EndpointToIndex(fLibusbTransfer->endpoint); + command.transfer.data = fLibusbTransfer->buffer; + command.transfer.length = fLibusbTransfer->length; + if (fCancelled) + break; + if (fLibusbTransfer->type == LIBUSB_TRANSFER_TYPE_BULK) { + if (ioctl(fRawFD, B_USB_RAW_COMMAND_BULK_TRANSFER, &command, sizeof(command)) || + command.transfer.status != B_USB_RAW_STATUS_SUCCESS) { + fUsbiTransfer->transferred = -1; + usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed bulk transfer"); + break; + } + } + else { + if (ioctl(fRawFD, B_USB_RAW_COMMAND_INTERRUPT_TRANSFER, &command, sizeof(command)) || + command.transfer.status != B_USB_RAW_STATUS_SUCCESS) { + fUsbiTransfer->transferred = -1; + usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed interrupt transfer"); + break; + } + } + fUsbiTransfer->transferred = command.transfer.length; + } + break; + // IsochronousTransfers not tested + case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: + { + usb_raw_command command; + command.isochronous.interface = fUSBDevice->EndpointToInterface(fLibusbTransfer->endpoint); + command.isochronous.endpoint = fUSBDevice->EndpointToIndex(fLibusbTransfer->endpoint); + command.isochronous.data = fLibusbTransfer->buffer; + command.isochronous.length = fLibusbTransfer->length; + command.isochronous.packet_count = fLibusbTransfer->num_iso_packets; + int i; + usb_iso_packet_descriptor *packetDescriptors = new usb_iso_packet_descriptor[fLibusbTransfer->num_iso_packets]; + for (i = 0; i < fLibusbTransfer->num_iso_packets; i++) { + if ((int16)(fLibusbTransfer->iso_packet_desc[i]).length != (fLibusbTransfer->iso_packet_desc[i]).length) { + fUsbiTransfer->transferred = -1; + usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed isochronous transfer"); + break; + } + packetDescriptors[i].request_length = (int16)(fLibusbTransfer->iso_packet_desc[i]).length; + } + if (i < fLibusbTransfer->num_iso_packets) + break; // TODO Handle this error + command.isochronous.packet_descriptors = packetDescriptors; + if (fCancelled) + break; + if (ioctl(fRawFD, B_USB_RAW_COMMAND_ISOCHRONOUS_TRANSFER, &command, sizeof(command)) || + command.isochronous.status != B_USB_RAW_STATUS_SUCCESS) { + fUsbiTransfer->transferred = -1; + usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed isochronous transfer"); + break; + } + for (i = 0; i < fLibusbTransfer->num_iso_packets; i++) { + (fLibusbTransfer->iso_packet_desc[i]).actual_length = packetDescriptors[i].actual_length; + switch (packetDescriptors[i].status) { + case B_OK: + (fLibusbTransfer->iso_packet_desc[i]).status = LIBUSB_TRANSFER_COMPLETED; + break; + default: + (fLibusbTransfer->iso_packet_desc[i]).status = LIBUSB_TRANSFER_ERROR; + break; + } + } + delete[] packetDescriptors; + // Do we put the length of transfer here, for isochronous transfers? + fUsbiTransfer->transferred = command.transfer.length; + } + break; + default: + usbi_err(TRANSFER_CTX(fLibusbTransfer), "Unknown type of transfer"); + } +} + +bool +USBDeviceHandle::InitCheck() +{ + return fInitCheck; +} + +status_t +USBDeviceHandle::TransfersThread(void *self) +{ + USBDeviceHandle *handle = (USBDeviceHandle *)self; + handle->TransfersWorker(); + return B_OK; +} + +void +USBDeviceHandle::TransfersWorker() +{ + while (true) { + status_t status = acquire_sem(fTransfersSem); + if (status == B_BAD_SEM_ID) + break; + if (status == B_INTERRUPTED) + continue; + fTransfersLock.Lock(); + USBTransfer *fPendingTransfer = (USBTransfer *) fTransfers.RemoveItem((int32)0); + fTransfersLock.Unlock(); + fPendingTransfer->Do(fRawFD); + usbi_signal_transfer_completion(fPendingTransfer->UsbiTransfer()); + } +} + +status_t +USBDeviceHandle::SubmitTransfer(struct usbi_transfer *itransfer) +{ + USBTransfer *transfer = new USBTransfer(itransfer, fUSBDevice); + *((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = transfer; + BAutolock locker(fTransfersLock); + fTransfers.AddItem(transfer); + release_sem(fTransfersSem); + return LIBUSB_SUCCESS; +} + +status_t +USBDeviceHandle::CancelTransfer(USBTransfer *transfer) +{ + transfer->SetCancelled(); + fTransfersLock.Lock(); + bool removed = fTransfers.RemoveItem(transfer); + fTransfersLock.Unlock(); + if(removed) + usbi_signal_transfer_completion(transfer->UsbiTransfer()); + return LIBUSB_SUCCESS; +} + +USBDeviceHandle::USBDeviceHandle(USBDevice *dev) + : + fTransfersThread(-1), + fUSBDevice(dev), + fClaimedInterfaces(0), + fInitCheck(false) +{ + fRawFD = open(dev->Location(), O_RDWR | O_CLOEXEC); + if (fRawFD < 0) { + usbi_err(NULL,"failed to open device"); + return; + } + fTransfersSem = create_sem(0, "Transfers Queue Sem"); + fTransfersThread = spawn_thread(TransfersThread, "Transfer Worker", B_NORMAL_PRIORITY, this); + resume_thread(fTransfersThread); + fInitCheck = true; +} + +USBDeviceHandle::~USBDeviceHandle() +{ + if (fRawFD > 0) + close(fRawFD); + for(int i = 0; i < 32; i++) { + if (fClaimedInterfaces & (1 << i)) + ReleaseInterface(i); + } + delete_sem(fTransfersSem); + if (fTransfersThread > 0) + wait_for_thread(fTransfersThread, NULL); +} + +int +USBDeviceHandle::ClaimInterface(int inumber) +{ + int status = fUSBDevice->ClaimInterface(inumber); + if (status == LIBUSB_SUCCESS) + fClaimedInterfaces |= (1 << inumber); + return status; +} + +int +USBDeviceHandle::ReleaseInterface(int inumber) +{ + fUSBDevice->ReleaseInterface(inumber); + fClaimedInterfaces &= ~(1 << inumber); + return LIBUSB_SUCCESS; +} + +int +USBDeviceHandle::SetConfiguration(int config) +{ + int config_index = fUSBDevice->CheckInterfacesFree(config); + if(config_index == LIBUSB_ERROR_BUSY || config_index == LIBUSB_ERROR_NOT_FOUND) + return config_index; + usb_raw_command command; + command.config.config_index = config_index; + if (ioctl(fRawFD, B_USB_RAW_COMMAND_SET_CONFIGURATION, &command, sizeof(command)) || + command.config.status != B_USB_RAW_STATUS_SUCCESS) { + return _errno_to_libusb(command.config.status); + } + fUSBDevice->SetActiveConfiguration(config_index); + return LIBUSB_SUCCESS; +} + +int +USBDeviceHandle::SetAltSetting(int inumber, int alt) +{ + usb_raw_command command; + command.alternate.config_index = fUSBDevice->ActiveConfigurationIndex(); + command.alternate.interface_index = inumber; + if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ACTIVE_ALT_INTERFACE_INDEX, &command, sizeof(command)) || + command.alternate.status != B_USB_RAW_STATUS_SUCCESS) { + usbi_err(NULL, "Error retrieving active alternate interface"); + return _errno_to_libusb(command.alternate.status); + } + if (command.alternate.alternate_info == alt) { + usbi_dbg("Setting alternate interface successful"); + return LIBUSB_SUCCESS; + } + command.alternate.alternate_info = alt; + if (ioctl(fRawFD, B_USB_RAW_COMMAND_SET_ALT_INTERFACE, &command, sizeof(command)) || + command.alternate.status != B_USB_RAW_STATUS_SUCCESS) { //IF IOCTL FAILS DEVICE DISONNECTED PROBABLY + usbi_err(NULL, "Error setting alternate interface"); + return _errno_to_libusb(command.alternate.status); + } + usbi_dbg("Setting alternate interface successful"); + return LIBUSB_SUCCESS; +} + + +USBDevice::USBDevice(const char *path) + : + fPath(NULL), + fActiveConfiguration(0), //0? + fConfigurationDescriptors(NULL), + fClaimedInterfaces(0), + fEndpointToIndex(NULL), + fEndpointToInterface(NULL), + fInitCheck(false) +{ + fPath=strdup(path); + Initialise(); +} + +USBDevice::~USBDevice() +{ + free(fPath); + if (fConfigurationDescriptors) { + for(int i = 0; i < fDeviceDescriptor.num_configurations; i++) { + if (fConfigurationDescriptors[i]) + delete fConfigurationDescriptors[i]; + } + delete[] fConfigurationDescriptors; + } + if (fEndpointToIndex) + delete[] fEndpointToIndex; + if (fEndpointToInterface) + delete[] fEndpointToInterface; +} + +bool +USBDevice::InitCheck() +{ + return fInitCheck; +} + +const char * +USBDevice::Location() const +{ + return fPath; +} + +uint8 +USBDevice::CountConfigurations() const +{ + return fDeviceDescriptor.num_configurations; +} + +const usb_device_descriptor * +USBDevice::Descriptor() const +{ + return &fDeviceDescriptor; +} + +const usb_configuration_descriptor * +USBDevice::ConfigurationDescriptor(uint32 index) const +{ + if (index > CountConfigurations()) + return NULL; + return (usb_configuration_descriptor *) fConfigurationDescriptors[index]; +} + +const usb_configuration_descriptor * +USBDevice::ActiveConfiguration() const +{ + return (usb_configuration_descriptor *) fConfigurationDescriptors[fActiveConfiguration]; +} + +int +USBDevice::ActiveConfigurationIndex() const +{ + return fActiveConfiguration; +} + +int USBDevice::ClaimInterface(int interface) +{ + if (interface > ActiveConfiguration()->number_interfaces) + return LIBUSB_ERROR_NOT_FOUND; + if (fClaimedInterfaces & (1 << interface)) + return LIBUSB_ERROR_BUSY; + fClaimedInterfaces |= (1 << interface); + return LIBUSB_SUCCESS; +} + +int USBDevice::ReleaseInterface(int interface) +{ + fClaimedInterfaces &= ~(1 << interface); + return LIBUSB_SUCCESS; +} + +int +USBDevice::CheckInterfacesFree(int config) +{ + if (fConfigToIndex.count(config) == 0) + return LIBUSB_ERROR_NOT_FOUND; + if (fClaimedInterfaces == 0) + return fConfigToIndex[(uint8)config]; + return LIBUSB_ERROR_BUSY; +} + +int +USBDevice::SetActiveConfiguration(int config_index) +{ + fActiveConfiguration = config_index; + return LIBUSB_SUCCESS; +} + +uint8 +USBDevice::EndpointToIndex(uint8 address) const +{ + return fEndpointToIndex[fActiveConfiguration][address]; +} + +uint8 +USBDevice::EndpointToInterface(uint8 address) const +{ + return fEndpointToInterface[fActiveConfiguration][address]; +} + +int +USBDevice::Initialise() //Do we need more error checking, etc? How to report? +{ + int fRawFD = open(fPath, O_RDWR | O_CLOEXEC); + if (fRawFD < 0) + return B_ERROR; + usb_raw_command command; + command.device.descriptor = &fDeviceDescriptor; + if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_DEVICE_DESCRIPTOR, &command, sizeof(command)) || + command.device.status != B_USB_RAW_STATUS_SUCCESS) { + close(fRawFD); + return B_ERROR; + } + + fConfigurationDescriptors = new(std::nothrow) unsigned char *[fDeviceDescriptor.num_configurations]; + fEndpointToIndex = new(std::nothrow) map [fDeviceDescriptor.num_configurations]; + fEndpointToInterface = new(std::nothrow) map [fDeviceDescriptor.num_configurations]; + for (int i = 0; i < fDeviceDescriptor.num_configurations; i++) { + usb_configuration_descriptor tmp_config; + command.config.descriptor = &tmp_config; + command.config.config_index = i; + if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR, &command, sizeof(command)) || + command.config.status != B_USB_RAW_STATUS_SUCCESS) { + usbi_err(NULL, "failed retrieving configuration descriptor"); + close(fRawFD); + return B_ERROR; + } + fConfigToIndex[tmp_config.configuration_value] = i; + fConfigurationDescriptors[i] = new(std::nothrow) unsigned char[tmp_config.total_length]; + command.control.request_type = 128; + command.control.request = 6; + command.control.value = (2 << 8) | i; + command.control.index = 0; + command.control.length = tmp_config.total_length; + command.control.data = fConfigurationDescriptors[i]; + if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command, sizeof(command)) || + command.control.status!=B_USB_RAW_STATUS_SUCCESS) { + usbi_err(NULL, "failed retrieving full configuration descriptor"); + close(fRawFD); + return B_ERROR; + } + for (int j = 0; j < tmp_config.number_interfaces; j++) { + command.alternate.config_index = i; + command.alternate.interface_index = j; + if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT, &command, sizeof(command)) || + command.config.status != B_USB_RAW_STATUS_SUCCESS) { + usbi_err(NULL, "failed retrieving number of alternate interfaces"); + close(fRawFD); + return B_ERROR; + } + int num_alternate = command.alternate.alternate_info; + for (int k = 0; k < num_alternate; k++) { + usb_interface_descriptor tmp_interface; + command.interface_etc.config_index = i; + command.interface_etc.interface_index = j; + command.interface_etc.alternate_index = k; + command.interface_etc.descriptor = &tmp_interface; + if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR_ETC, &command, sizeof(command)) || + command.config.status != B_USB_RAW_STATUS_SUCCESS) { + usbi_err(NULL, "failed retrieving interface descriptor"); + close(fRawFD); + return B_ERROR; + } + for (int l = 0; l < tmp_interface.num_endpoints; l++) { + usb_endpoint_descriptor tmp_endpoint; + command.endpoint_etc.config_index = i; + command.endpoint_etc.interface_index = j; + command.endpoint_etc.alternate_index = k; + command.endpoint_etc.endpoint_index = l; + command.endpoint_etc.descriptor = &tmp_endpoint; + if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR_ETC, &command, sizeof(command)) || + command.config.status != B_USB_RAW_STATUS_SUCCESS) { + usbi_err(NULL, "failed retrieving endpoint descriptor"); + close(fRawFD); + return B_ERROR; + } + fEndpointToIndex[i][tmp_endpoint.endpoint_address] = l; + fEndpointToInterface[i][tmp_endpoint.endpoint_address] = j; + } + } + } + } + close(fRawFD); + fInitCheck = true; + return B_OK; +} diff --git a/Externals/libusb/libusb/os/haiku_usb_raw.cpp b/Externals/libusb/libusb/os/haiku_usb_raw.cpp new file mode 100644 index 0000000000..77adbd1e60 --- /dev/null +++ b/Externals/libusb/libusb/os/haiku_usb_raw.cpp @@ -0,0 +1,250 @@ +/* + * Haiku Backend for libusb + * Copyright © 2014 Akshay Jaggi + * + * 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 +#include +#include +#include +#include + +#include "haiku_usb.h" + +USBRoster gUsbRoster; +int32 gInitCount = 0; + +static int +haiku_init(struct libusb_context *ctx) +{ + if (atomic_add(&gInitCount, 1) == 0) + return gUsbRoster.Start(); + return LIBUSB_SUCCESS; +} + +static void +haiku_exit(void) +{ + if (atomic_add(&gInitCount, -1) == 1) + gUsbRoster.Stop(); +} + +static int +haiku_open(struct libusb_device_handle *dev_handle) +{ + USBDevice *dev = *((USBDevice **)dev_handle->dev->os_priv); + USBDeviceHandle *handle = new(std::nothrow) USBDeviceHandle(dev); + if (handle == NULL) + return LIBUSB_ERROR_NO_MEM; + if (handle->InitCheck() == false) { + delete handle; + return LIBUSB_ERROR_NO_DEVICE; + } + *((USBDeviceHandle **)dev_handle->os_priv) = handle; + return LIBUSB_SUCCESS; +} + +static void +haiku_close(struct libusb_device_handle *dev_handle) +{ + USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv); + if (handle == NULL) + return; + delete handle; + *((USBDeviceHandle **)dev_handle->os_priv) = NULL; +} + +static int +haiku_get_device_descriptor(struct libusb_device *device, unsigned char *buffer, int *host_endian) +{ + USBDevice *dev = *((USBDevice **)device->os_priv); + memcpy(buffer, dev->Descriptor(), DEVICE_DESC_LENGTH); + *host_endian = 0; + return LIBUSB_SUCCESS; +} + +static int +haiku_get_active_config_descriptor(struct libusb_device *device, unsigned char *buffer, size_t len, int *host_endian) +{ + USBDevice *dev = *((USBDevice **)device->os_priv); + const usb_configuration_descriptor *act_config = dev->ActiveConfiguration(); + if (len > act_config->total_length) + return LIBUSB_ERROR_OVERFLOW; + memcpy(buffer, act_config, len); + *host_endian = 0; + return LIBUSB_SUCCESS; +} + +static int +haiku_get_config_descriptor(struct libusb_device *device, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) +{ + USBDevice *dev = *((USBDevice **)device->os_priv); + const usb_configuration_descriptor *config = dev->ConfigurationDescriptor(config_index); + if (config == NULL) { + usbi_err(DEVICE_CTX(device), "failed getting configuration descriptor"); + return LIBUSB_ERROR_INVALID_PARAM; + } + if (len > config->total_length) + len = config->total_length; + memcpy(buffer, config, len); + *host_endian = 0; + return len; +} + +static int +haiku_set_configuration(struct libusb_device_handle *dev_handle, int config) +{ + USBDeviceHandle *handle= *((USBDeviceHandle **)dev_handle->os_priv); + return handle->SetConfiguration(config); +} + +static int +haiku_claim_interface(struct libusb_device_handle *dev_handle, int interface_number) +{ + USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv); + return handle->ClaimInterface(interface_number); +} + +static int +haiku_set_altsetting(struct libusb_device_handle *dev_handle, int interface_number, int altsetting) +{ + USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv); + return handle->SetAltSetting(interface_number, altsetting); +} + +static int +haiku_release_interface(struct libusb_device_handle *dev_handle, int interface_number) +{ + USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv); + haiku_set_altsetting(dev_handle,interface_number, 0); + return handle->ReleaseInterface(interface_number); +} + +static int +haiku_submit_transfer(struct usbi_transfer *itransfer) +{ + struct libusb_transfer *fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + USBDeviceHandle *fDeviceHandle = *((USBDeviceHandle **)fLibusbTransfer->dev_handle->os_priv); + return fDeviceHandle->SubmitTransfer(itransfer); +} + +static int +haiku_cancel_transfer(struct usbi_transfer *itransfer) +{ + struct libusb_transfer *fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + USBDeviceHandle *fDeviceHandle = *((USBDeviceHandle **)fLibusbTransfer->dev_handle->os_priv); + return fDeviceHandle->CancelTransfer(*((USBTransfer **)usbi_transfer_get_os_priv(itransfer))); +} + +static void +haiku_clear_transfer_priv(struct usbi_transfer *itransfer) +{ + USBTransfer *transfer = *((USBTransfer **)usbi_transfer_get_os_priv(itransfer)); + delete transfer; + *((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = NULL; +} + +static int +haiku_handle_transfer_completion(struct usbi_transfer *itransfer) +{ + USBTransfer *transfer = *((USBTransfer **)usbi_transfer_get_os_priv(itransfer)); + + usbi_mutex_lock(&itransfer->lock); + if (transfer->IsCancelled()) { + delete transfer; + *((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = NULL; + usbi_mutex_unlock(&itransfer->lock); + if (itransfer->transferred < 0) + itransfer->transferred = 0; + return usbi_handle_transfer_cancellation(itransfer); + } + libusb_transfer_status status = LIBUSB_TRANSFER_COMPLETED; + if (itransfer->transferred < 0) { + usbi_err(ITRANSFER_CTX(itransfer), "error in transfer"); + status = LIBUSB_TRANSFER_ERROR; + itransfer->transferred = 0; + } + delete transfer; + *((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = NULL; + usbi_mutex_unlock(&itransfer->lock); + return usbi_handle_transfer_completion(itransfer, status); +} + +static int +haiku_clock_gettime(int clkid, struct timespec *tp) +{ + if (clkid == USBI_CLOCK_REALTIME) + return clock_gettime(CLOCK_REALTIME, tp); + if (clkid == USBI_CLOCK_MONOTONIC) + return clock_gettime(CLOCK_MONOTONIC, tp); + return LIBUSB_ERROR_INVALID_PARAM; +} + +const struct usbi_os_backend haiku_usb_raw_backend = { + /*.name =*/ "Haiku usbfs", + /*.caps =*/ 0, + /*.init =*/ haiku_init, + /*.exit =*/ haiku_exit, + /*.get_device_list =*/ NULL, + /*.hotplug_poll =*/ NULL, + /*.open =*/ haiku_open, + /*.close =*/ haiku_close, + /*.get_device_descriptor =*/ haiku_get_device_descriptor, + /*.get_active_config_descriptor =*/ haiku_get_active_config_descriptor, + /*.get_config_descriptor =*/ haiku_get_config_descriptor, + /*.get_config_descriptor_by_value =*/ NULL, + + + /*.get_configuration =*/ NULL, + /*.set_configuration =*/ haiku_set_configuration, + /*.claim_interface =*/ haiku_claim_interface, + /*.release_interface =*/ haiku_release_interface, + + /*.set_interface_altsetting =*/ haiku_set_altsetting, + /*.clear_halt =*/ NULL, + /*.reset_device =*/ NULL, + + /*.alloc_streams =*/ NULL, + /*.free_streams =*/ NULL, + + /*.dev_mem_alloc =*/ NULL, + /*.dev_mem_free =*/ NULL, + + /*.kernel_driver_active =*/ NULL, + /*.detach_kernel_driver =*/ NULL, + /*.attach_kernel_driver =*/ NULL, + + /*.destroy_device =*/ NULL, + + /*.submit_transfer =*/ haiku_submit_transfer, + /*.cancel_transfer =*/ haiku_cancel_transfer, + /*.clear_transfer_priv =*/ haiku_clear_transfer_priv, + + /*.handle_events =*/ NULL, + /*.handle_transfer_completion =*/ haiku_handle_transfer_completion, + + /*.clock_gettime =*/ haiku_clock_gettime, + +#ifdef USBI_TIMERFD_AVAILABLE + /*.get_timerfd_clockid =*/ NULL, +#endif + + /*.device_priv_size =*/ sizeof(USBDevice *), + /*.device_handle_priv_size =*/ sizeof(USBDeviceHandle *), + /*.transfer_priv_size =*/ sizeof(USBTransfer *), +}; diff --git a/Externals/libusb/libusb/os/haiku_usb_raw.h b/Externals/libusb/libusb/os/haiku_usb_raw.h new file mode 100644 index 0000000000..5baf53d7c9 --- /dev/null +++ b/Externals/libusb/libusb/os/haiku_usb_raw.h @@ -0,0 +1,180 @@ +/* + * Copyright 2006-2008, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ + +#ifndef _USB_RAW_H_ +#define _USB_RAW_H_ + +#include + +#define B_USB_RAW_PROTOCOL_VERSION 0x0015 +#define B_USB_RAW_ACTIVE_ALTERNATE 0xffffffff + +typedef enum { + B_USB_RAW_COMMAND_GET_VERSION = 0x1000, + + B_USB_RAW_COMMAND_GET_DEVICE_DESCRIPTOR = 0x2000, + B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR, + B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR, + B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR, + B_USB_RAW_COMMAND_GET_STRING_DESCRIPTOR, + B_USB_RAW_COMMAND_GET_GENERIC_DESCRIPTOR, + B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT, + B_USB_RAW_COMMAND_GET_ACTIVE_ALT_INTERFACE_INDEX, + B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR_ETC, + B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR_ETC, + B_USB_RAW_COMMAND_GET_GENERIC_DESCRIPTOR_ETC, + + B_USB_RAW_COMMAND_SET_CONFIGURATION = 0x3000, + B_USB_RAW_COMMAND_SET_FEATURE, + B_USB_RAW_COMMAND_CLEAR_FEATURE, + B_USB_RAW_COMMAND_GET_STATUS, + B_USB_RAW_COMMAND_GET_DESCRIPTOR, + B_USB_RAW_COMMAND_SET_ALT_INTERFACE, + + B_USB_RAW_COMMAND_CONTROL_TRANSFER = 0x4000, + B_USB_RAW_COMMAND_INTERRUPT_TRANSFER, + B_USB_RAW_COMMAND_BULK_TRANSFER, + B_USB_RAW_COMMAND_ISOCHRONOUS_TRANSFER +} usb_raw_command_id; + + +typedef enum { + B_USB_RAW_STATUS_SUCCESS = 0, + + B_USB_RAW_STATUS_FAILED, + B_USB_RAW_STATUS_ABORTED, + B_USB_RAW_STATUS_STALLED, + B_USB_RAW_STATUS_CRC_ERROR, + B_USB_RAW_STATUS_TIMEOUT, + + B_USB_RAW_STATUS_INVALID_CONFIGURATION, + B_USB_RAW_STATUS_INVALID_INTERFACE, + B_USB_RAW_STATUS_INVALID_ENDPOINT, + B_USB_RAW_STATUS_INVALID_STRING, + + B_USB_RAW_STATUS_NO_MEMORY +} usb_raw_command_status; + + +typedef union { + struct { + status_t status; + } version; + + struct { + status_t status; + usb_device_descriptor *descriptor; + } device; + + struct { + status_t status; + usb_configuration_descriptor *descriptor; + uint32 config_index; + } config; + + struct { + status_t status; + uint32 alternate_info; + uint32 config_index; + uint32 interface_index; + } alternate; + + struct { + status_t status; + usb_interface_descriptor *descriptor; + uint32 config_index; + uint32 interface_index; + } interface; + + struct { + status_t status; + usb_interface_descriptor *descriptor; + uint32 config_index; + uint32 interface_index; + uint32 alternate_index; + } interface_etc; + + struct { + status_t status; + usb_endpoint_descriptor *descriptor; + uint32 config_index; + uint32 interface_index; + uint32 endpoint_index; + } endpoint; + + struct { + status_t status; + usb_endpoint_descriptor *descriptor; + uint32 config_index; + uint32 interface_index; + uint32 alternate_index; + uint32 endpoint_index; + } endpoint_etc; + + struct { + status_t status; + usb_descriptor *descriptor; + uint32 config_index; + uint32 interface_index; + uint32 generic_index; + size_t length; + } generic; + + struct { + status_t status; + usb_descriptor *descriptor; + uint32 config_index; + uint32 interface_index; + uint32 alternate_index; + uint32 generic_index; + size_t length; + } generic_etc; + + struct { + status_t status; + usb_string_descriptor *descriptor; + uint32 string_index; + size_t length; + } string; + + struct { + status_t status; + uint8 type; + uint8 index; + uint16 language_id; + void *data; + size_t length; + } descriptor; + + struct { + status_t status; + uint8 request_type; + uint8 request; + uint16 value; + uint16 index; + uint16 length; + void *data; + } control; + + struct { + status_t status; + uint32 interface; + uint32 endpoint; + void *data; + size_t length; + } transfer; + + struct { + status_t status; + uint32 interface; + uint32 endpoint; + void *data; + size_t length; + usb_iso_packet_descriptor *packet_descriptors; + uint32 packet_count; + } isochronous; +} usb_raw_command; + +#endif // _USB_RAW_H_ diff --git a/Externals/libusb/libusb/os/linux_netlink.c b/Externals/libusb/libusb/os/linux_netlink.c index 7a305616dc..60cf3ad1bd 100644 --- a/Externals/libusb/libusb/os/linux_netlink.c +++ b/Externals/libusb/libusb/os/linux_netlink.c @@ -4,6 +4,7 @@ * Copyright (C) 2007-2009 Daniel Drake * Copyright (c) 2001 Johannes Erdfelt * Copyright (c) 2013 Nathan Hjelm + * Copyright (c) 2016 Chris Dickens * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,38 +23,27 @@ #include -#include -#include +#include #include #include #include #include #include #include +#include #include #ifdef HAVE_ASM_TYPES_H #include #endif -#ifdef HAVE_SYS_SOCKET_H #include -#endif - -#include - -#ifdef HAVE_LINUX_NETLINK_H #include -#endif - -#ifdef HAVE_LINUX_FILTER_H -#include -#endif #include "libusbi.h" #include "linux_usbfs.h" -#define KERNEL 1 +#define NL_GROUP_KERNEL 1 static int linux_netlink_socket = -1; static int netlink_control_pipe[2] = { -1, -1 }; @@ -61,30 +51,36 @@ static pthread_t libusb_linux_event_thread; static void *linux_netlink_event_thread_main(void *arg); -struct sockaddr_nl snl = { .nl_family=AF_NETLINK, .nl_groups=KERNEL }; - -static int set_fd_cloexec_nb (int fd) +static int set_fd_cloexec_nb(int fd) { int flags; #if defined(FD_CLOEXEC) - flags = fcntl (linux_netlink_socket, F_GETFD); - if (0 > flags) { + flags = fcntl(fd, F_GETFD); + if (flags == -1) { + usbi_err(NULL, "failed to get netlink fd flags (%d)", errno); return -1; } if (!(flags & FD_CLOEXEC)) { - fcntl (linux_netlink_socket, F_SETFD, flags | FD_CLOEXEC); + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { + usbi_err(NULL, "failed to set netlink fd flags (%d)", errno); + return -1; + } } #endif - flags = fcntl (linux_netlink_socket, F_GETFL); - if (0 > flags) { + flags = fcntl(fd, F_GETFL); + if (flags == -1) { + usbi_err(NULL, "failed to get netlink fd status flags (%d)", errno); return -1; } if (!(flags & O_NONBLOCK)) { - fcntl (linux_netlink_socket, F_SETFL, flags | O_NONBLOCK); + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { + usbi_err(NULL, "failed to set netlink fd status flags (%d)", errno); + return -1; + } } return 0; @@ -92,11 +88,11 @@ static int set_fd_cloexec_nb (int fd) int linux_netlink_start_event_monitor(void) { + struct sockaddr_nl sa_nl = { .nl_family = AF_NETLINK, .nl_groups = NL_GROUP_KERNEL }; int socktype = SOCK_RAW; + int opt = 1; int ret; - snl.nl_groups = KERNEL; - #if defined(SOCK_CLOEXEC) socktype |= SOCK_CLOEXEC; #endif @@ -105,64 +101,71 @@ int linux_netlink_start_event_monitor(void) #endif linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT); - if (-1 == linux_netlink_socket && EINVAL == errno) { + if (linux_netlink_socket == -1 && errno == EINVAL) { + usbi_dbg("failed to create netlink socket of type %d, attempting SOCK_RAW", socktype); linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT); } - if (-1 == linux_netlink_socket) { - return LIBUSB_ERROR_OTHER; + if (linux_netlink_socket == -1) { + usbi_err(NULL, "failed to create netlink socket (%d)", errno); + goto err; } - ret = set_fd_cloexec_nb (linux_netlink_socket); - if (0 != ret) { - close (linux_netlink_socket); - linux_netlink_socket = -1; - return LIBUSB_ERROR_OTHER; + ret = set_fd_cloexec_nb(linux_netlink_socket); + if (ret == -1) + goto err_close_socket; + + ret = bind(linux_netlink_socket, (struct sockaddr *)&sa_nl, sizeof(sa_nl)); + if (ret == -1) { + usbi_err(NULL, "failed to bind netlink socket (%d)", errno); + goto err_close_socket; } - ret = bind(linux_netlink_socket, (struct sockaddr *) &snl, sizeof(snl)); - if (0 != ret) { - close(linux_netlink_socket); - return LIBUSB_ERROR_OTHER; + ret = setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt)); + if (ret == -1) { + usbi_err(NULL, "failed to set netlink socket SO_PASSCRED option (%d)", errno); + goto err_close_socket; } - /* TODO -- add authentication */ - /* setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); */ - ret = usbi_pipe(netlink_control_pipe); if (ret) { - usbi_err(NULL, "could not create netlink control pipe"); - close(linux_netlink_socket); - return LIBUSB_ERROR_OTHER; + usbi_err(NULL, "failed to create netlink control pipe"); + goto err_close_socket; } ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL); - if (0 != ret) { - close(netlink_control_pipe[0]); - close(netlink_control_pipe[1]); - close(linux_netlink_socket); - return LIBUSB_ERROR_OTHER; + if (ret != 0) { + usbi_err(NULL, "failed to create netlink event thread (%d)", ret); + goto err_close_pipe; } return LIBUSB_SUCCESS; + +err_close_pipe: + close(netlink_control_pipe[0]); + close(netlink_control_pipe[1]); + netlink_control_pipe[0] = -1; + netlink_control_pipe[1] = -1; +err_close_socket: + close(linux_netlink_socket); + linux_netlink_socket = -1; +err: + return LIBUSB_ERROR_OTHER; } int linux_netlink_stop_event_monitor(void) { - int r; char dummy = 1; + ssize_t r; - if (-1 == linux_netlink_socket) { - /* already closed. nothing to do */ - return LIBUSB_SUCCESS; - } + assert(linux_netlink_socket != -1); /* Write some dummy data to the control pipe and * wait for the thread to exit */ r = usbi_write(netlink_control_pipe[1], &dummy, sizeof(dummy)); - if (r <= 0) { + if (r <= 0) usbi_warn(NULL, "netlink control pipe signal failed"); - } + pthread_join(libusb_linux_event_thread, NULL); close(linux_netlink_socket); @@ -177,26 +180,25 @@ int linux_netlink_stop_event_monitor(void) return LIBUSB_SUCCESS; } -static const char *netlink_message_parse (const char *buffer, size_t len, const char *key) +static const char *netlink_message_parse(const char *buffer, size_t len, const char *key) { + const char *end = buffer + len; size_t keylen = strlen(key); - size_t offset; - for (offset = 0 ; offset < len && '\0' != buffer[offset] ; offset += strlen(buffer + offset) + 1) { - if (0 == strncmp(buffer + offset, key, keylen) && - '=' == buffer[offset + keylen]) { - return buffer + offset + keylen + 1; - } + while (buffer < end && *buffer) { + if (strncmp(buffer, key, keylen) == 0 && buffer[keylen] == '=') + return buffer + keylen + 1; + buffer += strlen(buffer) + 1; } return NULL; } /* parse parts of netlink message common to both libudev and the kernel */ -static int linux_netlink_parse(char *buffer, size_t len, int *detached, const char **sys_name, - uint8_t *busnum, uint8_t *devaddr) { - const char *tmp; - int i; +static int linux_netlink_parse(const char *buffer, size_t len, int *detached, + const char **sys_name, uint8_t *busnum, uint8_t *devaddr) +{ + const char *tmp, *slash; errno = 0; @@ -205,81 +207,82 @@ static int linux_netlink_parse(char *buffer, size_t len, int *detached, const ch *busnum = 0; *devaddr = 0; - tmp = netlink_message_parse((const char *) buffer, len, "ACTION"); - if (tmp == NULL) + tmp = netlink_message_parse(buffer, len, "ACTION"); + if (!tmp) { return -1; - if (0 == strcmp(tmp, "remove")) { + } else if (strcmp(tmp, "remove") == 0) { *detached = 1; - } else if (0 != strcmp(tmp, "add")) { + } else if (strcmp(tmp, "add") != 0) { usbi_dbg("unknown device action %s", tmp); return -1; } /* check that this is a usb message */ tmp = netlink_message_parse(buffer, len, "SUBSYSTEM"); - if (NULL == tmp || 0 != strcmp(tmp, "usb")) { + if (!tmp || strcmp(tmp, "usb") != 0) { + /* not usb. ignore */ + return -1; + } + + /* check that this is an actual usb device */ + tmp = netlink_message_parse(buffer, len, "DEVTYPE"); + if (!tmp || strcmp(tmp, "usb_device") != 0) { /* not usb. ignore */ return -1; } tmp = netlink_message_parse(buffer, len, "BUSNUM"); - if (NULL == tmp) { + if (tmp) { + *busnum = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff); + if (errno) { + errno = 0; + return -1; + } + + tmp = netlink_message_parse(buffer, len, "DEVNUM"); + if (NULL == tmp) + return -1; + + *devaddr = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff); + if (errno) { + errno = 0; + return -1; + } + } else { /* no bus number. try "DEVICE" */ tmp = netlink_message_parse(buffer, len, "DEVICE"); - if (NULL == tmp) { + if (!tmp) { /* not usb. ignore */ return -1; } - + /* Parse a device path such as /dev/bus/usb/003/004 */ - char *pLastSlash = (char*)strrchr(tmp,'/'); - if(NULL == pLastSlash) { + slash = strrchr(tmp, '/'); + if (!slash) + return -1; + + *busnum = (uint8_t)(strtoul(slash - 3, NULL, 10) & 0xff); + if (errno) { + errno = 0; return -1; } - *devaddr = strtoul(pLastSlash + 1, NULL, 10); + *devaddr = (uint8_t)(strtoul(slash + 1, NULL, 10) & 0xff); if (errno) { errno = 0; return -1; } - - *busnum = strtoul(pLastSlash - 3, NULL, 10); - if (errno) { - errno = 0; - return -1; - } - + return 0; } - *busnum = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff); - if (errno) { - errno = 0; - return -1; - } - - tmp = netlink_message_parse(buffer, len, "DEVNUM"); - if (NULL == tmp) { - return -1; - } - - *devaddr = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff); - if (errno) { - errno = 0; - return -1; - } - tmp = netlink_message_parse(buffer, len, "DEVPATH"); - if (NULL == tmp) { + if (!tmp) return -1; - } - for (i = strlen(tmp) - 1 ; i ; --i) { - if ('/' ==tmp[i]) { - *sys_name = tmp + i + 1; - break; - } - } + slash = strrchr(tmp, '/'); + if (slash) + *sys_name = slash + 1; /* found a usb device */ return 0; @@ -287,28 +290,54 @@ static int linux_netlink_parse(char *buffer, size_t len, int *detached, const ch static int linux_netlink_read_message(void) { - unsigned char buffer[1024]; - struct iovec iov = {.iov_base = buffer, .iov_len = sizeof(buffer)}; - struct msghdr meh = { .msg_iov=&iov, .msg_iovlen=1, - .msg_name=&snl, .msg_namelen=sizeof(snl) }; + char cred_buffer[CMSG_SPACE(sizeof(struct ucred))]; + char msg_buffer[2048]; const char *sys_name = NULL; uint8_t busnum, devaddr; int detached, r; - size_t len; + ssize_t len; + struct cmsghdr *cmsg; + struct ucred *cred; + struct sockaddr_nl sa_nl; + struct iovec iov = { .iov_base = msg_buffer, .iov_len = sizeof(msg_buffer) }; + struct msghdr msg = { + .msg_iov = &iov, .msg_iovlen = 1, + .msg_control = cred_buffer, .msg_controllen = sizeof(cred_buffer), + .msg_name = &sa_nl, .msg_namelen = sizeof(sa_nl) + }; /* read netlink message */ - memset(buffer, 0, sizeof(buffer)); - len = recvmsg(linux_netlink_socket, &meh, 0); - if (len < 32) { - if (errno != EAGAIN) - usbi_dbg("error recieving message from netlink"); + len = recvmsg(linux_netlink_socket, &msg, 0); + if (len == -1) { + if (errno != EAGAIN && errno != EINTR) + usbi_err(NULL, "error receiving message from netlink (%d)", errno); return -1; } - /* TODO -- authenticate this message is from the kernel or udevd */ + if (len < 32 || (msg.msg_flags & MSG_TRUNC)) { + usbi_err(NULL, "invalid netlink message length"); + return -1; + } - r = linux_netlink_parse(buffer, len, &detached, &sys_name, - &busnum, &devaddr); + if (sa_nl.nl_groups != NL_GROUP_KERNEL || sa_nl.nl_pid != 0) { + usbi_dbg("ignoring netlink message from unknown group/PID (%u/%u)", + (unsigned int)sa_nl.nl_groups, (unsigned int)sa_nl.nl_pid); + return -1; + } + + cmsg = CMSG_FIRSTHDR(&msg); + if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) { + usbi_dbg("ignoring netlink message with no sender credentials"); + return -1; + } + + cred = (struct ucred *)CMSG_DATA(cmsg); + if (cred->uid != 0) { + usbi_dbg("ignoring netlink message with non-zero sender UID %u", (unsigned int)cred->uid); + return -1; + } + + r = linux_netlink_parse(msg_buffer, (size_t)len, &detached, &sys_name, &busnum, &devaddr); if (r) return r; @@ -317,7 +346,7 @@ static int linux_netlink_read_message(void) /* signal device is available (or not) to all contexts */ if (detached) - linux_device_disconnected(busnum, devaddr, sys_name); + linux_device_disconnected(busnum, devaddr); else linux_hotplug_enumerate(busnum, devaddr, sys_name); @@ -327,7 +356,7 @@ static int linux_netlink_read_message(void) static void *linux_netlink_event_thread_main(void *arg) { char dummy; - int r; + ssize_t r; struct pollfd fds[] = { { .fd = netlink_control_pipe[0], .events = POLLIN }, @@ -335,25 +364,27 @@ static void *linux_netlink_event_thread_main(void *arg) .events = POLLIN }, }; - /* silence compiler warning */ - (void) arg; + UNUSED(arg); + + usbi_dbg("netlink event thread entering"); while (poll(fds, 2, -1) >= 0) { if (fds[0].revents & POLLIN) { /* activity on control pipe, read the byte and exit */ r = usbi_read(netlink_control_pipe[0], &dummy, sizeof(dummy)); - if (r <= 0) { + if (r <= 0) usbi_warn(NULL, "netlink control pipe read failed"); - } break; } if (fds[1].revents & POLLIN) { - usbi_mutex_static_lock(&linux_hotplug_lock); - linux_netlink_read_message(); - usbi_mutex_static_unlock(&linux_hotplug_lock); + usbi_mutex_static_lock(&linux_hotplug_lock); + linux_netlink_read_message(); + usbi_mutex_static_unlock(&linux_hotplug_lock); } } + usbi_dbg("netlink event thread exiting"); + return NULL; } diff --git a/Externals/libusb/libusb/os/linux_udev.c b/Externals/libusb/libusb/os/linux_udev.c index 6577240f17..ea27142ed9 100644 --- a/Externals/libusb/libusb/os/linux_udev.c +++ b/Externals/libusb/libusb/os/linux_udev.c @@ -69,7 +69,7 @@ int linux_udev_start_event_monitor(void) goto err_free_ctx; } - r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", 0); + r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device"); if (r) { usbi_err(NULL, "could not initialize udev monitor filter for \"usb\" subsystem"); goto err_free_monitor; @@ -240,7 +240,7 @@ static void udev_hotplug_event(struct udev_device* udev_dev) if (strncmp(udev_action, "add", 3) == 0) { linux_hotplug_enumerate(busnum, devaddr, sys_name); } else if (detached) { - linux_device_disconnected(busnum, devaddr, sys_name); + linux_device_disconnected(busnum, devaddr); } else { usbi_err(NULL, "ignoring udev action %s", udev_action); } @@ -266,6 +266,7 @@ int linux_udev_scan_devices(struct libusb_context *ctx) } udev_enumerate_add_match_subsystem(enumerator, "usb"); + udev_enumerate_add_match_property(enumerator, "DEVTYPE", "usb_device"); udev_enumerate_scan_devices(enumerator); devices = udev_enumerate_get_list_entry(enumerator); diff --git a/Externals/libusb/libusb/os/linux_usbfs.c b/Externals/libusb/libusb/os/linux_usbfs.c index 99136ada4c..9cbeb80052 100644 --- a/Externals/libusb/libusb/os/linux_usbfs.c +++ b/Externals/libusb/libusb/os/linux_usbfs.c @@ -33,10 +33,11 @@ #include #include #include +#include #include #include #include -#include +#include #include "libusbi.h" #include "linux_usbfs.h" @@ -121,7 +122,7 @@ static int sysfs_has_descriptors = -1; static int init_count = 0; /* Serialize hotplug start/stop */ -usbi_mutex_static_t linux_hotplug_startstop_lock = USBI_MUTEX_INITIALIZER; +static usbi_mutex_static_t linux_hotplug_startstop_lock = USBI_MUTEX_INITIALIZER; /* Serialize scan-devices, event-thread, and poll */ usbi_mutex_static_t linux_hotplug_lock = USBI_MUTEX_INITIALIZER; @@ -144,6 +145,7 @@ struct linux_device_priv { struct linux_device_handle_priv { int fd; + int fd_removed; uint32_t caps; }; @@ -201,7 +203,7 @@ static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent) usbi_err(ctx, "File doesn't exist, wait %d ms and try again", delay/1000); /* Wait 10ms for USB device path creation.*/ - usleep(delay); + nanosleep(&(struct timespec){delay / 1000000, (delay * 1000) % 1000000000UL}, NULL); fd = open(path, mode); if (fd != -1) @@ -842,6 +844,7 @@ static int op_get_config_descriptor(struct libusb_device *dev, /* send a control message to retrieve active configuration */ static int usbfs_get_active_config(struct libusb_device *dev, int fd) { + struct linux_device_priv *priv = _device_priv(dev); unsigned char active_config = 0; int r; @@ -863,10 +866,23 @@ static int usbfs_get_active_config(struct libusb_device *dev, int fd) /* we hit this error path frequently with buggy devices :( */ usbi_warn(DEVICE_CTX(dev), "get_configuration failed ret=%d errno=%d", r, errno); - return LIBUSB_ERROR_IO; + priv->active_config = -1; + } else { + if (active_config > 0) { + priv->active_config = active_config; + } else { + /* some buggy devices have a configuration 0, but we're + * reaching into the corner of a corner case here, so let's + * not support buggy devices in these circumstances. + * stick to the specs: a configuration value of 0 means + * unconfigured. */ + usbi_warn(DEVICE_CTX(dev), + "active cfg 0? assuming unconfigured device"); + priv->active_config = -1; + } } - return active_config; + return LIBUSB_SUCCESS; } static int initialize_device(struct libusb_device *dev, uint8_t busnum, @@ -882,10 +898,9 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, dev->device_address = devaddr; if (sysfs_dir) { - priv->sysfs_dir = malloc(strlen(sysfs_dir) + 1); + priv->sysfs_dir = strdup(sysfs_dir); if (!priv->sysfs_dir) return LIBUSB_ERROR_NO_MEM; - strcpy(priv->sysfs_dir, sysfs_dir); /* Note speed can contain 1.5, in this case __read_sysfs_attr will stop parsing at the '.' and return 1 */ @@ -966,28 +981,8 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, } r = usbfs_get_active_config(dev, fd); - if (r > 0) { - priv->active_config = r; - r = LIBUSB_SUCCESS; - } else if (r == 0) { - /* some buggy devices have a configuration 0, but we're - * reaching into the corner of a corner case here, so let's - * not support buggy devices in these circumstances. - * stick to the specs: a configuration value of 0 means - * unconfigured. */ - usbi_dbg("active cfg 0? assuming unconfigured device"); - priv->active_config = -1; - r = LIBUSB_SUCCESS; - } else if (r == LIBUSB_ERROR_IO) { - /* buggy devices sometimes fail to report their active config. - * assume unconfigured and continue the probing */ - usbi_warn(ctx, "couldn't query active configuration, assuming" - " unconfigured"); - priv->active_config = -1; - r = LIBUSB_SUCCESS; - } /* else r < 0, just return the error code */ - close(fd); + return r; } @@ -1115,7 +1110,7 @@ void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_na usbi_mutex_static_unlock(&active_contexts_lock); } -void linux_device_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name) +void linux_device_disconnected(uint8_t busnum, uint8_t devaddr) { struct libusb_context *ctx; struct libusb_device *dev; @@ -1299,7 +1294,7 @@ static int op_open(struct libusb_device_handle *handle) if (handle->dev->attached) { usbi_dbg("open failed with no device, but device still attached"); linux_device_disconnected(handle->dev->bus_number, - handle->dev->device_address, NULL); + handle->dev->device_address); } usbi_mutex_static_unlock(&linux_hotplug_lock); } @@ -1319,14 +1314,20 @@ static int op_open(struct libusb_device_handle *handle) hpriv->caps |= USBFS_CAP_BULK_CONTINUATION; } - return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT); + r = usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT); + if (r < 0) + close(hpriv->fd); + + return r; } static void op_close(struct libusb_device_handle *dev_handle) { - int fd = _device_handle_priv(dev_handle)->fd; - usbi_remove_pollfd(HANDLE_CTX(dev_handle), fd); - close(fd); + struct linux_device_handle_priv *hpriv = _device_handle_priv(dev_handle); + /* fd may have already been removed by POLLERR condition in op_handle_events() */ + if (!hpriv->fd_removed) + usbi_remove_pollfd(HANDLE_CTX(dev_handle), hpriv->fd); + close(hpriv->fd); } static int op_get_configuration(struct libusb_device_handle *handle, @@ -1339,6 +1340,8 @@ static int op_get_configuration(struct libusb_device_handle *handle, } else { r = usbfs_get_active_config(handle->dev, _device_handle_priv(handle)->fd); + if (r == LIBUSB_SUCCESS) + *config = _device_priv(handle->dev)->active_config; } if (r < 0) return r; @@ -1555,6 +1558,32 @@ static int op_free_streams(struct libusb_device_handle *handle, endpoints, num_endpoints); } +static unsigned char *op_dev_mem_alloc(struct libusb_device_handle *handle, + size_t len) +{ + struct linux_device_handle_priv *hpriv = _device_handle_priv(handle); + unsigned char *buffer = (unsigned char *)mmap(NULL, len, + PROT_READ | PROT_WRITE, MAP_SHARED, hpriv->fd, 0); + if (buffer == MAP_FAILED) { + usbi_err(HANDLE_CTX(handle), "alloc dev mem failed errno %d", + errno); + return NULL; + } + return buffer; +} + +static int op_dev_mem_free(struct libusb_device_handle *handle, + unsigned char *buffer, size_t len) +{ + if (munmap(buffer, len) != 0) { + usbi_err(HANDLE_CTX(handle), "free dev mem failed errno %d", + errno); + return LIBUSB_ERROR_OTHER; + } else { + return LIBUSB_SUCCESS; + } +} + static int op_kernel_driver_active(struct libusb_device_handle *handle, int interface) { @@ -2595,15 +2624,27 @@ static int op_handle_events(struct libusb_context *ctx, } if (pollfd->revents & POLLERR) { + /* remove the fd from the pollfd set so that it doesn't continuously + * trigger an event, and flag that it has been removed so op_close() + * doesn't try to remove it a second time */ usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fd); - usbi_handle_disconnect(handle); + hpriv->fd_removed = 1; + /* device will still be marked as attached if hotplug monitor thread * hasn't processed remove event yet */ usbi_mutex_static_lock(&linux_hotplug_lock); if (handle->dev->attached) linux_device_disconnected(handle->dev->bus_number, - handle->dev->device_address, NULL); + handle->dev->device_address); usbi_mutex_static_unlock(&linux_hotplug_lock); + + if (hpriv->caps & USBFS_CAP_REAP_AFTER_DISCONNECT) { + do { + r = reap_for_handle(handle); + } while (r == 0); + } + + usbi_handle_disconnect(handle); continue; } @@ -2668,6 +2709,9 @@ const struct usbi_os_backend linux_usbfs_backend = { .alloc_streams = op_alloc_streams, .free_streams = op_free_streams, + .dev_mem_alloc = op_dev_mem_alloc, + .dev_mem_free = op_dev_mem_free, + .kernel_driver_active = op_kernel_driver_active, .detach_kernel_driver = op_detach_kernel_driver, .attach_kernel_driver = op_attach_kernel_driver, diff --git a/Externals/libusb/libusb/os/linux_usbfs.h b/Externals/libusb/libusb/os/linux_usbfs.h index 43fe11bea6..8bd3ebcb16 100644 --- a/Externals/libusb/libusb/os/linux_usbfs.h +++ b/Externals/libusb/libusb/os/linux_usbfs.h @@ -125,6 +125,7 @@ struct usbfs_hub_portinfo { #define USBFS_CAP_BULK_CONTINUATION 0x02 #define USBFS_CAP_NO_PACKET_SIZE_LIM 0x04 #define USBFS_CAP_BULK_SCATTER_GATHER 0x08 +#define USBFS_CAP_REAP_AFTER_DISCONNECT 0x10 #define USBFS_DISCONNECT_CLAIM_IF_DRIVER 0x01 #define USBFS_DISCONNECT_CLAIM_EXCEPT_DRIVER 0x02 @@ -181,7 +182,7 @@ void linux_netlink_hotplug_poll(void); #endif void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_name); -void linux_device_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name); +void linux_device_disconnected(uint8_t busnum, uint8_t devaddr); int linux_get_device_address (struct libusb_context *ctx, int detached, uint8_t *busnum, uint8_t *devaddr, const char *dev_node, diff --git a/Externals/libusb/libusb/os/netbsd_usb.c b/Externals/libusb/libusb/os/netbsd_usb.c index f3b274e352..ad1ede73e1 100644 --- a/Externals/libusb/libusb/os/netbsd_usb.c +++ b/Externals/libusb/libusb/os/netbsd_usb.c @@ -114,6 +114,9 @@ const struct usbi_os_backend netbsd_backend = { NULL, /* alloc_streams */ NULL, /* free_streams */ + NULL, /* dev_mem_alloc() */ + NULL, /* dev_mem_free() */ + NULL, /* kernel_driver_active() */ NULL, /* detach_kernel_driver() */ NULL, /* attach_kernel_driver() */ diff --git a/Externals/libusb/libusb/os/openbsd_usb.c b/Externals/libusb/libusb/os/openbsd_usb.c index cee60dbce2..c660257114 100644 --- a/Externals/libusb/libusb/os/openbsd_usb.c +++ b/Externals/libusb/libusb/os/openbsd_usb.c @@ -117,6 +117,9 @@ const struct usbi_os_backend openbsd_backend = { NULL, /* alloc_streams */ NULL, /* free_streams */ + NULL, /* dev_mem_alloc() */ + NULL, /* dev_mem_free() */ + NULL, /* kernel_driver_active() */ NULL, /* detach_kernel_driver() */ NULL, /* attach_kernel_driver() */ diff --git a/Externals/libusb/libusb/os/poll_windows.c b/Externals/libusb/libusb/os/poll_windows.c index 822bb94097..9825607512 100644 --- a/Externals/libusb/libusb/os/poll_windows.c +++ b/Externals/libusb/libusb/os/poll_windows.c @@ -54,7 +54,7 @@ #define poll_dbg usbi_dbg #else // MSVC++ < 2005 cannot use a variadic argument and non MSVC -// compilers produce warnings if parenthesis are ommitted. +// compilers produce warnings if parenthesis are omitted. #if defined(_MSC_VER) && (_MSC_VER < 1400) #define poll_dbg #else @@ -590,9 +590,9 @@ int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) // If nothing was triggered, wait on all fds that require it if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) { if (timeout < 0) { - poll_dbg("starting infinite wait for %d handles...", (int)nb_handles_to_wait_on); + poll_dbg("starting infinite wait for %u handles...", (unsigned int)nb_handles_to_wait_on); } else { - poll_dbg("starting %d ms wait for %d handles...", timeout, (int)nb_handles_to_wait_on); + poll_dbg("starting %d ms wait for %u handles...", timeout, (unsigned int)nb_handles_to_wait_on); } ret = WaitForMultipleObjects(nb_handles_to_wait_on, handles_to_wait_on, FALSE, (timeout<0)?INFINITE:(DWORD)timeout); @@ -672,7 +672,7 @@ ssize_t usbi_write(int fd, const void *buf, size_t count) return -1; } - poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId()); + poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, (unsigned int)GetCurrentThreadId()); SetEvent(poll_fd[_index].overlapped->hEvent); poll_fd[_index].overlapped->Internal = STATUS_WAIT_0; // If two threads write on the pipe at the same time, we need to @@ -707,12 +707,12 @@ ssize_t usbi_read(int fd, void *buf, size_t count) } if (WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) { - usbi_warn(NULL, "waiting for event failed: %d", (int)GetLastError()); + usbi_warn(NULL, "waiting for event failed: %u", (unsigned int)GetLastError()); errno = EIO; goto out; } - poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId()); + poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, (unsigned int)GetCurrentThreadId()); poll_fd[_index].overlapped->InternalHigh--; // Don't reset unless we don't have any more events to process if (poll_fd[_index].overlapped->InternalHigh <= 0) { diff --git a/Externals/libusb/libusb/os/sunos_usb.c b/Externals/libusb/libusb/os/sunos_usb.c new file mode 100644 index 0000000000..cb608976b6 --- /dev/null +++ b/Externals/libusb/libusb/os/sunos_usb.c @@ -0,0 +1,1292 @@ +/* + * + * Copyright (c) 2016, Oracle and/or its affiliates. + * + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libusbi.h" +#include "sunos_usb.h" + +/* + * Backend functions + */ +static int sunos_init(struct libusb_context *); +static void sunos_exit(void); +static int sunos_get_device_list(struct libusb_context *, + struct discovered_devs **); +static int sunos_open(struct libusb_device_handle *); +static void sunos_close(struct libusb_device_handle *); +static int sunos_get_device_descriptor(struct libusb_device *, + uint8_t*, int *); +static int sunos_get_active_config_descriptor(struct libusb_device *, + uint8_t*, size_t, int *); +static int sunos_get_config_descriptor(struct libusb_device *, uint8_t, + uint8_t*, size_t, int *); +static int sunos_get_configuration(struct libusb_device_handle *, int *); +static int sunos_set_configuration(struct libusb_device_handle *, int); +static int sunos_claim_interface(struct libusb_device_handle *, int); +static int sunos_release_interface(struct libusb_device_handle *, int); +static int sunos_set_interface_altsetting(struct libusb_device_handle *, + int, int); +static int sunos_clear_halt(struct libusb_device_handle *, uint8_t); +static int sunos_reset_device(struct libusb_device_handle *); +static void sunos_destroy_device(struct libusb_device *); +static int sunos_submit_transfer(struct usbi_transfer *); +static int sunos_cancel_transfer(struct usbi_transfer *); +static void sunos_clear_transfer_priv(struct usbi_transfer *); +static int sunos_handle_transfer_completion(struct usbi_transfer *); +static int sunos_clock_gettime(int, struct timespec *); + +/* + * Private functions + */ +static int _errno_to_libusb(int); +static int sunos_usb_get_status(int fd); + +static int sunos_init(struct libusb_context *ctx) +{ + return (LIBUSB_SUCCESS); +} + +static void sunos_exit(void) +{ + usbi_dbg(""); +} + +static int +sunos_fill_in_dev_info(di_node_t node, struct libusb_device *dev) +{ + int proplen; + int n, *addr, *port_prop; + char *phypath; + uint8_t *rdata; + struct libusb_device_descriptor *descr; + sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv; + + /* Device descriptors */ + proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, + "usb-dev-descriptor", &rdata); + if (proplen <= 0) { + + return (LIBUSB_ERROR_IO); + } + + descr = (struct libusb_device_descriptor *)rdata; + bcopy(descr, &dpriv->dev_descr, LIBUSB_DT_DEVICE_SIZE); + dpriv->dev_descr.bcdUSB = libusb_cpu_to_le16(descr->bcdUSB); + dpriv->dev_descr.idVendor = libusb_cpu_to_le16(descr->idVendor); + dpriv->dev_descr.idProduct = libusb_cpu_to_le16(descr->idProduct); + dpriv->dev_descr.bcdDevice = libusb_cpu_to_le16(descr->bcdDevice); + + /* Raw configuration descriptors */ + proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, + "usb-raw-cfg-descriptors", &rdata); + if (proplen <= 0) { + usbi_dbg("can't find raw config descriptors"); + + return (LIBUSB_ERROR_IO); + } + dpriv->raw_cfgdescr = calloc(1, proplen); + if (dpriv->raw_cfgdescr == NULL) { + return (LIBUSB_ERROR_NO_MEM); + } else { + bcopy(rdata, dpriv->raw_cfgdescr, proplen); + dpriv->cfgvalue = ((struct libusb_config_descriptor *) + rdata)->bConfigurationValue; + } + + n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &port_prop); + + if ((n != 1) || (*port_prop <= 0)) { + return (LIBUSB_ERROR_IO); + } + dev->port_number = *port_prop; + + /* device physical path */ + phypath = di_devfs_path(node); + if (phypath) { + dpriv->phypath = strdup(phypath); + di_devfs_path_free(phypath); + } else { + free(dpriv->raw_cfgdescr); + + return (LIBUSB_ERROR_IO); + } + + /* address */ + n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "assigned-address", &addr); + if (n != 1 || *addr == 0) { + usbi_dbg("can't get address"); + } else { + dev->device_address = *addr; + } + + /* speed */ + if (di_prop_exists(DDI_DEV_T_ANY, node, "low-speed") == 1) { + dev->speed = LIBUSB_SPEED_LOW; + } else if (di_prop_exists(DDI_DEV_T_ANY, node, "high-speed") == 1) { + dev->speed = LIBUSB_SPEED_HIGH; + } else if (di_prop_exists(DDI_DEV_T_ANY, node, "full-speed") == 1) { + dev->speed = LIBUSB_SPEED_FULL; + } else if (di_prop_exists(DDI_DEV_T_ANY, node, "super-speed") == 1) { + dev->speed = LIBUSB_SPEED_SUPER; + } + + usbi_dbg("vid=%x pid=%x, path=%s, bus_nmber=0x%x, port_number=%d, " + "speed=%d", dpriv->dev_descr.idVendor, dpriv->dev_descr.idProduct, + dpriv->phypath, dev->bus_number, dev->port_number, dev->speed); + + return (LIBUSB_SUCCESS); +} + + +static int +sunos_add_devices(di_devlink_t link, void *arg) +{ + struct devlink_cbarg *largs = (struct devlink_cbarg *)arg; + struct node_args *nargs; + di_node_t myself, pnode; + uint64_t session_id = 0; + uint16_t bdf = 0; + struct libusb_device *dev; + sunos_dev_priv_t *devpriv; + const char *path, *newpath; + int n, i; + int *addr_prop; + uint8_t bus_number = 0; + + nargs = (struct node_args *)largs->nargs; + myself = largs->myself; + if (nargs->last_ugenpath) { + /* the same node's links */ + return (DI_WALK_CONTINUE); + } + + /* + * Construct session ID. + * session ID = ...parent hub addr|hub addr|dev addr. + */ + pnode = myself; + i = 0; + while (pnode != DI_NODE_NIL) { + if (di_prop_exists(DDI_DEV_T_ANY, pnode, "root-hub") == 1) { + /* walk to root */ + uint32_t *regbuf = NULL; + uint32_t reg; + + n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode, "reg", + (int **)®buf); + reg = regbuf[0]; + bdf = (PCI_REG_BUS_G(reg) << 8) | + (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg); + session_id |= (bdf << i * 8); + + /* same as 'unit-address' property */ + bus_number = + (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg); + + usbi_dbg("device bus address=%s:%x", + di_bus_addr(pnode), bus_number); + + break; + } + + /* usb_addr */ + n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode, + "assigned-address", &addr_prop); + if ((n != 1) || (addr_prop[0] == 0)) { + usbi_dbg("cannot get valid usb_addr"); + + return (DI_WALK_CONTINUE); + } + + session_id |= ((addr_prop[0] & 0xff) << i * 8); + if (++i > 7) + break; + + pnode = di_parent_node(pnode); + } + + path = di_devlink_path(link); + dev = usbi_get_device_by_session_id(nargs->ctx, session_id); + if (dev == NULL) { + dev = usbi_alloc_device(nargs->ctx, session_id); + if (dev == NULL) { + usbi_dbg("can't alloc device"); + + return (DI_WALK_TERMINATE); + } + devpriv = (sunos_dev_priv_t *)dev->os_priv; + if ((newpath = strrchr(path, '/')) == NULL) { + libusb_unref_device(dev); + + return (DI_WALK_TERMINATE); + } + devpriv->ugenpath = strndup(path, strlen(path) - + strlen(newpath)); + dev->bus_number = bus_number; + + if (sunos_fill_in_dev_info(myself, dev) != LIBUSB_SUCCESS) { + libusb_unref_device(dev); + + return (DI_WALK_TERMINATE); + } + if (usbi_sanitize_device(dev) < 0) { + libusb_unref_device(dev); + usbi_dbg("sanatize failed: "); + return (DI_WALK_TERMINATE); + } + } else { + usbi_dbg("Dev %s exists", path); + } + + devpriv = (sunos_dev_priv_t *)dev->os_priv; + if (nargs->last_ugenpath == NULL) { + /* first device */ + nargs->last_ugenpath = devpriv->ugenpath; + + if (discovered_devs_append(*(nargs->discdevs), dev) == NULL) { + usbi_dbg("cannot append device"); + } + + /* + * we alloc and hence ref this dev. We don't need to ref it + * hereafter. Front end or app should take care of their ref. + */ + libusb_unref_device(dev); + } + + usbi_dbg("Device %s %s id=0x%llx, devcount:%d, bdf=%x", + devpriv->ugenpath, path, (uint64_t)session_id, + (*nargs->discdevs)->len, bdf); + + return (DI_WALK_CONTINUE); +} + +static int +sunos_walk_minor_node_link(di_node_t node, void *args) +{ + di_minor_t minor = DI_MINOR_NIL; + char *minor_path; + struct devlink_cbarg arg; + struct node_args *nargs = (struct node_args *)args; + di_devlink_handle_t devlink_hdl = nargs->dlink_hdl; + + /* walk each minor to find ugen devices */ + while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { + minor_path = di_devfs_minor_path(minor); + arg.nargs = args; + arg.myself = node; + arg.minor = minor; + (void) di_devlink_walk(devlink_hdl, + "^usb/[0-9a-f]+[.][0-9a-f]+", minor_path, + DI_PRIMARY_LINK, (void *)&arg, sunos_add_devices); + di_devfs_path_free(minor_path); + } + + /* switch to a different node */ + nargs->last_ugenpath = NULL; + + return (DI_WALK_CONTINUE); +} + +int +sunos_get_device_list(struct libusb_context * ctx, + struct discovered_devs **discdevs) +{ + di_node_t root_node; + struct node_args args; + di_devlink_handle_t devlink_hdl; + + args.ctx = ctx; + args.discdevs = discdevs; + args.last_ugenpath = NULL; + if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { + usbi_dbg("di_int() failed: %s", strerror(errno)); + return (LIBUSB_ERROR_IO); + } + + if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) { + di_fini(root_node); + usbi_dbg("di_devlink_init() failed: %s", strerror(errno)); + + return (LIBUSB_ERROR_IO); + } + args.dlink_hdl = devlink_hdl; + + /* walk each node to find USB devices */ + if (di_walk_node(root_node, DI_WALK_SIBFIRST, &args, + sunos_walk_minor_node_link) == -1) { + usbi_dbg("di_walk_node() failed: %s", strerror(errno)); + di_fini(root_node); + + return (LIBUSB_ERROR_IO); + } + + di_fini(root_node); + di_devlink_fini(&devlink_hdl); + + usbi_dbg("%d devices", (*discdevs)->len); + + return ((*discdevs)->len); +} + +static int +sunos_usb_open_ep0(sunos_dev_handle_priv_t *hpriv, sunos_dev_priv_t *dpriv) +{ + char filename[PATH_MAX + 1]; + + if (hpriv->eps[0].datafd > 0) { + + return (LIBUSB_SUCCESS); + } + snprintf(filename, PATH_MAX, "%s/cntrl0", dpriv->ugenpath); + + usbi_dbg("opening %s", filename); + hpriv->eps[0].datafd = open(filename, O_RDWR); + if (hpriv->eps[0].datafd < 0) { + return(_errno_to_libusb(errno)); + } + + snprintf(filename, PATH_MAX, "%s/cntrl0stat", dpriv->ugenpath); + hpriv->eps[0].statfd = open(filename, O_RDONLY); + if (hpriv->eps[0].statfd < 0) { + close(hpriv->eps[0].datafd); + hpriv->eps[0].datafd = -1; + + return(_errno_to_libusb(errno)); + } + + return (LIBUSB_SUCCESS); +} + +static void +sunos_usb_close_all_eps(sunos_dev_handle_priv_t *hdev) +{ + int i; + + /* not close ep0 */ + for (i = 1; i < USB_MAXENDPOINTS; i++) { + if (hdev->eps[i].datafd != -1) { + (void) close(hdev->eps[i].datafd); + hdev->eps[i].datafd = -1; + } + if (hdev->eps[i].statfd != -1) { + (void) close(hdev->eps[i].statfd); + hdev->eps[i].statfd = -1; + } + } +} + +static void +sunos_usb_close_ep0(sunos_dev_handle_priv_t *hdev, sunos_dev_priv_t *dpriv) +{ + if (hdev->eps[0].datafd >= 0) { + close(hdev->eps[0].datafd); + close(hdev->eps[0].statfd); + hdev->eps[0].datafd = -1; + hdev->eps[0].statfd = -1; + } +} + +static uchar_t +sunos_usb_ep_index(uint8_t ep_addr) +{ + return ((ep_addr & LIBUSB_ENDPOINT_ADDRESS_MASK) + + ((ep_addr & LIBUSB_ENDPOINT_DIR_MASK) ? 16 : 0)); +} + +static int +sunos_find_interface(struct libusb_device_handle *hdev, + uint8_t endpoint, uint8_t *interface) +{ + struct libusb_config_descriptor *config; + int r; + int iface_idx; + + r = libusb_get_active_config_descriptor(hdev->dev, &config); + if (r < 0) { + return (LIBUSB_ERROR_INVALID_PARAM); + } + + for (iface_idx = 0; iface_idx < config->bNumInterfaces; iface_idx++) { + const struct libusb_interface *iface = + &config->interface[iface_idx]; + int altsetting_idx; + + for (altsetting_idx = 0; altsetting_idx < iface->num_altsetting; + altsetting_idx++) { + const struct libusb_interface_descriptor *altsetting = + &iface->altsetting[altsetting_idx]; + int ep_idx; + + for (ep_idx = 0; ep_idx < altsetting->bNumEndpoints; + ep_idx++) { + const struct libusb_endpoint_descriptor *ep = + &altsetting->endpoint[ep_idx]; + if (ep->bEndpointAddress == endpoint) { + *interface = iface_idx; + libusb_free_config_descriptor(config); + + return (LIBUSB_SUCCESS); + } + } + } + } + libusb_free_config_descriptor(config); + + return (LIBUSB_ERROR_INVALID_PARAM); +} + +static int +sunos_check_device_and_status_open(struct libusb_device_handle *hdl, + uint8_t ep_addr, int ep_type) +{ + char filename[PATH_MAX + 1], statfilename[PATH_MAX + 1]; + char cfg_num[16], alt_num[16]; + int fd, fdstat, mode; + uint8_t ifc = 0; + uint8_t ep_index; + sunos_dev_handle_priv_t *hpriv; + + usbi_dbg("open ep 0x%02x", ep_addr); + hpriv = (sunos_dev_handle_priv_t *)hdl->os_priv; + ep_index = sunos_usb_ep_index(ep_addr); + /* ep already opened */ + if ((hpriv->eps[ep_index].datafd > 0) && + (hpriv->eps[ep_index].statfd > 0)) { + usbi_dbg("ep 0x%02x already opened, return success", + ep_addr); + + return (0); + } + + if (sunos_find_interface(hdl, ep_addr, &ifc) < 0) { + usbi_dbg("can't find interface for endpoint 0x%02x", + ep_addr); + + return (LIBUSB_ERROR_ACCESS); + } + + /* create filename */ + if (hpriv->config_index > 0) { + (void) snprintf(cfg_num, sizeof (cfg_num), "cfg%d", + hpriv->config_index + 1); + } else { + bzero(cfg_num, sizeof (cfg_num)); + } + + if (hpriv->altsetting[ifc] > 0) { + (void) snprintf(alt_num, sizeof (alt_num), ".%d", + hpriv->altsetting[ifc]); + } else { + bzero(alt_num, sizeof (alt_num)); + } + + (void) snprintf(filename, PATH_MAX, "%s/%sif%d%s%s%d", + hpriv->dpriv->ugenpath, cfg_num, ifc, alt_num, + (ep_addr & LIBUSB_ENDPOINT_DIR_MASK) ? "in" : + "out", (ep_addr & LIBUSB_ENDPOINT_ADDRESS_MASK)); + (void) snprintf(statfilename, PATH_MAX, "%sstat", filename); + + /* + * for interrupt IN endpoints, we need to enable one xfer + * mode before opening the endpoint + */ + if ((ep_type == LIBUSB_TRANSFER_TYPE_INTERRUPT) && + (ep_addr & LIBUSB_ENDPOINT_IN)) { + char control = USB_EP_INTR_ONE_XFER; + int count; + + /* open the status device node for the ep first RDWR */ + if ((fdstat = open(statfilename, O_RDWR)) == -1) { + usbi_dbg("can't open %s RDWR: %d", + statfilename, errno); + } else { + count = write(fdstat, &control, sizeof (control)); + if (count != 1) { + /* this should have worked */ + usbi_dbg("can't write to %s: %d", + statfilename, errno); + (void) close(fdstat); + + return (errno); + } + /* close status node and open xfer node first */ + close (fdstat); + } + } + + /* open the xfer node first in case alt needs to be changed */ + if (ep_type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { + mode = O_RDWR; + } else if (ep_addr & LIBUSB_ENDPOINT_IN) { + mode = O_RDONLY; + } else { + mode = O_WRONLY; + } + + /* + * IMPORTANT: must open data xfer node first and then open stat node + * Otherwise, it will fail on multi-config or multi-altsetting devices + * with "Device Busy" error. See ugen_epxs_switch_cfg_alt() and + * ugen_epxs_check_alt_switch() in ugen driver source code. + */ + if ((fd = open(filename, mode)) == -1) { + usbi_dbg("can't open %s: %d(%s)", filename, errno, + strerror(errno)); + + return (errno); + } + /* open the status node */ + if ((fdstat = open(statfilename, O_RDONLY)) == -1) { + usbi_dbg("can't open %s: %d", statfilename, errno); + + (void) close(fd); + + return (errno); + } + + hpriv->eps[ep_index].datafd = fd; + hpriv->eps[ep_index].statfd = fdstat; + usbi_dbg("ep=0x%02x datafd=%d, statfd=%d", ep_addr, fd, fdstat); + + return (0); +} + +int +sunos_open(struct libusb_device_handle *handle) +{ + sunos_dev_handle_priv_t *hpriv; + sunos_dev_priv_t *dpriv; + int i; + int ret; + + hpriv = (sunos_dev_handle_priv_t *)handle->os_priv; + dpriv = (sunos_dev_priv_t *)handle->dev->os_priv; + hpriv->dpriv = dpriv; + + /* set all file descriptors to "closed" */ + for (i = 0; i < USB_MAXENDPOINTS; i++) { + hpriv->eps[i].datafd = -1; + hpriv->eps[i].statfd = -1; + } + + if ((ret = sunos_usb_open_ep0(hpriv, dpriv)) != LIBUSB_SUCCESS) { + usbi_dbg("fail: %d", ret); + return (ret); + } + + return (LIBUSB_SUCCESS); +} + +void +sunos_close(struct libusb_device_handle *handle) +{ + sunos_dev_handle_priv_t *hpriv; + sunos_dev_priv_t *dpriv; + + usbi_dbg(""); + if (!handle) { + return; + } + + hpriv = (sunos_dev_handle_priv_t *)handle->os_priv; + if (!hpriv) { + return; + } + dpriv = (sunos_dev_priv_t *)handle->dev->os_priv; + if (!dpriv) { + return; + } + + sunos_usb_close_all_eps(hpriv); + sunos_usb_close_ep0(hpriv, dpriv); +} + +int +sunos_get_device_descriptor(struct libusb_device *dev, uint8_t *buf, + int *host_endian) +{ + sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv; + + memcpy(buf, &dpriv->dev_descr, LIBUSB_DT_DEVICE_SIZE); + *host_endian = 0; + + return (LIBUSB_SUCCESS); +} + +int +sunos_get_active_config_descriptor(struct libusb_device *dev, + uint8_t *buf, size_t len, int *host_endian) +{ + sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv; + struct libusb_config_descriptor *cfg; + int proplen; + di_node_t node; + uint8_t *rdata; + + /* + * Keep raw configuration descriptors updated, in case config + * has ever been changed through setCfg. + */ + if ((node = di_init(dpriv->phypath, DINFOCPYALL)) == DI_NODE_NIL) { + usbi_dbg("di_int() failed: %s", strerror(errno)); + return (LIBUSB_ERROR_IO); + } + proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, + "usb-raw-cfg-descriptors", &rdata); + if (proplen <= 0) { + usbi_dbg("can't find raw config descriptors"); + + return (LIBUSB_ERROR_IO); + } + dpriv->raw_cfgdescr = realloc(dpriv->raw_cfgdescr, proplen); + if (dpriv->raw_cfgdescr == NULL) { + return (LIBUSB_ERROR_NO_MEM); + } else { + bcopy(rdata, dpriv->raw_cfgdescr, proplen); + dpriv->cfgvalue = ((struct libusb_config_descriptor *) + rdata)->bConfigurationValue; + } + di_fini(node); + + cfg = (struct libusb_config_descriptor *)dpriv->raw_cfgdescr; + len = MIN(len, libusb_le16_to_cpu(cfg->wTotalLength)); + memcpy(buf, dpriv->raw_cfgdescr, len); + *host_endian = 0; + usbi_dbg("path:%s len %d", dpriv->phypath, len); + + return (len); +} + +int +sunos_get_config_descriptor(struct libusb_device *dev, uint8_t idx, + uint8_t *buf, size_t len, int *host_endian) +{ + /* XXX */ + return(sunos_get_active_config_descriptor(dev, buf, len, host_endian)); +} + +int +sunos_get_configuration(struct libusb_device_handle *handle, int *config) +{ + sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)handle->dev->os_priv; + + *config = dpriv->cfgvalue; + + usbi_dbg("bConfigurationValue %d", *config); + + return (LIBUSB_SUCCESS); +} + +int +sunos_set_configuration(struct libusb_device_handle *handle, int config) +{ + sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)handle->dev->os_priv; + sunos_dev_handle_priv_t *hpriv; + + usbi_dbg("bConfigurationValue %d", config); + hpriv = (sunos_dev_handle_priv_t *)handle->os_priv; + + if (dpriv->ugenpath == NULL) + return (LIBUSB_ERROR_NOT_SUPPORTED); + + if (config < 1 || config > dpriv->dev_descr.bNumConfigurations) + return (LIBUSB_ERROR_INVALID_PARAM); + + dpriv->cfgvalue = config; + hpriv->config_index = config - 1; + + return (LIBUSB_SUCCESS); +} + +int +sunos_claim_interface(struct libusb_device_handle *handle, int iface) +{ + usbi_dbg("iface %d", iface); + if (iface < 0) { + return (LIBUSB_ERROR_INVALID_PARAM); + } + + return (LIBUSB_SUCCESS); +} + +int +sunos_release_interface(struct libusb_device_handle *handle, int iface) +{ + sunos_dev_handle_priv_t *hpriv = + (sunos_dev_handle_priv_t *)handle->os_priv; + + usbi_dbg("iface %d", iface); + if (iface < 0) { + return (LIBUSB_ERROR_INVALID_PARAM); + } + + /* XXX: can we release it? */ + hpriv->altsetting[iface] = 0; + + return (LIBUSB_SUCCESS); +} + +int +sunos_set_interface_altsetting(struct libusb_device_handle *handle, int iface, + int altsetting) +{ + sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)handle->dev->os_priv; + sunos_dev_handle_priv_t *hpriv = + (sunos_dev_handle_priv_t *)handle->os_priv; + + usbi_dbg("iface %d, setting %d", iface, altsetting); + + if (iface < 0 || altsetting < 0) { + return (LIBUSB_ERROR_INVALID_PARAM); + } + if (dpriv->ugenpath == NULL) + return (LIBUSB_ERROR_NOT_FOUND); + + /* XXX: can we switch altsetting? */ + hpriv->altsetting[iface] = altsetting; + + return (LIBUSB_SUCCESS); +} + +static void +usb_dump_data(unsigned char *data, size_t size) +{ + int i; + + if (getenv("LIBUSB_DEBUG") == NULL) { + return; + } + + (void) fprintf(stderr, "data dump:"); + for (i = 0; i < size; i++) { + if (i % 16 == 0) { + (void) fprintf(stderr, "\n%08x ", i); + } + (void) fprintf(stderr, "%02x ", (uchar_t)data[i]); + } + (void) fprintf(stderr, "\n"); +} + +static void +sunos_async_callback(union sigval arg) +{ + struct sunos_transfer_priv *tpriv = + (struct sunos_transfer_priv *)arg.sival_ptr; + struct libusb_transfer *xfer = tpriv->transfer; + struct aiocb *aiocb = &tpriv->aiocb; + int ret; + sunos_dev_handle_priv_t *hpriv; + uint8_t ep; + + hpriv = (sunos_dev_handle_priv_t *)xfer->dev_handle->os_priv; + ep = sunos_usb_ep_index(xfer->endpoint); + + ret = aio_error(aiocb); + if (ret != 0) { + xfer->status = sunos_usb_get_status(hpriv->eps[ep].statfd); + } else { + xfer->actual_length = + LIBUSB_TRANSFER_TO_USBI_TRANSFER(xfer)->transferred = + aio_return(aiocb); + } + + usb_dump_data(xfer->buffer, xfer->actual_length); + + usbi_dbg("ret=%d, len=%d, actual_len=%d", ret, xfer->length, + xfer->actual_length); + + /* async notification */ + usbi_signal_transfer_completion(LIBUSB_TRANSFER_TO_USBI_TRANSFER(xfer)); +} + +static int +sunos_do_async_io(struct libusb_transfer *transfer) +{ + int ret = -1; + struct aiocb *aiocb; + sunos_dev_handle_priv_t *hpriv; + uint8_t ep; + struct sunos_transfer_priv *tpriv; + + usbi_dbg(""); + + tpriv = usbi_transfer_get_os_priv(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)); + hpriv = (sunos_dev_handle_priv_t *)transfer->dev_handle->os_priv; + ep = sunos_usb_ep_index(transfer->endpoint); + + tpriv->transfer = transfer; + aiocb = &tpriv->aiocb; + bzero(aiocb, sizeof (*aiocb)); + aiocb->aio_fildes = hpriv->eps[ep].datafd; + aiocb->aio_buf = transfer->buffer; + aiocb->aio_nbytes = transfer->length; + aiocb->aio_lio_opcode = + ((transfer->endpoint & LIBUSB_ENDPOINT_DIR_MASK) == + LIBUSB_ENDPOINT_IN) ? LIO_READ:LIO_WRITE; + aiocb->aio_sigevent.sigev_notify = SIGEV_THREAD; + aiocb->aio_sigevent.sigev_value.sival_ptr = tpriv; + aiocb->aio_sigevent.sigev_notify_function = sunos_async_callback; + + if (aiocb->aio_lio_opcode == LIO_READ) { + ret = aio_read(aiocb); + } else { + ret = aio_write(aiocb); + } + + return (ret); +} + +/* return the number of bytes read/written */ +static int +usb_do_io(int fd, int stat_fd, char *data, size_t size, int flag, int *status) +{ + int error; + int ret = -1; + + usbi_dbg("usb_do_io(): datafd=%d statfd=%d size=0x%x flag=%s", + fd, stat_fd, size, flag? "WRITE":"READ"); + + switch (flag) { + case READ: + errno = 0; + ret = read(fd, data, size); + usb_dump_data(data, size); + break; + case WRITE: + usb_dump_data(data, size); + errno = 0; + ret = write(fd, data, size); + break; + } + + usbi_dbg("usb_do_io(): amount=%d", ret); + + if (ret < 0) { + int save_errno = errno; + + usbi_dbg("TID=%x io %s errno=%d(%s) ret=%d", pthread_self(), + flag?"WRITE":"READ", errno, strerror(errno), ret); + + /* sunos_usb_get_status will do a read and overwrite errno */ + error = sunos_usb_get_status(stat_fd); + usbi_dbg("io status=%d errno=%d(%s)", error, + save_errno, strerror(save_errno)); + + if (status) { + *status = save_errno; + } + + return (save_errno); + + } else if (status) { + *status = 0; + } + + return (ret); +} + +static int +solaris_submit_ctrl_on_default(struct libusb_transfer *transfer) +{ + int ret = -1, setup_ret; + int status; + sunos_dev_handle_priv_t *hpriv; + struct libusb_device_handle *hdl = transfer->dev_handle; + uint16_t wLength; + uint8_t *data = transfer->buffer; + + hpriv = (sunos_dev_handle_priv_t *)hdl->os_priv; + wLength = transfer->length - LIBUSB_CONTROL_SETUP_SIZE; + + if (hpriv->eps[0].datafd == -1) { + usbi_dbg("ep0 not opened"); + + return (LIBUSB_ERROR_NOT_FOUND); + } + + if ((data[0] & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) { + usbi_dbg("IN request"); + ret = usb_do_io(hpriv->eps[0].datafd, + hpriv->eps[0].statfd, (char *)data, LIBUSB_CONTROL_SETUP_SIZE, + WRITE, (int *)&status); + } else { + usbi_dbg("OUT request"); + ret = usb_do_io(hpriv->eps[0].datafd, hpriv->eps[0].statfd, + transfer->buffer, transfer->length, WRITE, + (int *)&transfer->status); + } + + setup_ret = ret; + if (ret < LIBUSB_CONTROL_SETUP_SIZE) { + usbi_dbg("error sending control msg: %d", ret); + + return (LIBUSB_ERROR_IO); + } + + ret = transfer->length - LIBUSB_CONTROL_SETUP_SIZE; + + /* Read the remaining bytes for IN request */ + if ((wLength) && ((data[0] & LIBUSB_ENDPOINT_DIR_MASK) == + LIBUSB_ENDPOINT_IN)) { + usbi_dbg("DATA: %d", transfer->length - setup_ret); + ret = usb_do_io(hpriv->eps[0].datafd, + hpriv->eps[0].statfd, + (char *)transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, + wLength, READ, (int *)&transfer->status); + } + + if (ret >= 0) { + transfer->actual_length = ret; + LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)->transferred = ret; + } + usbi_dbg("Done: ctrl data bytes %d", ret); + + /* sync transfer handling */ + ret = usbi_handle_transfer_completion(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer), + transfer->status); + + return (ret); +} + +int +sunos_clear_halt(struct libusb_device_handle *handle, uint8_t endpoint) +{ + int ret; + + usbi_dbg("endpoint=0x%02x", endpoint); + + ret = libusb_control_transfer(handle, LIBUSB_ENDPOINT_OUT | + LIBUSB_RECIPIENT_ENDPOINT | LIBUSB_REQUEST_TYPE_STANDARD, + LIBUSB_REQUEST_CLEAR_FEATURE, 0, endpoint, NULL, 0, 1000); + + usbi_dbg("ret=%d", ret); + + return (ret); +} + +int +sunos_reset_device(struct libusb_device_handle *handle) +{ + usbi_dbg(""); + + return (LIBUSB_ERROR_NOT_SUPPORTED); +} + +void +sunos_destroy_device(struct libusb_device *dev) +{ + sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv; + + usbi_dbg(""); + + free(dpriv->raw_cfgdescr); + free(dpriv->ugenpath); + free(dpriv->phypath); +} + +int +sunos_submit_transfer(struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer; + struct libusb_device_handle *hdl; + int err = 0; + + transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + hdl = transfer->dev_handle; + + err = sunos_check_device_and_status_open(hdl, + transfer->endpoint, transfer->type); + if (err < 0) { + + return (_errno_to_libusb(err)); + } + + switch (transfer->type) { + case LIBUSB_TRANSFER_TYPE_CONTROL: + /* sync transfer */ + usbi_dbg("CTRL transfer: %d", transfer->length); + err = solaris_submit_ctrl_on_default(transfer); + break; + + case LIBUSB_TRANSFER_TYPE_BULK: + /* fallthru */ + case LIBUSB_TRANSFER_TYPE_INTERRUPT: + if (transfer->type == LIBUSB_TRANSFER_TYPE_BULK) + usbi_dbg("BULK transfer: %d", transfer->length); + else + usbi_dbg("INTR transfer: %d", transfer->length); + err = sunos_do_async_io(transfer); + break; + + case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: + /* Isochronous/Stream is not supported */ + + /* fallthru */ + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: + if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) + usbi_dbg("ISOC transfer: %d", transfer->length); + else + usbi_dbg("BULK STREAM transfer: %d", transfer->length); + err = LIBUSB_ERROR_NOT_SUPPORTED; + break; + } + + return (err); +} + +int +sunos_cancel_transfer(struct usbi_transfer *itransfer) +{ + sunos_xfer_priv_t *tpriv; + sunos_dev_handle_priv_t *hpriv; + struct libusb_transfer *transfer; + struct aiocb *aiocb; + uint8_t ep; + int ret; + + tpriv = usbi_transfer_get_os_priv(itransfer); + aiocb = &tpriv->aiocb; + transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + hpriv = (sunos_dev_handle_priv_t *)transfer->dev_handle->os_priv; + ep = sunos_usb_ep_index(transfer->endpoint); + + ret = aio_cancel(hpriv->eps[ep].datafd, aiocb); + + usbi_dbg("aio->fd=%d fd=%d ret = %d, %s", aiocb->aio_fildes, + hpriv->eps[ep].datafd, ret, (ret == AIO_CANCELED)? + strerror(0):strerror(errno)); + + if (ret != AIO_CANCELED) { + ret = _errno_to_libusb(errno); + } else { + /* + * we don't need to call usbi_handle_transfer_cancellation(), + * because we'll handle everything in sunos_async_callback. + */ + ret = LIBUSB_SUCCESS; + } + + return (ret); +} + +void +sunos_clear_transfer_priv(struct usbi_transfer *itransfer) +{ + usbi_dbg(""); + + /* Nothing to do */ +} + +int +sunos_handle_transfer_completion(struct usbi_transfer *itransfer) +{ + return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED); +} + +int +sunos_clock_gettime(int clkid, struct timespec *tp) +{ + usbi_dbg("clock %d", clkid); + + if (clkid == USBI_CLOCK_REALTIME) + return clock_gettime(CLOCK_REALTIME, tp); + + if (clkid == USBI_CLOCK_MONOTONIC) + return clock_gettime(CLOCK_MONOTONIC, tp); + + return (LIBUSB_ERROR_INVALID_PARAM); +} + +int +_errno_to_libusb(int err) +{ + usbi_dbg("error: %s (%d)", strerror(err), err); + + switch (err) { + case EIO: + return (LIBUSB_ERROR_IO); + case EACCES: + return (LIBUSB_ERROR_ACCESS); + case ENOENT: + return (LIBUSB_ERROR_NO_DEVICE); + case ENOMEM: + return (LIBUSB_ERROR_NO_MEM); + case ETIMEDOUT: + return (LIBUSB_ERROR_TIMEOUT); + } + + return (LIBUSB_ERROR_OTHER); +} + +/* + * sunos_usb_get_status: + * gets status of endpoint + * + * Returns: ugen's last cmd status + */ +static int +sunos_usb_get_status(int fd) +{ + int status, ret; + + usbi_dbg("sunos_usb_get_status(): fd=%d", fd); + + ret = read(fd, &status, sizeof (status)); + if (ret == sizeof (status)) { + switch (status) { + case USB_LC_STAT_NOERROR: + usbi_dbg("No Error"); + break; + case USB_LC_STAT_CRC: + usbi_dbg("CRC Timeout Detected\n"); + break; + case USB_LC_STAT_BITSTUFFING: + usbi_dbg("Bit Stuffing Violation\n"); + break; + case USB_LC_STAT_DATA_TOGGLE_MM: + usbi_dbg("Data Toggle Mismatch\n"); + break; + case USB_LC_STAT_STALL: + usbi_dbg("End Point Stalled\n"); + break; + case USB_LC_STAT_DEV_NOT_RESP: + usbi_dbg("Device is Not Responding\n"); + break; + case USB_LC_STAT_PID_CHECKFAILURE: + usbi_dbg("PID Check Failure\n"); + break; + case USB_LC_STAT_UNEXP_PID: + usbi_dbg("Unexpected PID\n"); + break; + case USB_LC_STAT_DATA_OVERRUN: + usbi_dbg("Data Exceeded Size\n"); + break; + case USB_LC_STAT_DATA_UNDERRUN: + usbi_dbg("Less data received\n"); + break; + case USB_LC_STAT_BUFFER_OVERRUN: + usbi_dbg("Buffer Size Exceeded\n"); + break; + case USB_LC_STAT_BUFFER_UNDERRUN: + usbi_dbg("Buffer Underrun\n"); + break; + case USB_LC_STAT_TIMEOUT: + usbi_dbg("Command Timed Out\n"); + break; + case USB_LC_STAT_NOT_ACCESSED: + usbi_dbg("Not Accessed by h/w\n"); + break; + case USB_LC_STAT_UNSPECIFIED_ERR: + usbi_dbg("Unspecified Error\n"); + break; + case USB_LC_STAT_NO_BANDWIDTH: + usbi_dbg("No Bandwidth\n"); + break; + case USB_LC_STAT_HW_ERR: + usbi_dbg("Host Controller h/w Error\n"); + break; + case USB_LC_STAT_SUSPENDED: + usbi_dbg("Device was Suspended\n"); + break; + case USB_LC_STAT_DISCONNECTED: + usbi_dbg("Device was Disconnected\n"); + break; + case USB_LC_STAT_INTR_BUF_FULL: + usbi_dbg("Interrupt buffer was full\n"); + break; + case USB_LC_STAT_INVALID_REQ: + usbi_dbg("Request was Invalid\n"); + break; + case USB_LC_STAT_INTERRUPTED: + usbi_dbg("Request was Interrupted\n"); + break; + case USB_LC_STAT_NO_RESOURCES: + usbi_dbg("No resources available for " + "request\n"); + break; + case USB_LC_STAT_INTR_POLLING_FAILED: + usbi_dbg("Failed to Restart Poll"); + break; + default: + usbi_dbg("Error Not Determined %d\n", + status); + break; + } + } else { + usbi_dbg("read stat error: %s",strerror(errno)); + status = -1; + } + + return (status); +} + +const struct usbi_os_backend sunos_backend = { + .name = "Solaris", + .caps = 0, + .init = sunos_init, + .exit = sunos_exit, + .get_device_list = sunos_get_device_list, + .get_device_descriptor = sunos_get_device_descriptor, + .get_active_config_descriptor = sunos_get_active_config_descriptor, + .get_config_descriptor = sunos_get_config_descriptor, + .hotplug_poll = NULL, + .open = sunos_open, + .close = sunos_close, + .get_configuration = sunos_get_configuration, + .set_configuration = sunos_set_configuration, + + .claim_interface = sunos_claim_interface, + .release_interface = sunos_release_interface, + .set_interface_altsetting = sunos_set_interface_altsetting, + .clear_halt = sunos_clear_halt, + .reset_device = sunos_reset_device, /* TODO */ + .alloc_streams = NULL, + .free_streams = NULL, + .kernel_driver_active = NULL, + .detach_kernel_driver = NULL, + .attach_kernel_driver = NULL, + .destroy_device = sunos_destroy_device, + .submit_transfer = sunos_submit_transfer, + .cancel_transfer = sunos_cancel_transfer, + .handle_events = NULL, + .clear_transfer_priv = sunos_clear_transfer_priv, + .handle_transfer_completion = sunos_handle_transfer_completion, + .clock_gettime = sunos_clock_gettime, + .device_priv_size = sizeof(sunos_dev_priv_t), + .device_handle_priv_size = sizeof(sunos_dev_handle_priv_t), + .transfer_priv_size = sizeof(sunos_xfer_priv_t), +}; diff --git a/Externals/libusb/libusb/os/sunos_usb.h b/Externals/libusb/libusb/os/sunos_usb.h new file mode 100644 index 0000000000..5741660319 --- /dev/null +++ b/Externals/libusb/libusb/os/sunos_usb.h @@ -0,0 +1,74 @@ +/* + * + * Copyright (c) 2016, Oracle and/or its affiliates. + * + * 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 + */ + +#ifndef LIBUSB_SUNOS_H +#define LIBUSB_SUNOS_H + +#include +#include +#include "libusbi.h" + +#define READ 0 +#define WRITE 1 + +typedef struct sunos_device_priv { + uint8_t cfgvalue; /* active config value */ + uint8_t *raw_cfgdescr; /* active config descriptor */ + struct libusb_device_descriptor dev_descr; /* usb device descriptor */ + char *ugenpath; /* name of the ugen(4) node */ + char *phypath; /* physical path */ +} sunos_dev_priv_t; + +typedef struct endpoint { + int datafd; /* data file */ + int statfd; /* state file */ +} sunos_ep_priv_t; + +typedef struct sunos_device_handle_priv { + uint8_t altsetting[USB_MAXINTERFACES]; /* a interface's alt */ + uint8_t config_index; + sunos_ep_priv_t eps[USB_MAXENDPOINTS]; + sunos_dev_priv_t *dpriv; /* device private */ +} sunos_dev_handle_priv_t; + +typedef struct sunos_transfer_priv { + struct aiocb aiocb; + struct libusb_transfer *transfer; +} sunos_xfer_priv_t; + +struct node_args { + struct libusb_context *ctx; + struct discovered_devs **discdevs; + const char *last_ugenpath; + di_devlink_handle_t dlink_hdl; +}; + +struct devlink_cbarg { + struct node_args *nargs; /* di node walk arguments */ + di_node_t myself; /* the di node */ + di_minor_t minor; +}; + +/* AIO callback args */ +struct aio_callback_args{ + struct libusb_transfer *transfer; + struct aiocb aiocb; +}; + +#endif /* LIBUSB_SUNOS_H */ diff --git a/Externals/libusb/libusb/os/threads_posix.c b/Externals/libusb/libusb/os/threads_posix.c index e8e87bbb4c..a4f270bbe5 100644 --- a/Externals/libusb/libusb/os/threads_posix.c +++ b/Externals/libusb/libusb/os/threads_posix.c @@ -21,6 +21,7 @@ #include +#include #if defined(__linux__) || defined(__OpenBSD__) # if defined(__OpenBSD__) # define _BSD_SOURCE @@ -34,30 +35,26 @@ #endif #include "threads_posix.h" +#include "libusbi.h" -int usbi_mutex_init_recursive(pthread_mutex_t *mutex, pthread_mutexattr_t *attr) +int usbi_cond_timedwait(pthread_cond_t *cond, + pthread_mutex_t *mutex, const struct timeval *tv) { - int err; - pthread_mutexattr_t stack_attr; - if (!attr) { - attr = &stack_attr; - err = pthread_mutexattr_init(&stack_attr); - if (err != 0) - return err; + struct timespec timeout; + int r; + + r = usbi_backend->clock_gettime(USBI_CLOCK_REALTIME, &timeout); + if (r < 0) + return r; + + timeout.tv_sec += tv->tv_sec; + timeout.tv_nsec += tv->tv_usec * 1000; + while (timeout.tv_nsec >= 1000000000L) { + timeout.tv_nsec -= 1000000000L; + timeout.tv_sec++; } - /* mutexattr_settype requires _GNU_SOURCE or _XOPEN_SOURCE >= 500 on Linux */ - err = pthread_mutexattr_settype(attr, PTHREAD_MUTEX_RECURSIVE); - if (err != 0) - goto finish; - - err = pthread_mutex_init(mutex, attr); - -finish: - if (attr == &stack_attr) - pthread_mutexattr_destroy(&stack_attr); - - return err; + return pthread_cond_timedwait(cond, mutex, &timeout); } int usbi_get_tid(void) diff --git a/Externals/libusb/libusb/os/threads_posix.h b/Externals/libusb/libusb/os/threads_posix.h index d7a5d215fe..7ec70b1b52 100644 --- a/Externals/libusb/libusb/os/threads_posix.h +++ b/Externals/libusb/libusb/os/threads_posix.h @@ -22,6 +22,9 @@ #define LIBUSB_THREADS_POSIX_H #include +#ifdef HAVE_SYS_TIME_H +#include +#endif #define usbi_mutex_static_t pthread_mutex_t #define USBI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER @@ -29,21 +32,26 @@ #define usbi_mutex_static_unlock pthread_mutex_unlock #define usbi_mutex_t pthread_mutex_t -#define usbi_mutex_init pthread_mutex_init +#define usbi_mutex_init(mutex) pthread_mutex_init((mutex), NULL) #define usbi_mutex_lock pthread_mutex_lock #define usbi_mutex_unlock pthread_mutex_unlock #define usbi_mutex_trylock pthread_mutex_trylock #define usbi_mutex_destroy pthread_mutex_destroy #define usbi_cond_t pthread_cond_t -#define usbi_cond_init pthread_cond_init +#define usbi_cond_init(cond) pthread_cond_init((cond), NULL) #define usbi_cond_wait pthread_cond_wait -#define usbi_cond_timedwait pthread_cond_timedwait #define usbi_cond_broadcast pthread_cond_broadcast #define usbi_cond_destroy pthread_cond_destroy -#define usbi_cond_signal pthread_cond_signal -extern int usbi_mutex_init_recursive(pthread_mutex_t *mutex, pthread_mutexattr_t *attr); +#define usbi_tls_key_t pthread_key_t +#define usbi_tls_key_create(key) pthread_key_create((key), NULL) +#define usbi_tls_key_get pthread_getspecific +#define usbi_tls_key_set pthread_setspecific +#define usbi_tls_key_delete pthread_key_delete + +int usbi_cond_timedwait(pthread_cond_t *cond, + pthread_mutex_t *mutex, const struct timeval *tv); int usbi_get_tid(void); diff --git a/Externals/libusb/libusb/os/threads_windows.c b/Externals/libusb/libusb/os/threads_windows.c index 700bad6144..7c2e52dba6 100644 --- a/Externals/libusb/libusb/os/threads_windows.c +++ b/Externals/libusb/libusb/os/threads_windows.c @@ -22,134 +22,161 @@ #include #include -#include #include "libusbi.h" -extern const uint64_t epoch_time; +struct usbi_cond_perthread { + struct list_head list; + DWORD tid; + HANDLE event; +}; -int usbi_mutex_init(usbi_mutex_t *mutex, - const usbi_mutexattr_t *attr) { - UNUSED(attr); - if(! mutex) return ((errno=EINVAL)); - *mutex = CreateMutex(NULL, FALSE, NULL); - if(!*mutex) return ((errno=ENOMEM)); +int usbi_mutex_static_lock(usbi_mutex_static_t *mutex) +{ + if (!mutex) + return EINVAL; + while (InterlockedExchange(mutex, 1) == 1) + SleepEx(0, TRUE); return 0; } -int usbi_mutex_destroy(usbi_mutex_t *mutex) { + +int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex) +{ + if (!mutex) + return EINVAL; + InterlockedExchange(mutex, 0); + return 0; +} + +int usbi_mutex_init(usbi_mutex_t *mutex) +{ + if (!mutex) + return EINVAL; + *mutex = CreateMutex(NULL, FALSE, NULL); + if (!*mutex) + return ENOMEM; + return 0; +} + +int usbi_mutex_lock(usbi_mutex_t *mutex) +{ + DWORD result; + + if (!mutex) + return EINVAL; + result = WaitForSingleObject(*mutex, INFINITE); + if (result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) + return 0; // acquired (ToDo: check that abandoned is ok) + else + return EINVAL; // don't know how this would happen + // so don't know proper errno +} + +int usbi_mutex_unlock(usbi_mutex_t *mutex) +{ + if (!mutex) + return EINVAL; + if (ReleaseMutex(*mutex)) + return 0; + else + return EPERM; +} + +int usbi_mutex_trylock(usbi_mutex_t *mutex) +{ + DWORD result; + + if (!mutex) + return EINVAL; + result = WaitForSingleObject(*mutex, 0); + if (result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) + return 0; // acquired (ToDo: check that abandoned is ok) + else if (result == WAIT_TIMEOUT) + return EBUSY; + else + return EINVAL; // don't know how this would happen + // so don't know proper error +} + +int usbi_mutex_destroy(usbi_mutex_t *mutex) +{ // It is not clear if CloseHandle failure is due to failure to unlock. // If so, this should be errno=EBUSY. - if(!mutex || !CloseHandle(*mutex)) return ((errno=EINVAL)); + if (!mutex || !CloseHandle(*mutex)) + return EINVAL; *mutex = NULL; return 0; } -int usbi_mutex_trylock(usbi_mutex_t *mutex) { - DWORD result; - if(!mutex) return ((errno=EINVAL)); - result = WaitForSingleObject(*mutex, 0); - if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) - return 0; // acquired (ToDo: check that abandoned is ok) - if(result == WAIT_TIMEOUT) - return ((errno=EBUSY)); - return ((errno=EINVAL)); // don't know how this would happen - // so don't know proper errno -} -int usbi_mutex_lock(usbi_mutex_t *mutex) { - DWORD result; - if(!mutex) return ((errno=EINVAL)); - result = WaitForSingleObject(*mutex, INFINITE); - if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) - return 0; // acquired (ToDo: check that abandoned is ok) - return ((errno=EINVAL)); // don't know how this would happen - // so don't know proper errno -} -int usbi_mutex_unlock(usbi_mutex_t *mutex) { - if(!mutex) return ((errno=EINVAL)); - if(!ReleaseMutex(*mutex)) return ((errno=EPERM )); - return 0; -} -int usbi_mutex_static_lock(usbi_mutex_static_t *mutex) { - if(!mutex) return ((errno=EINVAL)); - while (InterlockedExchange((LONG *)mutex, 1) == 1) { - SleepEx(0, TRUE); - } - return 0; -} -int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex) { - if(!mutex) return ((errno=EINVAL)); - *mutex = 0; - return 0; -} - -int usbi_cond_init(usbi_cond_t *cond, - const usbi_condattr_t *attr) { - UNUSED(attr); - if(!cond) return ((errno=EINVAL)); - list_init(&cond->waiters ); +int usbi_cond_init(usbi_cond_t *cond) +{ + if (!cond) + return EINVAL; + list_init(&cond->waiters); list_init(&cond->not_waiting); return 0; } -int usbi_cond_destroy(usbi_cond_t *cond) { + +int usbi_cond_destroy(usbi_cond_t *cond) +{ // This assumes no one is using this anymore. The check MAY NOT BE safe. - struct usbi_cond_perthread *pos, *next_pos = NULL; - if(!cond) return ((errno=EINVAL)); - if(!list_empty(&cond->waiters)) return ((errno=EBUSY )); // (!see above!) + struct usbi_cond_perthread *pos, *next_pos; + + if(!cond) + return EINVAL; + if (!list_empty(&cond->waiters)) + return EBUSY; // (!see above!) list_for_each_entry_safe(pos, next_pos, &cond->not_waiting, list, struct usbi_cond_perthread) { CloseHandle(pos->event); list_del(&pos->list); free(pos); } - return 0; } -int usbi_cond_broadcast(usbi_cond_t *cond) { +int usbi_cond_broadcast(usbi_cond_t *cond) +{ // Assumes mutex is locked; this is not in keeping with POSIX spec, but // libusb does this anyway, so we simplify by not adding more sync // primitives to the CV definition! int fail = 0; struct usbi_cond_perthread *pos; - if(!cond) return ((errno=EINVAL)); + + if (!cond) + return EINVAL; list_for_each_entry(pos, &cond->waiters, list, struct usbi_cond_perthread) { - if(!SetEvent(pos->event)) + if (!SetEvent(pos->event)) fail = 1; } // The wait function will remove its respective item from the list. - return fail ? ((errno=EINVAL)) : 0; -} -int usbi_cond_signal(usbi_cond_t *cond) { - // Assumes mutex is locked; this is not in keeping with POSIX spec, but - // libusb does this anyway, so we simplify by not adding more sync - // primitives to the CV definition! - struct usbi_cond_perthread *pos; - if(!cond) return ((errno=EINVAL)); - if(list_empty(&cond->waiters)) return 0; // no one to wakeup. - pos = list_entry(&cond->waiters.next, struct usbi_cond_perthread, list); - // The wait function will remove its respective item from the list. - return SetEvent(pos->event) ? 0 : ((errno=EINVAL)); + return fail ? EINVAL : 0; } + __inline static int usbi_cond_intwait(usbi_cond_t *cond, - usbi_mutex_t *mutex, - DWORD timeout_ms) { + usbi_mutex_t *mutex, DWORD timeout_ms) +{ struct usbi_cond_perthread *pos; - int found = 0, r; - DWORD r2,tid = GetCurrentThreadId(); - if(!cond || !mutex) return ((errno=EINVAL)); + int r, found = 0; + DWORD r2, tid = GetCurrentThreadId(); + + if (!cond || !mutex) + return EINVAL; list_for_each_entry(pos, &cond->not_waiting, list, struct usbi_cond_perthread) { if(tid == pos->tid) { found = 1; break; } } - if(!found) { - pos = (struct usbi_cond_perthread*) calloc(1, sizeof(struct usbi_cond_perthread)); - if(!pos) return ((errno=ENOMEM)); // This errno is not POSIX-allowed. + + if (!found) { + pos = calloc(1, sizeof(struct usbi_cond_perthread)); + if (!pos) + return ENOMEM; // This errno is not POSIX-allowed. pos->tid = tid; pos->event = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset. - if(!pos->event) { + if (!pos->event) { free(pos); - return ((errno=ENOMEM)); + return ENOMEM; } list_add(&pos->list, &cond->not_waiting); } @@ -158,57 +185,75 @@ __inline static int usbi_cond_intwait(usbi_cond_t *cond, list_add(&pos->list, &cond->waiters); r = usbi_mutex_unlock(mutex); - if(r) return r; + if (r) + return r; + r2 = WaitForSingleObject(pos->event, timeout_ms); - r = usbi_mutex_lock(mutex); - if(r) return r; + r = usbi_mutex_lock(mutex); + if (r) + return r; list_del(&pos->list); list_add(&pos->list, &cond->not_waiting); - if(r2 == WAIT_TIMEOUT) return ((errno=ETIMEDOUT)); - - return 0; + if (r2 == WAIT_OBJECT_0) + return 0; + else if (r2 == WAIT_TIMEOUT) + return ETIMEDOUT; + else + return EINVAL; } // N.B.: usbi_cond_*wait() can also return ENOMEM, even though pthread_cond_*wait cannot! -int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex) { +int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex) +{ return usbi_cond_intwait(cond, mutex, INFINITE); } + int usbi_cond_timedwait(usbi_cond_t *cond, - usbi_mutex_t *mutex, - const struct timespec *abstime) { - FILETIME filetime; - ULARGE_INTEGER rtime; - struct timeval targ_time, cur_time, delta_time; - struct timespec cur_time_ns; + usbi_mutex_t *mutex, const struct timeval *tv) +{ DWORD millis; - // GetSystemTimeAsFileTime() is not available on CE - SYSTEMTIME st; - GetSystemTime(&st); - if (!SystemTimeToFileTime(&st, &filetime)) - return 0; - rtime.LowPart = filetime.dwLowDateTime; - rtime.HighPart = filetime.dwHighDateTime; - rtime.QuadPart -= epoch_time; - cur_time_ns.tv_sec = (long)(rtime.QuadPart / 10000000); - cur_time_ns.tv_nsec = (long)((rtime.QuadPart % 10000000)*100); - TIMESPEC_TO_TIMEVAL(&cur_time, &cur_time_ns); - - TIMESPEC_TO_TIMEVAL(&targ_time, abstime); - timersub(&targ_time, &cur_time, &delta_time); - if(delta_time.tv_sec < 0) // abstime already passed? - millis = 0; - else { - millis = delta_time.tv_usec/1000; - millis += delta_time.tv_sec *1000; - if (delta_time.tv_usec % 1000) // round up to next millisecond - millis++; - } - + millis = (DWORD)(tv->tv_sec * 1000) + (tv->tv_usec / 1000); + /* round up to next millisecond */ + if (tv->tv_usec % 1000) + millis++; return usbi_cond_intwait(cond, mutex, millis); } -int usbi_get_tid(void) { - return GetCurrentThreadId(); +int usbi_tls_key_create(usbi_tls_key_t *key) +{ + if (!key) + return EINVAL; + *key = TlsAlloc(); + if (*key == TLS_OUT_OF_INDEXES) + return ENOMEM; + else + return 0; +} + +void *usbi_tls_key_get(usbi_tls_key_t key) +{ + return TlsGetValue(key); +} + +int usbi_tls_key_set(usbi_tls_key_t key, void *value) +{ + if (TlsSetValue(key, value)) + return 0; + else + return EINVAL; +} + +int usbi_tls_key_delete(usbi_tls_key_t key) +{ + if (TlsFree(key)) + return 0; + else + return EINVAL; +} + +int usbi_get_tid(void) +{ + return (int)GetCurrentThreadId(); } diff --git a/Externals/libusb/libusb/os/threads_windows.h b/Externals/libusb/libusb/os/threads_windows.h index b28da25555..e97ee78757 100644 --- a/Externals/libusb/libusb/os/threads_windows.h +++ b/Externals/libusb/libusb/os/threads_windows.h @@ -21,38 +21,26 @@ #ifndef LIBUSB_THREADS_WINDOWS_H #define LIBUSB_THREADS_WINDOWS_H -#define usbi_mutex_static_t volatile LONG -#define USBI_MUTEX_INITIALIZER 0 +#define usbi_mutex_static_t volatile LONG +#define USBI_MUTEX_INITIALIZER 0 -#define usbi_mutex_t HANDLE +#define usbi_mutex_t HANDLE -struct usbi_cond_perthread { - struct list_head list; - DWORD tid; - HANDLE event; -}; -struct usbi_cond_t_ { +typedef struct usbi_cond { // Every time a thread touches the CV, it winds up in one of these lists. - // It stays there until the CV is destroyed, even if the thread - // terminates. + // It stays there until the CV is destroyed, even if the thread terminates. struct list_head waiters; struct list_head not_waiting; -}; -typedef struct usbi_cond_t_ usbi_cond_t; +} usbi_cond_t; // We *were* getting timespec from pthread.h: #if (!defined(HAVE_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED)) #define HAVE_STRUCT_TIMESPEC 1 -// (shuffle2) see https://github.com/libusb/libusb/pull/60 -#if defined(_MSC_VER) && (_MSC_VER >= 1900) -#include -#else #define _TIMESPEC_DEFINED 1 struct timespec { - long tv_sec; - long tv_nsec; + long tv_sec; + long tv_nsec; }; -#endif #endif /* HAVE_STRUCT_TIMESPEC | _TIMESPEC_DEFINED */ // We *were* getting ETIMEDOUT from pthread.h: @@ -60,32 +48,28 @@ struct timespec { # define ETIMEDOUT 10060 /* This is the value in winsock.h. */ #endif -#define usbi_mutexattr_t void -#define usbi_condattr_t void - -// all Windows mutexes are recursive -#define usbi_mutex_init_recursive(mutex, attr) usbi_mutex_init((mutex), (attr)) +#define usbi_tls_key_t DWORD int usbi_mutex_static_lock(usbi_mutex_static_t *mutex); int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex); - -int usbi_mutex_init(usbi_mutex_t *mutex, - const usbi_mutexattr_t *attr); +int usbi_mutex_init(usbi_mutex_t *mutex); int usbi_mutex_lock(usbi_mutex_t *mutex); int usbi_mutex_unlock(usbi_mutex_t *mutex); int usbi_mutex_trylock(usbi_mutex_t *mutex); int usbi_mutex_destroy(usbi_mutex_t *mutex); -int usbi_cond_init(usbi_cond_t *cond, - const usbi_condattr_t *attr); -int usbi_cond_destroy(usbi_cond_t *cond); +int usbi_cond_init(usbi_cond_t *cond); int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex); int usbi_cond_timedwait(usbi_cond_t *cond, - usbi_mutex_t *mutex, - const struct timespec *abstime); + usbi_mutex_t *mutex, const struct timeval *tv); int usbi_cond_broadcast(usbi_cond_t *cond); -int usbi_cond_signal(usbi_cond_t *cond); +int usbi_cond_destroy(usbi_cond_t *cond); + +int usbi_tls_key_create(usbi_tls_key_t *key); +void *usbi_tls_key_get(usbi_tls_key_t key); +int usbi_tls_key_set(usbi_tls_key_t key, void *value); +int usbi_tls_key_delete(usbi_tls_key_t key); int usbi_get_tid(void); diff --git a/Externals/libusb/libusb/os/wince_usb.c b/Externals/libusb/libusb/os/wince_usb.c index 71fc8ac313..89b5e657c5 100644 --- a/Externals/libusb/libusb/os/wince_usb.c +++ b/Externals/libusb/libusb/os/wince_usb.c @@ -31,29 +31,29 @@ #include "wince_usb.h" // 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 +const uint64_t epoch_time = UINT64_C(116444736000000000); // 1970.01.01 00:00:000 in MS Filetime int windows_version = WINDOWS_CE; +static uint64_t hires_frequency, hires_ticks_to_ps; +static HANDLE driver_handle = INVALID_HANDLE_VALUE; static int concurrent_usage = -1; -HANDLE driver_handle = INVALID_HANDLE_VALUE; /* * 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 const char *windows_error_str(DWORD retval) { static TCHAR wErr_string[ERR_BUFFER_SIZE]; static char err_string[ERR_BUFFER_SIZE]; + DWORD error_code, format_error; DWORD size; size_t i; - uint32_t error_code, format_error; - error_code = retval?retval:GetLastError(); + error_code = retval ? retval : GetLastError(); - safe_stprintf(wErr_string, ERR_BUFFER_SIZE, _T("[%d] "), error_code); + safe_stprintf(wErr_string, ERR_BUFFER_SIZE, _T("[%u] "), (unsigned int)error_code); size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &wErr_string[safe_tcslen(wErr_string)], @@ -62,80 +62,87 @@ static char* windows_error_str(uint32_t retval) format_error = GetLastError(); if (format_error) safe_stprintf(wErr_string, ERR_BUFFER_SIZE, - _T("Windows error code %u (FormatMessage error code %u)"), error_code, format_error); + _T("Windows error code %u (FormatMessage error code %u)"), + (unsigned int)error_code, (unsigned int)format_error); else - safe_stprintf(wErr_string, ERR_BUFFER_SIZE, _T("Unknown error code %u"), error_code); + safe_stprintf(wErr_string, ERR_BUFFER_SIZE, _T("Unknown error code %u"), (unsigned int)error_code); } else { // Remove CR/LF terminators - for (i=safe_tcslen(wErr_string)-1; ((wErr_string[i]==0x0A) || (wErr_string[i]==0x0D)); i--) { + for (i = safe_tcslen(wErr_string) - 1; ((wErr_string[i] == 0x0A) || (wErr_string[i] == 0x0D)); i--) wErr_string[i] = 0; - } } + if (WideCharToMultiByte(CP_ACP, 0, wErr_string, -1, err_string, ERR_BUFFER_SIZE, NULL, NULL) < 0) - { strcpy(err_string, "Unable to convert error string"); - } + return err_string; } #endif static struct wince_device_priv *_device_priv(struct libusb_device *dev) { - return (struct wince_device_priv *) dev->os_priv; + return (struct wince_device_priv *)dev->os_priv; } // ceusbkwrapper to libusb error code mapping -static int translate_driver_error(int error) +static int translate_driver_error(DWORD error) { switch (error) { - case ERROR_INVALID_PARAMETER: - return LIBUSB_ERROR_INVALID_PARAM; - case ERROR_CALL_NOT_IMPLEMENTED: - case ERROR_NOT_SUPPORTED: - return LIBUSB_ERROR_NOT_SUPPORTED; - case ERROR_NOT_ENOUGH_MEMORY: - return LIBUSB_ERROR_NO_MEM; - case ERROR_INVALID_HANDLE: - return LIBUSB_ERROR_NO_DEVICE; - case ERROR_BUSY: - return LIBUSB_ERROR_BUSY; + case ERROR_INVALID_PARAMETER: + return LIBUSB_ERROR_INVALID_PARAM; + case ERROR_CALL_NOT_IMPLEMENTED: + case ERROR_NOT_SUPPORTED: + return LIBUSB_ERROR_NOT_SUPPORTED; + case ERROR_NOT_ENOUGH_MEMORY: + return LIBUSB_ERROR_NO_MEM; + case ERROR_INVALID_HANDLE: + return LIBUSB_ERROR_NO_DEVICE; + case ERROR_BUSY: + return LIBUSB_ERROR_BUSY; - // Error codes that are either unexpected, or have - // no suitable LIBUSB_ERROR equivilant. - case ERROR_CANCELLED: - case ERROR_INTERNAL_ERROR: - default: - return LIBUSB_ERROR_OTHER; + // Error codes that are either unexpected, or have + // no suitable LIBUSB_ERROR equivalent. + case ERROR_CANCELLED: + case ERROR_INTERNAL_ERROR: + default: + return LIBUSB_ERROR_OTHER; } } -static int init_dllimports() +static int init_dllimports(void) { - DLL_LOAD(ceusbkwrapper.dll, UkwOpenDriver, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwGetDeviceList, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwReleaseDeviceList, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwGetDeviceAddress, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwGetDeviceDescriptor, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwGetConfigDescriptor, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwCloseDriver, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwCancelTransfer, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwIssueControlTransfer, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwClaimInterface, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwReleaseInterface, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwSetInterfaceAlternateSetting, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwClearHaltHost, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwClearHaltDevice, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwGetConfig, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwSetConfig, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwResetDevice, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwKernelDriverActive, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwAttachKernelDriver, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwDetachKernelDriver, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwIssueBulkTransfer, TRUE); - DLL_LOAD(ceusbkwrapper.dll, UkwIsPipeHalted, TRUE); + DLL_GET_HANDLE(ceusbkwrapper); + DLL_LOAD_FUNC(ceusbkwrapper, UkwOpenDriver, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwGetDeviceList, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwReleaseDeviceList, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwGetDeviceAddress, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwGetDeviceDescriptor, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwGetConfigDescriptor, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwCloseDriver, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwCancelTransfer, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwIssueControlTransfer, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwClaimInterface, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwReleaseInterface, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwSetInterfaceAlternateSetting, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwClearHaltHost, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwClearHaltDevice, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwGetConfig, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwSetConfig, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwResetDevice, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwKernelDriverActive, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwAttachKernelDriver, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwDetachKernelDriver, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwIssueBulkTransfer, TRUE); + DLL_LOAD_FUNC(ceusbkwrapper, UkwIsPipeHalted, TRUE); + return LIBUSB_SUCCESS; } +static void exit_dllimports(void) +{ + DLL_FREE_HANDLE(ceusbkwrapper); +} + static int init_device( struct libusb_device *dev, UKW_DEVICE drv_dev, unsigned char bus_addr, unsigned char dev_addr) @@ -147,9 +154,9 @@ static int init_device( dev->device_address = dev_addr; priv->dev = drv_dev; - if (!UkwGetDeviceDescriptor(priv->dev, &(priv->desc))) { + if (!UkwGetDeviceDescriptor(priv->dev, &(priv->desc))) r = translate_driver_error(GetLastError()); - } + return r; } @@ -159,9 +166,9 @@ static int wince_init(struct libusb_context *ctx) int r = LIBUSB_ERROR_OTHER; HANDLE semaphore; LARGE_INTEGER li_frequency; - TCHAR sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID) + TCHAR sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0' - _stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)GetCurrentProcessId()&0xFFFFFFFF); + _stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF)); semaphore = CreateSemaphore(NULL, 1, 1, sem_name); if (semaphore == NULL) { usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0)); @@ -215,6 +222,9 @@ static int wince_init(struct libusb_context *ctx) init_exit: // Holds semaphore here. if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed? + exit_dllimports(); + exit_polling(); + if (driver_handle != INVALID_HANDLE_VALUE) { UkwCloseDriver(driver_handle); driver_handle = INVALID_HANDLE_VALUE; @@ -232,13 +242,12 @@ init_exit: // Holds semaphore here. static void wince_exit(void) { HANDLE semaphore; - TCHAR sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID) + TCHAR sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0' - _stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)GetCurrentProcessId()&0xFFFFFFFF); + _stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF)); semaphore = CreateSemaphore(NULL, 1, 1, sem_name); - if (semaphore == NULL) { + if (semaphore == NULL) return; - } // A successful wait brings our semaphore count to 0 (unsignaled) // => any concurent wait stalls until the semaphore release @@ -249,6 +258,7 @@ static void wince_exit(void) // Only works if exits and inits are balanced exactly if (--concurrent_usage < 0) { // Last exit + exit_dllimports(); exit_polling(); if (driver_handle != INVALID_HANDLE_VALUE) { @@ -266,7 +276,7 @@ static int wince_get_device_list( struct discovered_devs **discdevs) { UKW_DEVICE devices[MAX_DEVICE_COUNT]; - struct discovered_devs * new_devices = *discdevs; + struct discovered_devs *new_devices = *discdevs; DWORD count = 0, i; struct libusb_device *dev = NULL; unsigned char bus_addr, dev_addr; @@ -281,44 +291,51 @@ static int wince_get_device_list( usbi_err(ctx, "could not get devices: %s", windows_error_str(0)); return libusbErr; } - for(i = 0; i < count; ++i) { + + for (i = 0; i < count; ++i) { release_list_offset = i; success = UkwGetDeviceAddress(devices[i], &bus_addr, &dev_addr, &session_id); if (!success) { r = translate_driver_error(GetLastError()); - usbi_err(ctx, "could not get device address for %d: %s", i, windows_error_str(0)); + usbi_err(ctx, "could not get device address for %u: %s", (unsigned int)i, windows_error_str(0)); goto err_out; } + dev = usbi_get_device_by_session_id(ctx, session_id); if (dev) { - usbi_dbg("using existing device for %d/%d (session %ld)", + usbi_dbg("using existing device for %u/%u (session %lu)", bus_addr, dev_addr, session_id); // Release just this element in the device list (as we already hold a // reference to it). UkwReleaseDeviceList(driver_handle, &devices[i], 1); release_list_offset++; } else { - usbi_dbg("allocating new device for %d/%d (session %ld)", + usbi_dbg("allocating new device for %u/%u (session %lu)", bus_addr, dev_addr, session_id); dev = usbi_alloc_device(ctx, session_id); if (!dev) { r = LIBUSB_ERROR_NO_MEM; goto err_out; } + r = init_device(dev, devices[i], bus_addr, dev_addr); if (r < 0) goto err_out; + r = usbi_sanitize_device(dev); if (r < 0) goto err_out; } + new_devices = discovered_devs_append(new_devices, dev); if (!discdevs) { r = LIBUSB_ERROR_NO_MEM; goto err_out; } + safe_unref_device(dev); } + *discdevs = new_devices; return r; err_out: @@ -360,10 +377,11 @@ static int wince_get_active_config_descriptor( { struct wince_device_priv *priv = _device_priv(device); DWORD actualSize = len; + *host_endian = 0; - if (!UkwGetConfigDescriptor(priv->dev, UKW_ACTIVE_CONFIGURATION, buffer, len, &actualSize)) { + if (!UkwGetConfigDescriptor(priv->dev, UKW_ACTIVE_CONFIGURATION, buffer, len, &actualSize)) return translate_driver_error(GetLastError()); - } + return actualSize; } @@ -374,10 +392,11 @@ static int wince_get_config_descriptor( { struct wince_device_priv *priv = _device_priv(device); DWORD actualSize = len; + *host_endian = 0; - if (!UkwGetConfigDescriptor(priv->dev, config_index, buffer, len, &actualSize)) { + if (!UkwGetConfigDescriptor(priv->dev, config_index, buffer, len, &actualSize)) return translate_driver_error(GetLastError()); - } + return actualSize; } @@ -387,9 +406,10 @@ static int wince_get_configuration( { struct wince_device_priv *priv = _device_priv(handle->dev); UCHAR cv = 0; - if (!UkwGetConfig(priv->dev, &cv)) { + + if (!UkwGetConfig(priv->dev, &cv)) return translate_driver_error(GetLastError()); - } + (*config) = cv; return LIBUSB_SUCCESS; } @@ -403,9 +423,9 @@ static int wince_set_configuration( // This should correspond to the "unconfigured state" required by // libusb when the specified configuration is -1. UCHAR cv = (config < 0) ? 0 : config; - if (!UkwSetConfig(priv->dev, cv)) { + if (!UkwSetConfig(priv->dev, cv)) return translate_driver_error(GetLastError()); - } + return LIBUSB_SUCCESS; } @@ -414,9 +434,10 @@ static int wince_claim_interface( int interface_number) { struct wince_device_priv *priv = _device_priv(handle->dev); - if (!UkwClaimInterface(priv->dev, interface_number)) { + + if (!UkwClaimInterface(priv->dev, interface_number)) return translate_driver_error(GetLastError()); - } + return LIBUSB_SUCCESS; } @@ -425,12 +446,13 @@ static int wince_release_interface( int interface_number) { struct wince_device_priv *priv = _device_priv(handle->dev); - if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, 0)) { + + if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, 0)) return translate_driver_error(GetLastError()); - } - if (!UkwReleaseInterface(priv->dev, interface_number)) { + + if (!UkwReleaseInterface(priv->dev, interface_number)) return translate_driver_error(GetLastError()); - } + return LIBUSB_SUCCESS; } @@ -439,9 +461,10 @@ static int wince_set_interface_altsetting( int interface_number, int altsetting) { struct wince_device_priv *priv = _device_priv(handle->dev); - if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, altsetting)) { + + if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, altsetting)) return translate_driver_error(GetLastError()); - } + return LIBUSB_SUCCESS; } @@ -450,12 +473,13 @@ static int wince_clear_halt( unsigned char endpoint) { struct wince_device_priv *priv = _device_priv(handle->dev); - if (!UkwClearHaltHost(priv->dev, endpoint)) { + + if (!UkwClearHaltHost(priv->dev, endpoint)) return translate_driver_error(GetLastError()); - } - if (!UkwClearHaltDevice(priv->dev, endpoint)) { + + if (!UkwClearHaltDevice(priv->dev, endpoint)) return translate_driver_error(GetLastError()); - } + return LIBUSB_SUCCESS; } @@ -463,9 +487,10 @@ static int wince_reset_device( struct libusb_device_handle *handle) { struct wince_device_priv *priv = _device_priv(handle->dev); - if (!UkwResetDevice(priv->dev)) { + + if (!UkwResetDevice(priv->dev)) return translate_driver_error(GetLastError()); - } + return LIBUSB_SUCCESS; } @@ -475,9 +500,10 @@ static int wince_kernel_driver_active( { struct wince_device_priv *priv = _device_priv(handle->dev); BOOL result = FALSE; - if (!UkwKernelDriverActive(priv->dev, interface_number, &result)) { + + if (!UkwKernelDriverActive(priv->dev, interface_number, &result)) return translate_driver_error(GetLastError()); - } + return result ? 1 : 0; } @@ -486,9 +512,10 @@ static int wince_detach_kernel_driver( int interface_number) { struct wince_device_priv *priv = _device_priv(handle->dev); - if (!UkwDetachKernelDriver(priv->dev, interface_number)) { + + if (!UkwDetachKernelDriver(priv->dev, interface_number)) return translate_driver_error(GetLastError()); - } + return LIBUSB_SUCCESS; } @@ -497,22 +524,25 @@ static int wince_attach_kernel_driver( int interface_number) { struct wince_device_priv *priv = _device_priv(handle->dev); - if (!UkwAttachKernelDriver(priv->dev, interface_number)) { + + if (!UkwAttachKernelDriver(priv->dev, interface_number)) return translate_driver_error(GetLastError()); - } + return LIBUSB_SUCCESS; } static void wince_destroy_device(struct libusb_device *dev) { struct wince_device_priv *priv = _device_priv(dev); + UkwReleaseDeviceList(driver_handle, &priv->dev, 1); } static void wince_clear_transfer_priv(struct usbi_transfer *itransfer) { - struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer); + struct wince_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); struct winfd wfd = fd_to_winfd(transfer_priv->pollable_fd.fd); + // No need to cancel transfer as it is either complete or abandoned wfd.itransfer = NULL; CloseHandle(wfd.handle); @@ -523,11 +553,11 @@ static int wince_cancel_transfer(struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev); - struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer); + struct wince_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - if (!UkwCancelTransfer(priv->dev, transfer_priv->pollable_fd.overlapped, UKW_TF_NO_WAIT)) { + if (!UkwCancelTransfer(priv->dev, transfer_priv->pollable_fd.overlapped, UKW_TF_NO_WAIT)) return translate_driver_error(GetLastError()); - } + return LIBUSB_SUCCESS; } @@ -535,7 +565,7 @@ static int wince_submit_control_or_bulk_transfer(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 wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer); + struct wince_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev); BOOL direction_in, ret; struct winfd wfd; @@ -577,10 +607,11 @@ static int wince_submit_control_or_bulk_transfer(struct usbi_transfer *itransfer ret = UkwIssueBulkTransfer(priv->dev, flags, transfer->endpoint, transfer->buffer, transfer->length, &transfer->actual_length, wfd.overlapped); } + if (!ret) { int libusbErr = translate_driver_error(GetLastError()); - usbi_err(ctx, "UkwIssue%sTransfer failed: error %d", - control_transfer ? "Control" : "Bulk", GetLastError()); + usbi_err(ctx, "UkwIssue%sTransfer failed: error %u", + control_transfer ? "Control" : "Bulk", (unsigned int)GetLastError()); wince_clear_transfer_priv(itransfer); return libusbErr; } @@ -622,7 +653,7 @@ static void wince_transfer_callback( struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev); int status; - usbi_dbg("handling I/O completion with errcode %d", io_result); + usbi_dbg("handling I/O completion with errcode %u", io_result); if (io_result == ERROR_NOT_SUPPORTED && transfer->type != LIBUSB_TRANSFER_TYPE_CONTROL) { @@ -689,25 +720,20 @@ static void wince_transfer_callback( status = LIBUSB_TRANSFER_TIMED_OUT; break; case ERROR_OPERATION_ABORTED: - 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; - } + usbi_dbg("detected operation aborted"); + status = LIBUSB_TRANSFER_CANCELLED; break; default: usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error: %s", windows_error_str(io_result)); status = LIBUSB_TRANSFER_ERROR; break; } + wince_clear_transfer_priv(itransfer); - if (status == LIBUSB_TRANSFER_CANCELLED) { + if (status == LIBUSB_TRANSFER_CANCELLED) usbi_handle_transfer_cancellation(itransfer); - } else { + else usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status); - } } static void wince_handle_callback( @@ -739,15 +765,15 @@ static int wince_handle_events( BOOL found = FALSE; struct usbi_transfer *transfer; DWORD io_size, io_result; + int r = LIBUSB_SUCCESS; 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) { + if (!fds[i].revents) continue; - } num_ready--; @@ -772,18 +798,18 @@ static int wince_handle_events( // newly allocated wfd that took the place of the one from the transfer. wince_handle_callback(transfer, io_result, io_size); } else if (found) { - usbi_err(ctx, "matching transfer for fd %x has not completed", fds[i]); - usbi_mutex_unlock(&ctx->open_devs_lock); - return LIBUSB_ERROR_OTHER; + usbi_err(ctx, "matching transfer for fd %d has not completed", fds[i]); + r = LIBUSB_ERROR_OTHER; + break; } else { - usbi_err(ctx, "could not find a matching transfer for fd %x", fds[i]); - usbi_mutex_unlock(&ctx->open_devs_lock); - return LIBUSB_ERROR_NOT_FOUND; + usbi_err(ctx, "could not find a matching transfer for fd %d", fds[i]); + r = LIBUSB_ERROR_NOT_FOUND; + break; } } - usbi_mutex_unlock(&ctx->open_devs_lock); - return LIBUSB_SUCCESS; + + return r; } /* @@ -795,6 +821,7 @@ static int wince_clock_gettime(int clk_id, struct timespec *tp) ULARGE_INTEGER rtime; FILETIME filetime; SYSTEMTIME st; + switch(clk_id) { case USBI_CLOCK_MONOTONIC: if (hires_frequency != 0 && QueryPerformanceCounter(&hires_counter)) { @@ -849,6 +876,9 @@ const struct usbi_os_backend wince_backend = { NULL, /* alloc_streams */ NULL, /* free_streams */ + NULL, /* dev_mem_alloc() */ + NULL, /* dev_mem_free() */ + wince_kernel_driver_active, wince_detach_kernel_driver, wince_attach_kernel_driver, @@ -864,6 +894,6 @@ const struct usbi_os_backend wince_backend = { wince_clock_gettime, sizeof(struct wince_device_priv), - sizeof(struct wince_device_handle_priv), + 0, sizeof(struct wince_transfer_priv), }; diff --git a/Externals/libusb/libusb/os/wince_usb.h b/Externals/libusb/libusb/os/wince_usb.h index bc61b5c103..edcb9fcc40 100644 --- a/Externals/libusb/libusb/os/wince_usb.h +++ b/Externals/libusb/libusb/os/wince_usb.h @@ -87,28 +87,29 @@ typedef struct { * to specify the currently active configuration for the device. */ #define UKW_ACTIVE_CONFIGURATION -1 -DLL_DECLARE(WINAPI, HANDLE, UkwOpenDriver, ()); -DLL_DECLARE(WINAPI, BOOL, UkwGetDeviceList, (HANDLE, LPUKW_DEVICE, DWORD, LPDWORD)); -DLL_DECLARE(WINAPI, void, UkwReleaseDeviceList, (HANDLE, LPUKW_DEVICE, DWORD)); -DLL_DECLARE(WINAPI, BOOL, UkwGetDeviceAddress, (UKW_DEVICE, unsigned char*, unsigned char*, unsigned long*)); -DLL_DECLARE(WINAPI, BOOL, UkwGetDeviceDescriptor, (UKW_DEVICE, LPUKW_DEVICE_DESCRIPTOR)); -DLL_DECLARE(WINAPI, BOOL, UkwGetConfigDescriptor, (UKW_DEVICE, DWORD, LPVOID, DWORD, LPDWORD)); -DLL_DECLARE(WINAPI, void, UkwCloseDriver, (HANDLE)); -DLL_DECLARE(WINAPI, BOOL, UkwCancelTransfer, (UKW_DEVICE, LPOVERLAPPED, DWORD)); -DLL_DECLARE(WINAPI, BOOL, UkwIssueControlTransfer, (UKW_DEVICE, DWORD, LPUKW_CONTROL_HEADER, LPVOID, DWORD, LPDWORD, LPOVERLAPPED)); -DLL_DECLARE(WINAPI, BOOL, UkwClaimInterface, (UKW_DEVICE, DWORD)); -DLL_DECLARE(WINAPI, BOOL, UkwReleaseInterface, (UKW_DEVICE, DWORD)); -DLL_DECLARE(WINAPI, BOOL, UkwSetInterfaceAlternateSetting, (UKW_DEVICE, DWORD, DWORD)); -DLL_DECLARE(WINAPI, BOOL, UkwClearHaltHost, (UKW_DEVICE, UCHAR)); -DLL_DECLARE(WINAPI, BOOL, UkwClearHaltDevice, (UKW_DEVICE, UCHAR)); -DLL_DECLARE(WINAPI, BOOL, UkwGetConfig, (UKW_DEVICE, PUCHAR)); -DLL_DECLARE(WINAPI, BOOL, UkwSetConfig, (UKW_DEVICE, UCHAR)); -DLL_DECLARE(WINAPI, BOOL, UkwResetDevice, (UKW_DEVICE)); -DLL_DECLARE(WINAPI, BOOL, UkwKernelDriverActive, (UKW_DEVICE, DWORD, PBOOL)); -DLL_DECLARE(WINAPI, BOOL, UkwAttachKernelDriver, (UKW_DEVICE, DWORD)); -DLL_DECLARE(WINAPI, BOOL, UkwDetachKernelDriver, (UKW_DEVICE, DWORD)); -DLL_DECLARE(WINAPI, BOOL, UkwIssueBulkTransfer, (UKW_DEVICE, DWORD, UCHAR, LPVOID, DWORD, LPDWORD, LPOVERLAPPED)); -DLL_DECLARE(WINAPI, BOOL, UkwIsPipeHalted, (UKW_DEVICE, UCHAR, LPBOOL)); +DLL_DECLARE_HANDLE(ceusbkwrapper); +DLL_DECLARE_FUNC(WINAPI, HANDLE, UkwOpenDriver, ()); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwGetDeviceList, (HANDLE, LPUKW_DEVICE, DWORD, LPDWORD)); +DLL_DECLARE_FUNC(WINAPI, void, UkwReleaseDeviceList, (HANDLE, LPUKW_DEVICE, DWORD)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwGetDeviceAddress, (UKW_DEVICE, unsigned char*, unsigned char*, unsigned long*)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwGetDeviceDescriptor, (UKW_DEVICE, LPUKW_DEVICE_DESCRIPTOR)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwGetConfigDescriptor, (UKW_DEVICE, DWORD, LPVOID, DWORD, LPDWORD)); +DLL_DECLARE_FUNC(WINAPI, void, UkwCloseDriver, (HANDLE)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwCancelTransfer, (UKW_DEVICE, LPOVERLAPPED, DWORD)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwIssueControlTransfer, (UKW_DEVICE, DWORD, LPUKW_CONTROL_HEADER, LPVOID, DWORD, LPDWORD, LPOVERLAPPED)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwClaimInterface, (UKW_DEVICE, DWORD)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwReleaseInterface, (UKW_DEVICE, DWORD)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwSetInterfaceAlternateSetting, (UKW_DEVICE, DWORD, DWORD)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwClearHaltHost, (UKW_DEVICE, UCHAR)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwClearHaltDevice, (UKW_DEVICE, UCHAR)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwGetConfig, (UKW_DEVICE, PUCHAR)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwSetConfig, (UKW_DEVICE, UCHAR)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwResetDevice, (UKW_DEVICE)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwKernelDriverActive, (UKW_DEVICE, DWORD, PBOOL)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwAttachKernelDriver, (UKW_DEVICE, DWORD)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwDetachKernelDriver, (UKW_DEVICE, DWORD)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwIssueBulkTransfer, (UKW_DEVICE, DWORD, UCHAR, LPVOID, DWORD, LPDWORD, LPOVERLAPPED)); +DLL_DECLARE_FUNC(WINAPI, BOOL, UkwIsPipeHalted, (UKW_DEVICE, UCHAR, LPBOOL)); // Used to determine if an endpoint status really is halted on a failed transfer. #define STATUS_HALT_FLAG 0x1 @@ -118,12 +119,6 @@ struct wince_device_priv { UKW_DEVICE_DESCRIPTOR desc; }; -struct wince_device_handle_priv { - // This member isn't used, but only exists to avoid an empty structure - // for private data for the device handle. - int reserved; -}; - struct wince_transfer_priv { struct winfd pollable_fd; uint8_t interface_number; diff --git a/Externals/libusb/libusb/os/windows_common.h b/Externals/libusb/libusb/os/windows_common.h index 466f31d988..17a1923723 100644 --- a/Externals/libusb/libusb/os/windows_common.h +++ b/Externals/libusb/libusb/os/windows_common.h @@ -37,6 +37,14 @@ #define false FALSE #endif +#if defined(__CYGWIN__ ) +#define _stricmp strcasecmp +#define _snprintf snprintf +#define _strdup strdup +// _beginthreadex is MSVCRT => unavailable for cygwin. Fallback to using CreateThread +#define _beginthreadex(a, b, c, d, e, f) CreateThread(a, b, (LPTHREAD_START_ROUTINE)c, d, e, (LPDWORD)f) +#endif + #define safe_free(p) do {if (p != NULL) {free((void*)p); p = NULL;}} while(0) #define safe_closehandle(h) do {if (h != INVALID_HANDLE_VALUE) {CloseHandle(h); h = INVALID_HANDLE_VALUE;}} while(0) #define safe_min(a, b) MIN((size_t)(a), (size_t)(b)) @@ -58,51 +66,74 @@ #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) #endif -#define ERR_BUFFER_SIZE 256 -#define TIMER_REQUEST_RETRY_MS 100 -#define MAX_TIMER_SEMAPHORES 128 +#define ERR_BUFFER_SIZE 256 /* - * API macros - from libusb-win32 1.x + * API macros - leveraged from libusb-win32 1.x */ -#define DLL_DECLARE_PREFIXNAME(api, ret, prefixname, name, args) \ - typedef ret (api * __dll_##name##_t)args; \ - static __dll_##name##_t prefixname = NULL - #ifndef _WIN32_WCE -#define DLL_STRINGIFY(dll) #dll -#define DLL_GET_MODULE_HANDLE(dll) GetModuleHandleA(DLL_STRINGIFY(dll)) -#define DLL_LOAD_LIBRARY(dll) LoadLibraryA(DLL_STRINGIFY(dll)) +#define DLL_STRINGIFY(s) #s +#define DLL_LOAD_LIBRARY(name) LoadLibraryA(DLL_STRINGIFY(name)) #else -#define DLL_STRINGIFY(dll) L#dll -#define DLL_GET_MODULE_HANDLE(dll) GetModuleHandle(DLL_STRINGIFY(dll)) -#define DLL_LOAD_LIBRARY(dll) LoadLibrary(DLL_STRINGIFY(dll)) +#define DLL_STRINGIFY(s) L#s +#define DLL_LOAD_LIBRARY(name) LoadLibrary(DLL_STRINGIFY(name)) #endif -#define DLL_LOAD_PREFIXNAME(dll, prefixname, name, ret_on_failure) \ - do { \ - HMODULE h = DLL_GET_MODULE_HANDLE(dll); \ - if (!h) \ - h = DLL_LOAD_LIBRARY(dll); \ - if (!h) { \ - if (ret_on_failure) { return LIBUSB_ERROR_NOT_FOUND; } \ - else { break; } \ - } \ - prefixname = (__dll_##name##_t)GetProcAddress(h, \ - DLL_STRINGIFY(name)); \ - if (prefixname) break; \ - prefixname = (__dll_##name##_t)GetProcAddress(h, \ - DLL_STRINGIFY(name) DLL_STRINGIFY(A)); \ - if (prefixname) break; \ - prefixname = (__dll_##name##_t)GetProcAddress(h, \ - DLL_STRINGIFY(name) DLL_STRINGIFY(W)); \ - if (prefixname) break; \ - if(ret_on_failure) \ - return LIBUSB_ERROR_NOT_FOUND; \ +/* + * Macros for handling DLL themselves + */ +#define DLL_DECLARE_HANDLE(name) \ + static HMODULE __dll_##name##_handle = NULL + +#define DLL_GET_HANDLE(name) \ + do { \ + __dll_##name##_handle = DLL_LOAD_LIBRARY(name); \ + if (!__dll_##name##_handle) \ + return LIBUSB_ERROR_OTHER; \ + } while (0) + +#define DLL_FREE_HANDLE(name) \ + do { \ + if (__dll_##name##_handle) { \ + FreeLibrary(__dll_##name##_handle); \ + __dll_##name##_handle = NULL; \ + } \ } while(0) -#define DLL_DECLARE(api, ret, name, args) DLL_DECLARE_PREFIXNAME(api, ret, name, name, args) -#define DLL_LOAD(dll, name, ret_on_failure) DLL_LOAD_PREFIXNAME(dll, name, name, ret_on_failure) -#define DLL_DECLARE_PREFIXED(api, ret, prefix, name, args) DLL_DECLARE_PREFIXNAME(api, ret, prefix##name, name, args) -#define DLL_LOAD_PREFIXED(dll, prefix, name, ret_on_failure) DLL_LOAD_PREFIXNAME(dll, prefix##name, name, ret_on_failure) + +/* + * Macros for handling functions within a DLL + */ +#define DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefixname, name, args) \ + typedef ret (api * __dll_##name##_func_t)args; \ + static __dll_##name##_func_t prefixname = NULL + +#define DLL_DECLARE_FUNC(api, ret, name, args) \ + DLL_DECLARE_FUNC_PREFIXNAME(api, ret, name, name, args) +#define DLL_DECLARE_FUNC_PREFIXED(api, ret, prefix, name, args) \ + DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefix##name, name, args) + +#define DLL_LOAD_FUNC_PREFIXNAME(dll, prefixname, name, ret_on_failure) \ + do { \ + HMODULE h = __dll_##dll##_handle; \ + prefixname = (__dll_##name##_func_t)GetProcAddress(h, \ + DLL_STRINGIFY(name)); \ + if (prefixname) \ + break; \ + prefixname = (__dll_##name##_func_t)GetProcAddress(h, \ + DLL_STRINGIFY(name) DLL_STRINGIFY(A)); \ + if (prefixname) \ + break; \ + prefixname = (__dll_##name##_func_t)GetProcAddress(h, \ + DLL_STRINGIFY(name) DLL_STRINGIFY(W)); \ + if (prefixname) \ + break; \ + if (ret_on_failure) \ + return LIBUSB_ERROR_NOT_FOUND; \ + } while(0) + +#define DLL_LOAD_FUNC(dll, name, ret_on_failure) \ + DLL_LOAD_FUNC_PREFIXNAME(dll, name, name, ret_on_failure) +#define DLL_LOAD_FUNC_PREFIXED(dll, prefix, name, ret_on_failure) \ + DLL_LOAD_FUNC_PREFIXNAME(dll, prefix##name, name, ret_on_failure) diff --git a/Externals/libusb/libusb/os/windows_nt_common.c b/Externals/libusb/libusb/os/windows_nt_common.c new file mode 100644 index 0000000000..68eb4a7920 --- /dev/null +++ b/Externals/libusb/libusb/os/windows_nt_common.c @@ -0,0 +1,610 @@ +/* + * windows backend for libusb 1.0 + * Copyright © 2009-2012 Pete Batard + * 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 + +#include +#include +#include + +#include "libusbi.h" +#include "windows_common.h" +#include "windows_nt_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 +static uint64_t hires_ticks_to_ps; +static uint64_t hires_frequency; + +#define TIMER_REQUEST_RETRY_MS 100 +#define WM_TIMER_REQUEST (WM_USER + 1) +#define WM_TIMER_EXIT (WM_USER + 2) + +// used for monotonic clock_gettime() +struct timer_request { + struct timespec *tp; + HANDLE event; +}; + +// Timer thread +static HANDLE timer_thread = NULL; +static DWORD timer_thread_id = 0; + +/* User32 dependencies */ +DLL_DECLARE_HANDLE(User32); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, GetMessageA, (LPMSG, HWND, UINT, UINT)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, PeekMessageA, (LPMSG, HWND, UINT, UINT, UINT)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, PostThreadMessageA, (DWORD, UINT, WPARAM, LPARAM)); + +static unsigned __stdcall windows_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) +const char *windows_error_str(DWORD retval) +{ + static char err_string[ERR_BUFFER_SIZE]; + + DWORD error_code, format_error; + DWORD size; + ssize_t i; + + error_code = retval ? retval : GetLastError(); + + safe_sprintf(err_string, ERR_BUFFER_SIZE, "[%u] ", (unsigned int)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)", + (unsigned int)error_code, (unsigned int)format_error); + else + safe_sprintf(err_string, ERR_BUFFER_SIZE, "Unknown error code %u", (unsigned int)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) */ + +#define HTAB_SIZE 1021 + +typedef struct htab_entry { + unsigned long used; + char *str; +} htab_entry; + +static htab_entry *htab_table = NULL; +static usbi_mutex_t htab_write_mutex = NULL; +static 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 bool htab_create(struct libusb_context *ctx, unsigned long nel) +{ + if (htab_table != NULL) { + usbi_err(ctx, "hash table already allocated"); + return true; + } + + // Create a mutex + usbi_mutex_init(&htab_write_mutex); + + // Change nel to the first prime number not smaller as nel. + nel |= 1; + while (!isprime(nel)) + nel += 2; + + htab_size = nel; + usbi_dbg("using %lu entries hash table", nel); + htab_filled = 0; + + // allocate memory and zero out. + htab_table = calloc(htab_size + 1, sizeof(htab_entry)); + if (htab_table == NULL) { + usbi_err(ctx, "could not allocate space for hash table"); + return false; + } + + return true; +} + +/* After using the hash table it has to be destroyed. */ +static void htab_destroy(void) +{ + unsigned long 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 a 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(const char *str) +{ + unsigned long hval, hval2; + unsigned long idx; + unsigned long r = 5381; + int c; + const 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)) + return idx; // existing hash + + 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 = _strdup(str); + if (htab_table[idx].str == NULL) { + usbi_err(NULL, "could not duplicate string for hash table"); + usbi_mutex_unlock(&htab_write_mutex); + return 0; + } + ++htab_filled; + usbi_mutex_unlock(&htab_write_mutex); + + return idx; +} + +static int windows_init_dlls(void) +{ + DLL_GET_HANDLE(User32); + DLL_LOAD_FUNC_PREFIXED(User32, p, GetMessageA, TRUE); + DLL_LOAD_FUNC_PREFIXED(User32, p, PeekMessageA, TRUE); + DLL_LOAD_FUNC_PREFIXED(User32, p, PostThreadMessageA, TRUE); + + return LIBUSB_SUCCESS; +} + +static void windows_exit_dlls(void) +{ + DLL_FREE_HANDLE(User32); +} + +static bool windows_init_clock(struct libusb_context *ctx) +{ + DWORD_PTR affinity, dummy; + HANDLE event = NULL; + LARGE_INTEGER li_frequency; + int i; + + if (QueryPerformanceFrequency(&li_frequency)) { + // Load DLL imports + if (windows_init_dlls() != LIBUSB_SUCCESS) { + usbi_err(ctx, "could not resolve DLL functions"); + return false; + } + + // 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_frequency = li_frequency.QuadPart; + hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency; + usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency); + + // 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 available core always to prevent timing discrepancies. + if (!GetProcessAffinityMask(GetCurrentProcess(), &affinity, &dummy) || (affinity == 0)) { + usbi_err(ctx, "could not get process affinity: %s", windows_error_str(0)); + return false; + } + + // The process affinity mask is a bitmask where each set bit represents a core on + // which this process is allowed to run, so we find the first set bit + for (i = 0; !(affinity & (DWORD_PTR)(1 << i)); i++); + affinity = (DWORD_PTR)(1 << i); + + usbi_dbg("timer thread will run on core #%d", i); + + event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (event == NULL) { + usbi_err(ctx, "could not create event: %s", windows_error_str(0)); + return false; + } + + timer_thread = (HANDLE)_beginthreadex(NULL, 0, windows_clock_gettime_threaded, (void *)event, + 0, (unsigned int *)&timer_thread_id); + if (timer_thread == NULL) { + usbi_err(ctx, "unable to create timer thread - aborting"); + CloseHandle(event); + return false; + } + + if (!SetThreadAffinityMask(timer_thread, affinity)) + usbi_warn(ctx, "unable to set timer thread affinity, timer discrepancies may arise"); + + // Wait for timer thread to init before continuing. + if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) { + usbi_err(ctx, "failed to wait for timer thread to become ready - aborting"); + CloseHandle(event); + return false; + } + + CloseHandle(event); + } else { + usbi_dbg("no hires timer available on this platform"); + hires_frequency = 0; + hires_ticks_to_ps = UINT64_C(0); + } + + return true; +} + +void windows_destroy_clock(void) +{ + if (timer_thread) { + // actually the signal to quit the thread. + if (!pPostThreadMessageA(timer_thread_id, WM_TIMER_EXIT, 0, 0) + || (WaitForSingleObject(timer_thread, INFINITE) != WAIT_OBJECT_0)) { + usbi_dbg("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; + timer_thread_id = 0; + } +} + +/* +* Monotonic and real time functions +*/ +static unsigned __stdcall windows_clock_gettime_threaded(void *param) +{ + struct timer_request *request; + LARGE_INTEGER hires_counter; + MSG msg; + + // The following call will create this thread's message queue + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms644946.aspx + pPeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); + + // Signal windows_init_clock() that we're ready to service requests + if (!SetEvent((HANDLE)param)) + usbi_dbg("SetEvent failed for timer init event: %s", windows_error_str(0)); + param = NULL; + + // Main loop - wait for requests + while (1) { + if (pGetMessageA(&msg, NULL, WM_TIMER_REQUEST, WM_TIMER_EXIT) == -1) { + usbi_err(NULL, "GetMessage failed for timer thread: %s", windows_error_str(0)); + return 1; + } + + switch (msg.message) { + case WM_TIMER_REQUEST: + // Requests to this thread are for hires always + // Microsoft says that this function always succeeds on XP and later + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms644904.aspx + request = (struct timer_request *)msg.lParam; + QueryPerformanceCounter(&hires_counter); + request->tp->tv_sec = (long)(hires_counter.QuadPart / hires_frequency); + request->tp->tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency) / 1000) * hires_ticks_to_ps); + if (!SetEvent(request->event)) + usbi_err(NULL, "SetEvent failed for timer request: %s", windows_error_str(0)); + break; + case WM_TIMER_EXIT: + usbi_dbg("timer thread quitting"); + return 0; + } + } +} + +int windows_clock_gettime(int clk_id, struct timespec *tp) +{ + struct timer_request request; + FILETIME filetime; + ULARGE_INTEGER rtime; + DWORD r; + + switch (clk_id) { + case USBI_CLOCK_MONOTONIC: + if (timer_thread) { + request.tp = tp; + request.event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (request.event == NULL) + return LIBUSB_ERROR_NO_MEM; + + if (!pPostThreadMessageA(timer_thread_id, WM_TIMER_REQUEST, 0, (LPARAM)&request)) { + usbi_err(NULL, "PostThreadMessage failed for timer thread: %s", windows_error_str(0)); + CloseHandle(request.event); + return LIBUSB_ERROR_OTHER; + } + + do { + r = WaitForSingleObject(request.event, TIMER_REQUEST_RETRY_MS); + if (r == WAIT_TIMEOUT) + usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?"); + else if (r == WAIT_FAILED) + usbi_err(NULL, "WaitForSingleObject failed: %s", windows_error_str(0)); + } while (r == WAIT_TIMEOUT); + CloseHandle(request.event); + + if (r == WAIT_OBJECT_0) + return LIBUSB_SUCCESS; + else + 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; + } +} + +static void windows_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 %u, size %u", io_result, io_size); + + switch (io_result) { + case NO_ERROR: + status = windows_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 = windows_copy_transfer_data(itransfer, io_size); + if (istatus != LIBUSB_TRANSFER_COMPLETED) + usbi_dbg("Failed to copy partial data in aborted operation: %d", istatus); + + usbi_dbg("detected operation aborted"); + status = LIBUSB_TRANSFER_CANCELLED; + break; + default: + usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error %u: %s", io_result, windows_error_str(io_result)); + status = LIBUSB_TRANSFER_ERROR; + break; + } + windows_clear_transfer_priv(itransfer); // Cancel polling + if (status == LIBUSB_TRANSFER_CANCELLED) + usbi_handle_transfer_cancellation(itransfer); + else + usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status); +} + +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); + } +} + +int windows_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; + int r = LIBUSB_SUCCESS; + + 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 = windows_get_fd(transfer); + if (pollable_fd->fd == fds[i].fd) { + found = true; + break; + } + } + usbi_mutex_unlock(&ctx->flying_transfers_lock); + + if (found) { + windows_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. + windows_handle_callback(transfer, io_result, io_size); + } else { + usbi_err(ctx, "could not find a matching transfer for fd %d", fds[i]); + r = LIBUSB_ERROR_NOT_FOUND; + break; + } + } + usbi_mutex_unlock(&ctx->open_devs_lock); + + return r; +} + +int windows_common_init(struct libusb_context *ctx) +{ + if (!windows_init_clock(ctx)) + goto error_roll_back; + + if (!htab_create(ctx, HTAB_SIZE)) + goto error_roll_back; + + return LIBUSB_SUCCESS; + +error_roll_back: + windows_common_exit(); + return LIBUSB_ERROR_NO_MEM; +} + +void windows_common_exit(void) +{ + htab_destroy(); + windows_destroy_clock(); + windows_exit_dlls(); +} diff --git a/Externals/libusb/libusb/os/windows_nt_common.h b/Externals/libusb/libusb/os/windows_nt_common.h new file mode 100644 index 0000000000..9749e00181 --- /dev/null +++ b/Externals/libusb/libusb/os/windows_nt_common.h @@ -0,0 +1,63 @@ +/* + * 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 + * 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 + +// Missing from MinGW +#if !defined(FACILITY_SETUPAPI) +#define FACILITY_SETUPAPI 15 +#endif + +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; + +int windows_common_init(struct libusb_context *ctx); +void windows_common_exit(void); + +unsigned long htab_hash(const char *str); +int windows_clock_gettime(int clk_id, struct timespec *tp); + +void windows_clear_transfer_priv(struct usbi_transfer *itransfer); +int windows_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size); +struct winfd *windows_get_fd(struct usbi_transfer *transfer); +void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size); + +void windows_handle_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size); +int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready); + +#if defined(ENABLE_LOGGING) +const char *windows_error_str(DWORD retval); +#endif diff --git a/Externals/libusb/libusb/os/windows_usbdk.c b/Externals/libusb/libusb/os/windows_usbdk.c new file mode 100644 index 0000000000..7cc5793872 --- /dev/null +++ b/Externals/libusb/libusb/os/windows_usbdk.c @@ -0,0 +1,905 @@ +/* + * windows UsbDk backend for libusb 1.0 + * Copyright © 2014 Red Hat, Inc. + + * Authors: + * Dmitry Fleytman + * Pavel Gurvich + * + * 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 + +#if defined(USE_USBDK) + +#include +#include +#include + +#include "libusbi.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 "windows_usbdk.h" + +#if !defined(STATUS_SUCCESS) +typedef LONG NTSTATUS; +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#endif + +#if !defined(STATUS_CANCELLED) +#define STATUS_CANCELLED ((NTSTATUS)0xC0000120L) +#endif + +#if !defined(STATUS_REQUEST_CANCELED) +#define STATUS_REQUEST_CANCELED ((NTSTATUS)0xC0000703L) +#endif + +#if !defined(USBD_SUCCESS) +typedef int32_t USBD_STATUS; +#define USBD_SUCCESS(Status) ((USBD_STATUS) (Status) >= 0) +#define USBD_PENDING(Status) ((ULONG) (Status) >> 30 == 1) +#define USBD_ERROR(Status) ((USBD_STATUS) (Status) < 0) +#define USBD_STATUS_STALL_PID ((USBD_STATUS) 0xc0000004) +#define USBD_STATUS_ENDPOINT_HALTED ((USBD_STATUS) 0xc0000030) +#define USBD_STATUS_BAD_START_FRAME ((USBD_STATUS) 0xc0000a00) +#define USBD_STATUS_TIMEOUT ((USBD_STATUS) 0xc0006000) +#define USBD_STATUS_CANCELED ((USBD_STATUS) 0xc0010000) +#endif + +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_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); +} + +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_RESET_PIPE ResetPipe; + USBDK_SET_ALTSETTING SetAltsetting; + USBDK_RESET_DEVICE ResetDevice; + USBDK_GET_REDIRECTOR_SYSTEM_HANDLE GetRedirectorSystemHandle; +} usbdk_helper; + +static FARPROC get_usbdk_proc_addr(struct libusb_context *ctx, LPCSTR api_name) +{ + FARPROC api_ptr = GetProcAddress(usbdk_helper.module, api_name); + + if (api_ptr == NULL) + usbi_err(ctx, "UsbDkHelper API %s not found, error %d", api_name, GetLastError()); + + return api_ptr; +} + +static void unload_usbdk_helper_dll(void) +{ + if (usbdk_helper.module != NULL) { + FreeLibrary(usbdk_helper.module); + usbdk_helper.module = NULL; + } +} + +static int load_usbdk_helper_dll(struct libusb_context *ctx) +{ + usbdk_helper.module = LoadLibraryA("UsbDkHelper"); + if (usbdk_helper.module == NULL) { + usbi_err(ctx, "Failed to load UsbDkHelper.dll, error %d", GetLastError()); + 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.ResetPipe = (USBDK_RESET_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ResetPipe"); + if (usbdk_helper.ResetPipe == 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); + usbdk_helper.module = NULL; + return LIBUSB_ERROR_NOT_FOUND; +} + +static int usbdk_init(struct libusb_context *ctx) +{ + int r; + + if (++concurrent_usage == 0) { // First init? + r = load_usbdk_helper_dll(ctx); + if (r) + goto init_exit; + + init_polling(); + + r = windows_common_init(ctx); + if (r) + goto init_exit; + } + // At this stage, either we went through full init successfully, or didn't need to + r = LIBUSB_SUCCESS; + +init_exit: + if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed? + exit_polling(); + windows_common_exit(); + unload_usbdk_helper_dll(); + } + + if (r != LIBUSB_SUCCESS) + --concurrent_usage; // Not expected to call libusb_exit if we failed. + + 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, struct 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 = (uint8_t)info->FilterID; + dev->port_number = (uint8_t)info->Port; + dev->parent_dev = NULL; + + //Addresses in libusb are 1-based + dev->device_address = (uint8_t)(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; + ULONG i; + 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 (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) { + windows_common_exit(); + 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) +{ + UNUSED(dev_handle); + UNUSED(config); + return LIBUSB_SUCCESS; +} + +static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, int iface) +{ + UNUSED(dev_handle); + UNUSED(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) +{ + UNUSED(dev_handle); + UNUSED(iface); + return LIBUSB_SUCCESS; +} + +static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev); + + if (!usbdk_helper.ResetPipe(priv->redirector_handle, endpoint)) { + usbi_err(ctx, "ResetPipe failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_NO_DEVICE; + } + + 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) +{ + UNUSED(dev_handle); + UNUSED(iface); + return LIBUSB_ERROR_NOT_SUPPORTED; +} + +static int usbdk_attach_kernel_driver(struct libusb_device_handle *dev_handle, int iface) +{ + UNUSED(dev_handle); + UNUSED(iface); + return LIBUSB_ERROR_NOT_SUPPORTED; +} + +static int usbdk_detach_kernel_driver(struct libusb_device_handle *dev_handle, int iface) +{ + UNUSED(dev_handle); + UNUSED(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 windows_clear_transfer_priv(struct usbi_transfer *itransfer) +{ + struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + + usbi_free_fd(&transfer_priv->pollable_fd); + + 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); + struct winfd wfd; + ULONG Length; + TransferResult transResult; + HANDLE sysHandle; + + sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle); + + 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; + Length = (ULONG)transfer->length; + + 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; + HANDLE sysHandle; + + 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; + + 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, 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; + HANDLE sysHandle; + + 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; + + 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, 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)) + return LIBUSB_ERROR_NOT_SUPPORTED; //TODO: Check whether we can support this in UsbDk + 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; + } +} + +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 windows_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size) +{ + itransfer->transferred += io_size; + return LIBUSB_TRANSFER_COMPLETED; +} + +struct winfd *windows_get_fd(struct usbi_transfer *transfer) +{ + struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer); + return &transfer_priv->pollable_fd; +} + +static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus) +{ + if (USBD_SUCCESS(UsbdStatus)) + return NO_ERROR; + + switch (UsbdStatus) { + case USBD_STATUS_STALL_PID: + case USBD_STATUS_ENDPOINT_HALTED: + case USBD_STATUS_BAD_START_FRAME: + return ERROR_GEN_FAILURE; + case USBD_STATUS_TIMEOUT: + return ERROR_SEM_TIMEOUT; + case USBD_STATUS_CANCELED: + return ERROR_OPERATION_ABORTED; + default: + return ERROR_FUNCTION_FAILED; + } +} + +void windows_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 = (unsigned int)transfer_priv->IsochronousResultsArray[i].ActualLength; + } + } + + *io_size = (DWORD) transfer_priv->request.Result.GenResult.BytesTransferred; + *io_result = usbdk_translate_usbd_status((USBD_STATUS) transfer_priv->request.Result.GenResult.UsbdStatus); + } + else { + *io_result = GetLastError(); + } +} + +static int usbdk_clock_gettime(int clk_id, struct timespec *tp) +{ + return windows_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, + + NULL, // dev_mem_alloc() + NULL, // dev_mem_free() + + usbdk_kernel_driver_active, + usbdk_detach_kernel_driver, + usbdk_attach_kernel_driver, + + usbdk_destroy_device, + + usbdk_submit_transfer, + usbdk_cancel_transfer, + windows_clear_transfer_priv, + + windows_handle_events, + NULL, + + usbdk_clock_gettime, +#if defined(USBI_TIMERFD_AVAILABLE) + NULL, +#endif + sizeof(struct usbdk_device_priv), + 0, + sizeof(struct usbdk_transfer_priv), +}; + +#endif /* USE_USBDK */ diff --git a/Externals/libusb/libusb/os/windows_usbdk.h b/Externals/libusb/libusb/os/windows_usbdk.h new file mode 100644 index 0000000000..04a9787f2d --- /dev/null +++ b/Externals/libusb/libusb/os/windows_usbdk.h @@ -0,0 +1,146 @@ +/* +* windows UsbDk backend for libusb 1.0 +* Copyright © 2014 Red Hat, Inc. + +* Authors: +* Dmitry Fleytman +* Pavel Gurvich +* +* 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 + +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_TRANSFER_RESULT { + ULONG64 ActualLength; + ULONG64 TransferResult; +} USB_DK_ISO_TRANSFER_RESULT, *PUSB_DK_ISO_TRANSFER_RESULT; + +typedef struct tag_USB_DK_GEN_TRANSFER_RESULT { + ULONG64 BytesTransferred; + ULONG64 UsbdStatus; // USBD_STATUS code +} USB_DK_GEN_TRANSFER_RESULT, *PUSB_DK_GEN_TRANSFER_RESULT; + +typedef struct tag_USB_DK_TRANSFER_RESULT { + USB_DK_GEN_TRANSFER_RESULT GenResult; + 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; + +typedef BOOL (__cdecl *USBDK_GET_DEVICES_LIST)( + PUSB_DK_DEVICE_INFO *DeviceInfo, + PULONG DeviceNumber +); +typedef void (__cdecl *USBDK_RELEASE_DEVICES_LIST)( + PUSB_DK_DEVICE_INFO DeviceInfo +); +typedef HANDLE (__cdecl *USBDK_START_REDIRECT)( + PUSB_DK_DEVICE_ID DeviceId +); +typedef BOOL (__cdecl *USBDK_STOP_REDIRECT)( + HANDLE DeviceHandle +); +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_RESET_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 +); diff --git a/Externals/libusb/libusb/os/windows_winusb.c b/Externals/libusb/libusb/os/windows_winusb.c new file mode 100644 index 0000000000..d1d2749042 --- /dev/null +++ b/Externals/libusb/libusb/os/windows_winusb.c @@ -0,0 +1,4288 @@ +/* + * windows backend for libusb 1.0 + * Copyright © 2009-2012 Pete Batard + * 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 + +#if !defined(USE_USBDK) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libusbi.h" +#include "poll_windows.h" +#include "windows_winusb.h" + +#define HANDLE_VALID(h) (((h) != 0) && ((h) != INVALID_HANDLE_VALUE)) + +// The 2 macros below are used in conjunction with safe loops. +#define LOOP_CHECK(fcall) \ + { \ + r = fcall; \ + if (r != LIBUSB_SUCCESS) \ + continue; \ + } +#define LOOP_BREAK(err) \ + { \ + r = err; \ + continue; \ + } + +// WinUSB-like API prototypes +static int winusbx_init(int sub_api, struct libusb_context *ctx); +static int winusbx_exit(int sub_api); +static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle); +static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle); +static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface); +static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); +static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); +static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer); +static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting); +static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer); +static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint); +static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer); +static int winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer); +static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle); +static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size); +// HID API prototypes +static int hid_init(int sub_api, struct libusb_context *ctx); +static int hid_exit(int sub_api); +static int hid_open(int sub_api, struct libusb_device_handle *dev_handle); +static void hid_close(int sub_api, struct libusb_device_handle *dev_handle); +static int hid_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); +static int hid_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); +static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting); +static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer); +static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer); +static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint); +static int hid_abort_transfers(int sub_api, struct usbi_transfer *itransfer); +static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle); +static int hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size); +// Composite API prototypes +static int composite_init(int sub_api, struct libusb_context *ctx); +static int composite_exit(int sub_api); +static int composite_open(int sub_api, struct libusb_device_handle *dev_handle); +static void composite_close(int sub_api, struct libusb_device_handle *dev_handle); +static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); +static int composite_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting); +static int composite_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); +static int composite_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer); +static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer); +static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer); +static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint); +static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfer); +static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer); +static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle); +static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size); + + +// Global variables +int windows_version = WINDOWS_UNDEFINED; +static char windows_version_str[128] = "Windows Undefined"; +// Concurrency +static int concurrent_usage = -1; +static usbi_mutex_t autoclaim_lock; +// 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) + +static HMODULE WinUSBX_handle = NULL; +static struct winusb_interface WinUSBX[SUB_API_MAX]; +static const char *sub_api_name[SUB_API_MAX] = WINUSBX_DRV_NAMES; + +static bool api_hid_available = false; +#define CHECK_HID_AVAILABLE \ + do { \ + if (!api_hid_available) \ + return LIBUSB_ERROR_ACCESS; \ + } while (0) + +static inline BOOLEAN guid_eq(const GUID *guid1, const GUID *guid2) +{ + if ((guid1 != NULL) && (guid2 != NULL)) + return (memcmp(guid1, guid2, sizeof(GUID)) == 0); + + return false; +} + +#if defined(ENABLE_LOGGING) +static char *guid_to_string(const GUID *guid) +{ + static char guid_string[MAX_GUID_STRING_LENGTH]; + + if (guid == NULL) + return NULL; + + sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + (unsigned int)guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], + guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); + + return guid_string; +} +#endif + +/* + * Sanitize Microsoft's paths: convert to uppercase, add prefix and fix backslashes. + * Return an allocated sanitized string or NULL on error. + */ +static char *sanitize_path(const char *path) +{ + const char root_prefix[] = "\\\\.\\"; + size_t j, size, root_size; + char *ret_path = NULL; + size_t add_root = 0; + + if (path == NULL) + return NULL; + + size = safe_strlen(path) + 1; + root_size = sizeof(root_prefix) - 1; + + // Microsoft indiscriminately uses '\\?\', '\\.\', '##?#" or "##.#" for root prefixes. + if (!((size > 3) && (((path[0] == '\\') && (path[1] == '\\') && (path[3] == '\\')) + || ((path[0] == '#') && (path[1] == '#') && (path[3] == '#'))))) { + add_root = root_size; + size += add_root; + } + + ret_path = calloc(1, size); + if (ret_path == NULL) + return NULL; + + safe_strcpy(&ret_path[add_root], size-add_root, path); + + // Ensure consistency with root prefix + for (j = 0; j < root_size; j++) + ret_path[j] = root_prefix[j]; + + // Same goes for '\' and '#' after the root prefix. Ensure '#' is used + for (j = root_size; j < size; j++) { + ret_path[j] = (char)toupper((int)ret_path[j]); // Fix case too + if (ret_path[j] == '\\') + ret_path[j] = '#'; + } + + return ret_path; +} + +/* + * Cfgmgr32, OLE32 and SetupAPI DLL functions + */ +static int init_dlls(void) +{ + DLL_GET_HANDLE(Cfgmgr32); + DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Parent, TRUE); + DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Child, TRUE); + DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Sibling, TRUE); + DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Device_IDA, TRUE); + + // Prefixed to avoid conflict with header files + DLL_GET_HANDLE(AdvAPI32); + DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExW, TRUE); + DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegCloseKey, TRUE); + + DLL_GET_HANDLE(Kernel32); + DLL_LOAD_FUNC_PREFIXED(Kernel32, p, IsWow64Process, FALSE); + + DLL_GET_HANDLE(OLE32); + DLL_LOAD_FUNC_PREFIXED(OLE32, p, CLSIDFromString, TRUE); + + DLL_GET_HANDLE(SetupAPI); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetClassDevsA, TRUE); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInfo, TRUE); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInterfaces, TRUE); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInterfaceDetailA, TRUE); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiDestroyDeviceInfoList, TRUE); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDevRegKey, TRUE); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceRegistryPropertyA, TRUE); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDeviceInterfaceRegKey, TRUE); + + return LIBUSB_SUCCESS; +} + +static void exit_dlls(void) +{ + DLL_FREE_HANDLE(Cfgmgr32); + DLL_FREE_HANDLE(AdvAPI32); + DLL_FREE_HANDLE(Kernel32); + DLL_FREE_HANDLE(OLE32); + DLL_FREE_HANDLE(SetupAPI); +} + +/* + * enumerate interfaces for the whole USB class + * + * Parameters: + * dev_info: a pointer to a dev_info list + * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed) + * usb_class: the generic USB class for which to retrieve interface details + * index: zero based index of the interface in the device info list + * + * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA + * structure returned and call this function repeatedly using the same guid (with an + * incremented index starting at zero) until all interfaces have been returned. + */ +static bool get_devinfo_data(struct libusb_context *ctx, + HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const char *usb_class, unsigned _index) +{ + if (_index <= 0) { + *dev_info = pSetupDiGetClassDevsA(NULL, usb_class, NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES); + if (*dev_info == INVALID_HANDLE_VALUE) + return false; + } + + dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA); + if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) { + if (GetLastError() != ERROR_NO_MORE_ITEMS) + usbi_err(ctx, "Could not obtain device info data for index %u: %s", + _index, windows_error_str(0)); + + pSetupDiDestroyDeviceInfoList(*dev_info); + *dev_info = INVALID_HANDLE_VALUE; + return false; + } + return true; +} + +/* + * enumerate interfaces for a specific GUID + * + * Parameters: + * dev_info: a pointer to a dev_info list + * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed) + * guid: the GUID for which to retrieve interface details + * index: zero based index of the interface in the device info list + * + * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA + * structure returned and call this function repeatedly using the same guid (with an + * incremented index starting at zero) until all interfaces have been returned. + */ +static SP_DEVICE_INTERFACE_DETAIL_DATA_A *get_interface_details(struct libusb_context *ctx, + HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const GUID *guid, unsigned _index) +{ + SP_DEVICE_INTERFACE_DATA dev_interface_data; + SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL; + DWORD size; + + if (_index <= 0) + *dev_info = pSetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); + + if (dev_info_data != NULL) { + dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA); + if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) { + if (GetLastError() != ERROR_NO_MORE_ITEMS) + usbi_err(ctx, "Could not obtain device info data for index %u: %s", + _index, windows_error_str(0)); + + pSetupDiDestroyDeviceInfoList(*dev_info); + *dev_info = INVALID_HANDLE_VALUE; + return NULL; + } + } + + dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + if (!pSetupDiEnumDeviceInterfaces(*dev_info, NULL, guid, _index, &dev_interface_data)) { + if (GetLastError() != ERROR_NO_MORE_ITEMS) + usbi_err(ctx, "Could not obtain interface data for index %u: %s", + _index, windows_error_str(0)); + + pSetupDiDestroyDeviceInfoList(*dev_info); + *dev_info = INVALID_HANDLE_VALUE; + return NULL; + } + + // Read interface data (dummy + actual) to access the device path + if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, NULL, 0, &size, NULL)) { + // The dummy call should fail with ERROR_INSUFFICIENT_BUFFER + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + usbi_err(ctx, "could not access interface data (dummy) for index %u: %s", + _index, windows_error_str(0)); + goto err_exit; + } + } else { + usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong."); + goto err_exit; + } + + dev_interface_details = calloc(1, size); + if (dev_interface_details == NULL) { + usbi_err(ctx, "could not allocate interface data for index %u.", _index); + goto err_exit; + } + + dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); + if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, + dev_interface_details, size, &size, NULL)) { + usbi_err(ctx, "could not access interface data (actual) for index %u: %s", + _index, windows_error_str(0)); + } + + return dev_interface_details; + +err_exit: + pSetupDiDestroyDeviceInfoList(*dev_info); + *dev_info = INVALID_HANDLE_VALUE; + return NULL; +} + +/* For libusb0 filter */ +static SP_DEVICE_INTERFACE_DETAIL_DATA_A *get_interface_details_filter(struct libusb_context *ctx, + HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const GUID *guid, unsigned _index, char *filter_path) +{ + SP_DEVICE_INTERFACE_DATA dev_interface_data; + SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL; + DWORD size; + + if (_index <= 0) + *dev_info = pSetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); + + if (dev_info_data != NULL) { + dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA); + if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) { + if (GetLastError() != ERROR_NO_MORE_ITEMS) + usbi_err(ctx, "Could not obtain device info data for index %u: %s", + _index, windows_error_str(0)); + + pSetupDiDestroyDeviceInfoList(*dev_info); + *dev_info = INVALID_HANDLE_VALUE; + return NULL; + } + } + + dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + if (!pSetupDiEnumDeviceInterfaces(*dev_info, NULL, guid, _index, &dev_interface_data)) { + if (GetLastError() != ERROR_NO_MORE_ITEMS) + usbi_err(ctx, "Could not obtain interface data for index %u: %s", + _index, windows_error_str(0)); + + pSetupDiDestroyDeviceInfoList(*dev_info); + *dev_info = INVALID_HANDLE_VALUE; + return NULL; + } + + // Read interface data (dummy + actual) to access the device path + if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, NULL, 0, &size, NULL)) { + // The dummy call should fail with ERROR_INSUFFICIENT_BUFFER + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + usbi_err(ctx, "could not access interface data (dummy) for index %u: %s", + _index, windows_error_str(0)); + goto err_exit; + } + } else { + usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong."); + goto err_exit; + } + + dev_interface_details = calloc(1, size); + if (dev_interface_details == NULL) { + usbi_err(ctx, "could not allocate interface data for index %u.", _index); + goto err_exit; + } + + dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); + if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, dev_interface_details, size, &size, NULL)) + usbi_err(ctx, "could not access interface data (actual) for index %u: %s", + _index, windows_error_str(0)); + + // [trobinso] lookup the libusb0 symbolic index. + if (dev_interface_details) { + HKEY hkey_device_interface = pSetupDiOpenDeviceInterfaceRegKey(*dev_info, &dev_interface_data, 0, KEY_READ); + if (hkey_device_interface != INVALID_HANDLE_VALUE) { + DWORD libusb0_symboliclink_index = 0; + DWORD value_length = sizeof(DWORD); + DWORD value_type = 0; + LONG status; + + status = pRegQueryValueExW(hkey_device_interface, L"LUsb0", NULL, &value_type, + (LPBYTE)&libusb0_symboliclink_index, &value_length); + if (status == ERROR_SUCCESS) { + if (libusb0_symboliclink_index < 256) { + // libusb0.sys is connected to this device instance. + // If the the device interface guid is {F9F3FF14-AE21-48A0-8A25-8011A7A931D9} then it's a filter. + safe_sprintf(filter_path, sizeof("\\\\.\\libusb0-0000"), "\\\\.\\libusb0-%04u", (unsigned int)libusb0_symboliclink_index); + usbi_dbg("assigned libusb0 symbolic link %s", filter_path); + } else { + // libusb0.sys was connected to this device instance at one time; but not anymore. + } + } + pRegCloseKey(hkey_device_interface); + } + } + + return dev_interface_details; + +err_exit: + pSetupDiDestroyDeviceInfoList(*dev_info); + *dev_info = INVALID_HANDLE_VALUE; + return NULL; +} + +/* + * Returns the session ID of a device's nth level ancestor + * If there's no device at the nth level, return 0 + */ +static unsigned long get_ancestor_session_id(DWORD devinst, unsigned level) +{ + DWORD parent_devinst; + unsigned long session_id = 0; + char *sanitized_path = NULL; + char path[MAX_PATH_LENGTH]; + unsigned i; + + if (level < 1) + return 0; + + for (i = 0; i < level; i++) { + if (CM_Get_Parent(&parent_devinst, devinst, 0) != CR_SUCCESS) + return 0; + devinst = parent_devinst; + } + + if (CM_Get_Device_IDA(devinst, path, MAX_PATH_LENGTH, 0) != CR_SUCCESS) + return 0; + + // TODO: (post hotplug): try without sanitizing + sanitized_path = sanitize_path(path); + if (sanitized_path == NULL) + return 0; + + session_id = htab_hash(sanitized_path); + safe_free(sanitized_path); + return session_id; +} + +/* + * Determine which interface the given endpoint address belongs to + */ +static int get_interface_by_endpoint(struct libusb_config_descriptor *conf_desc, uint8_t ep) +{ + const struct libusb_interface *intf; + const struct libusb_interface_descriptor *intf_desc; + int i, j, k; + + for (i = 0; i < conf_desc->bNumInterfaces; i++) { + intf = &conf_desc->interface[i]; + for (j = 0; j < intf->num_altsetting; j++) { + intf_desc = &intf->altsetting[j]; + for (k = 0; k < intf_desc->bNumEndpoints; k++) { + if (intf_desc->endpoint[k].bEndpointAddress == ep) { + usbi_dbg("found endpoint %02X on interface %d", intf_desc->bInterfaceNumber, i); + return intf_desc->bInterfaceNumber; + } + } + } + } + + usbi_dbg("endpoint %02X not found on any interface", ep); + return LIBUSB_ERROR_NOT_FOUND; +} + +/* + * Populate the endpoints addresses of the device_priv interface helper structs + */ +static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, int iface, int altsetting) +{ + int i, r; + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + struct libusb_config_descriptor *conf_desc; + const struct libusb_interface_descriptor *if_desc; + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + + r = libusb_get_active_config_descriptor(dev_handle->dev, &conf_desc); + if (r != LIBUSB_SUCCESS) { + usbi_warn(ctx, "could not read config descriptor: error %d", r); + return r; + } + + if_desc = &conf_desc->interface[iface].altsetting[altsetting]; + safe_free(priv->usb_interface[iface].endpoint); + + if (if_desc->bNumEndpoints == 0) { + usbi_dbg("no endpoints found for interface %d", iface); + libusb_free_config_descriptor(conf_desc); + return LIBUSB_SUCCESS; + } + + priv->usb_interface[iface].endpoint = malloc(if_desc->bNumEndpoints); + if (priv->usb_interface[iface].endpoint == NULL) { + libusb_free_config_descriptor(conf_desc); + return LIBUSB_ERROR_NO_MEM; + } + + priv->usb_interface[iface].nb_endpoints = if_desc->bNumEndpoints; + for (i = 0; i < if_desc->bNumEndpoints; i++) { + priv->usb_interface[iface].endpoint[i] = if_desc->endpoint[i].bEndpointAddress; + usbi_dbg("(re)assigned endpoint %02X to interface %d", priv->usb_interface[iface].endpoint[i], iface); + } + libusb_free_config_descriptor(conf_desc); + + // Extra init may be required to configure endpoints + return priv->apib->configure_endpoints(SUB_API_NOTSET, dev_handle, iface); +} + +// Lookup for a match in the list of API driver names +// return -1 if not found, driver match number otherwise +static int get_sub_api(char *driver, int api) +{ + int i; + const char sep_str[2] = {LIST_SEPARATOR, 0}; + char *tok, *tmp_str; + size_t len = safe_strlen(driver); + + if (len == 0) + return SUB_API_NOTSET; + + tmp_str = _strdup(driver); + if (tmp_str == NULL) + return SUB_API_NOTSET; + + tok = strtok(tmp_str, sep_str); + while (tok != NULL) { + for (i = 0; i < usb_api_backend[api].nb_driver_names; i++) { + if (safe_stricmp(tok, usb_api_backend[api].driver_name_list[i]) == 0) { + free(tmp_str); + return i; + } + } + tok = strtok(NULL, sep_str); + } + + free(tmp_str); + return SUB_API_NOTSET; +} + +/* + * auto-claiming and auto-release helper functions + */ +static int auto_claim(struct libusb_transfer *transfer, int *interface_number, int api_type) +{ + struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct windows_device_handle_priv *handle_priv = _device_handle_priv( + transfer->dev_handle); + struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + int current_interface = *interface_number; + int r = LIBUSB_SUCCESS; + + switch(api_type) { + case USB_API_WINUSBX: + case USB_API_HID: + break; + default: + return LIBUSB_ERROR_INVALID_PARAM; + } + + usbi_mutex_lock(&autoclaim_lock); + if (current_interface < 0) { // No serviceable interface was found + for (current_interface = 0; current_interface < USB_MAXINTERFACES; current_interface++) { + // Must claim an interface of the same API type + if ((priv->usb_interface[current_interface].apib->id == api_type) + && (libusb_claim_interface(transfer->dev_handle, current_interface) == LIBUSB_SUCCESS)) { + usbi_dbg("auto-claimed interface %d for control request", current_interface); + if (handle_priv->autoclaim_count[current_interface] != 0) + usbi_warn(ctx, "program assertion failed - autoclaim_count was nonzero"); + handle_priv->autoclaim_count[current_interface]++; + break; + } + } + if (current_interface == USB_MAXINTERFACES) { + usbi_err(ctx, "could not auto-claim any interface"); + r = LIBUSB_ERROR_NOT_FOUND; + } + } else { + // If we have a valid interface that was autoclaimed, we must increment + // its autoclaim count so that we can prevent an early release. + if (handle_priv->autoclaim_count[current_interface] != 0) + handle_priv->autoclaim_count[current_interface]++; + } + usbi_mutex_unlock(&autoclaim_lock); + + *interface_number = current_interface; + return r; +} + +static void auto_release(struct usbi_transfer *itransfer) +{ + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + libusb_device_handle *dev_handle = transfer->dev_handle; + struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + int r; + + usbi_mutex_lock(&autoclaim_lock); + if (handle_priv->autoclaim_count[transfer_priv->interface_number] > 0) { + handle_priv->autoclaim_count[transfer_priv->interface_number]--; + if (handle_priv->autoclaim_count[transfer_priv->interface_number] == 0) { + r = libusb_release_interface(dev_handle, transfer_priv->interface_number); + if (r == LIBUSB_SUCCESS) + usbi_dbg("auto-released interface %d", transfer_priv->interface_number); + else + usbi_dbg("failed to auto-release interface %d (%s)", + transfer_priv->interface_number, libusb_error_name((enum libusb_error)r)); + } + } + usbi_mutex_unlock(&autoclaim_lock); +} + +/* Windows version dtection */ +static BOOL is_x64(void) +{ + BOOL ret = FALSE; + + // Detect if we're running a 32 or 64 bit system + if (sizeof(uintptr_t) < 8) { + if (pIsWow64Process != NULL) + pIsWow64Process(GetCurrentProcess(), &ret); + } else { + ret = TRUE; + } + + return ret; +} + +static void get_windows_version(void) +{ + OSVERSIONINFOEXA vi, vi2; + const char *w = 0; + const char *w64 = "32 bit"; + char *vptr; + size_t vlen; + unsigned major, minor; + ULONGLONG major_equal, minor_equal; + BOOL ws; + + memset(&vi, 0, sizeof(vi)); + vi.dwOSVersionInfoSize = sizeof(vi); + if (!GetVersionExA((OSVERSIONINFOA *)&vi)) { + memset(&vi, 0, sizeof(vi)); + vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); + if (!GetVersionExA((OSVERSIONINFOA *)&vi)) + return; + } + + if (vi.dwPlatformId == VER_PLATFORM_WIN32_NT) { + if (vi.dwMajorVersion > 6 || (vi.dwMajorVersion == 6 && vi.dwMinorVersion >= 2)) { + // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the actual OS version + // See: http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx + + major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL); + for (major = vi.dwMajorVersion; major <= 9; major++) { + memset(&vi2, 0, sizeof(vi2)); + vi2.dwOSVersionInfoSize = sizeof(vi2); + vi2.dwMajorVersion = major; + if (!VerifyVersionInfoA(&vi2, VER_MAJORVERSION, major_equal)) + continue; + + if (vi.dwMajorVersion < major) { + vi.dwMajorVersion = major; + vi.dwMinorVersion = 0; + } + + minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL); + for (minor = vi.dwMinorVersion; minor <= 9; minor++) { + memset(&vi2, 0, sizeof(vi2)); + vi2.dwOSVersionInfoSize = sizeof(vi2); + vi2.dwMinorVersion = minor; + if (!VerifyVersionInfoA(&vi2, VER_MINORVERSION, minor_equal)) + continue; + + vi.dwMinorVersion = minor; + break; + } + + break; + } + } + + if (vi.dwMajorVersion <= 0xf && vi.dwMinorVersion <= 0xf) { + ws = (vi.wProductType <= VER_NT_WORKSTATION); + windows_version = vi.dwMajorVersion << 4 | vi.dwMinorVersion; + switch (windows_version) { + case 0x50: w = "2000"; break; + case 0x51: w = "XP"; break; + case 0x52: w = ("2003"); break; + case 0x60: w = (ws ? "Vista" : "2008"); break; + case 0x61: w = (ws ? "7" : "2008_R2"); break; + case 0x62: w = (ws ? "8" : "2012"); break; + case 0x63: w = (ws ? "8.1": "2012_R2"); break; + case 0x64: w = (ws ? "10": "2015"); break; + default: + if (windows_version < 0x50) + windows_version = WINDOWS_UNSUPPORTED; + else + w = "11 or later"; + break; + } + } + } + + if (is_x64()) + w64 = "64-bit"; + + vptr = &windows_version_str[sizeof("Windows ") - 1]; + vlen = sizeof(windows_version_str) - sizeof("Windows ") - 1; + if (!w) + safe_sprintf(vptr, vlen, "%s %u.%u %s", (vi.dwPlatformId == VER_PLATFORM_WIN32_NT ? "NT" : "??"), + (unsigned int)vi.dwMajorVersion, (unsigned int)vi.dwMinorVersion, w64); + else if (vi.wServicePackMinor) + safe_sprintf(vptr, vlen, "%s SP%u.%u %s", w, vi.wServicePackMajor, vi.wServicePackMinor, w64); + else if (vi.wServicePackMajor) + safe_sprintf(vptr, vlen, "%s SP%u %s", w, vi.wServicePackMajor, w64); + else + safe_sprintf(vptr, vlen, "%s %s", w, w64); +} + +/* + * init: libusb backend init function + * + * This function enumerates the HCDs (Host Controller Drivers) and populates our private HCD list + * In our implementation, we equate Windows' "HCD" to libusb's "bus". Note that bus is zero indexed. + * HCDs are not expected to change after init (might not hold true for hot pluggable USB PCI card?) + */ +static int windows_init(struct libusb_context *ctx) +{ + int i, r = LIBUSB_ERROR_OTHER; + HANDLE semaphore; + char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0' + + sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF)); + semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name); + if (semaphore == NULL) { + usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0)); + return LIBUSB_ERROR_NO_MEM; + } + + // A successful wait brings our semaphore count to 0 (unsignaled) + // => any concurent wait stalls until the semaphore's release + if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) { + usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0)); + CloseHandle(semaphore); + return LIBUSB_ERROR_NO_MEM; + } + + // NB: concurrent usage supposes that init calls are equally balanced with + // exit calls. If init is called more than exit, we will not exit properly + if (++concurrent_usage == 0) { // First init? + get_windows_version(); + usbi_dbg(windows_version_str); + + if (windows_version == WINDOWS_UNSUPPORTED) { + usbi_err(ctx, "This version of Windows is NOT supported"); + r = LIBUSB_ERROR_NOT_SUPPORTED; + goto init_exit; + } + + // We need a lock for proper auto-release + usbi_mutex_init(&autoclaim_lock); + + // Initialize pollable file descriptors + init_polling(); + + // Load DLL imports + if (init_dlls() != LIBUSB_SUCCESS) { + usbi_err(ctx, "could not resolve DLL functions"); + goto init_exit; + } + + // Initialize the low level APIs (we don't care about errors at this stage) + for (i = 0; i < USB_API_MAX; i++) + usb_api_backend[i].init(SUB_API_NOTSET, ctx); + + r = windows_common_init(ctx); + if (r) + goto init_exit; + } + // At this stage, either we went through full init successfully, or didn't need to + r = LIBUSB_SUCCESS; + +init_exit: // Holds semaphore here. + if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed? + for (i = 0; i < USB_API_MAX; i++) + usb_api_backend[i].exit(SUB_API_NOTSET); + exit_dlls(); + exit_polling(); + windows_common_exit(); + usbi_mutex_destroy(&autoclaim_lock); + } + + if (r != LIBUSB_SUCCESS) + --concurrent_usage; // Not expected to call libusb_exit if we failed. + + ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1 + CloseHandle(semaphore); + return r; +} + +/* + * HCD (root) hubs need to have their device descriptor manually populated + * + * Note that, like Microsoft does in the device manager, we populate the + * Vendor and Device ID for HCD hubs with the ones from the PCI HCD device. + */ +static int force_hcd_device_descriptor(struct libusb_device *dev) +{ + struct windows_device_priv *parent_priv, *priv = _device_priv(dev); + struct libusb_context *ctx = DEVICE_CTX(dev); + int vid, pid; + + dev->num_configurations = 1; + priv->dev_descriptor.bLength = sizeof(USB_DEVICE_DESCRIPTOR); + priv->dev_descriptor.bDescriptorType = USB_DEVICE_DESCRIPTOR_TYPE; + priv->dev_descriptor.bNumConfigurations = 1; + priv->active_config = 1; + + if (dev->parent_dev == NULL) { + usbi_err(ctx, "program assertion failed - HCD hub has no parent"); + return LIBUSB_ERROR_NO_DEVICE; + } + + parent_priv = _device_priv(dev->parent_dev); + if (sscanf(parent_priv->path, "\\\\.\\PCI#VEN_%04x&DEV_%04x%*s", &vid, &pid) == 2) { + priv->dev_descriptor.idVendor = (uint16_t)vid; + priv->dev_descriptor.idProduct = (uint16_t)pid; + } else { + usbi_warn(ctx, "could not infer VID/PID of HCD hub from '%s'", parent_priv->path); + priv->dev_descriptor.idVendor = 0x1d6b; // Linux Foundation root hub + priv->dev_descriptor.idProduct = 1; + } + + return LIBUSB_SUCCESS; +} + +/* + * fetch and cache all the config descriptors through I/O + */ +static int cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handle, char *device_id) +{ + DWORD size, ret_size; + struct libusb_context *ctx = DEVICE_CTX(dev); + struct windows_device_priv *priv = _device_priv(dev); + int r; + uint8_t i; + + USB_CONFIGURATION_DESCRIPTOR_SHORT cd_buf_short; // dummy request + PUSB_DESCRIPTOR_REQUEST cd_buf_actual = NULL; // actual request + PUSB_CONFIGURATION_DESCRIPTOR cd_data = NULL; + + if (dev->num_configurations == 0) + return LIBUSB_ERROR_INVALID_PARAM; + + priv->config_descriptor = calloc(dev->num_configurations, sizeof(unsigned char *)); + if (priv->config_descriptor == NULL) + return LIBUSB_ERROR_NO_MEM; + + for (i = 0; i < dev->num_configurations; i++) + priv->config_descriptor[i] = NULL; + + for (i = 0, r = LIBUSB_SUCCESS; ; i++) { + // safe loop: release all dynamic resources + safe_free(cd_buf_actual); + + // safe loop: end of loop condition + if ((i >= dev->num_configurations) || (r != LIBUSB_SUCCESS)) + break; + + size = sizeof(USB_CONFIGURATION_DESCRIPTOR_SHORT); + memset(&cd_buf_short, 0, size); + + cd_buf_short.req.ConnectionIndex = (ULONG)priv->port; + cd_buf_short.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN; + cd_buf_short.req.SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR; + cd_buf_short.req.SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i; + cd_buf_short.req.SetupPacket.wIndex = 0; + cd_buf_short.req.SetupPacket.wLength = (USHORT)(size - sizeof(USB_DESCRIPTOR_REQUEST)); + + // Dummy call to get the required data size. Initial failures are reported as info rather + // than error as they can occur for non-penalizing situations, such as with some hubs. + // coverity[tainted_data_argument] + if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, &cd_buf_short, size, + &cd_buf_short, size, &ret_size, NULL)) { + usbi_info(ctx, "could not access configuration descriptor (dummy) for '%s': %s", device_id, windows_error_str(0)); + LOOP_BREAK(LIBUSB_ERROR_IO); + } + + if ((ret_size != size) || (cd_buf_short.data.wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))) { + usbi_info(ctx, "unexpected configuration descriptor size (dummy) for '%s'.", device_id); + LOOP_BREAK(LIBUSB_ERROR_IO); + } + + size = sizeof(USB_DESCRIPTOR_REQUEST) + cd_buf_short.data.wTotalLength; + cd_buf_actual = calloc(1, size); + if (cd_buf_actual == NULL) { + usbi_err(ctx, "could not allocate configuration descriptor buffer for '%s'.", device_id); + LOOP_BREAK(LIBUSB_ERROR_NO_MEM); + } + + // Actual call + cd_buf_actual->ConnectionIndex = (ULONG)priv->port; + cd_buf_actual->SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN; + cd_buf_actual->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR; + cd_buf_actual->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i; + cd_buf_actual->SetupPacket.wIndex = 0; + cd_buf_actual->SetupPacket.wLength = (USHORT)(size - sizeof(USB_DESCRIPTOR_REQUEST)); + + if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, cd_buf_actual, size, + cd_buf_actual, size, &ret_size, NULL)) { + usbi_err(ctx, "could not access configuration descriptor (actual) for '%s': %s", device_id, windows_error_str(0)); + LOOP_BREAK(LIBUSB_ERROR_IO); + } + + cd_data = (PUSB_CONFIGURATION_DESCRIPTOR)((UCHAR *)cd_buf_actual + sizeof(USB_DESCRIPTOR_REQUEST)); + + if ((size != ret_size) || (cd_data->wTotalLength != cd_buf_short.data.wTotalLength)) { + usbi_err(ctx, "unexpected configuration descriptor size (actual) for '%s'.", device_id); + LOOP_BREAK(LIBUSB_ERROR_IO); + } + + if (cd_data->bDescriptorType != USB_CONFIGURATION_DESCRIPTOR_TYPE) { + usbi_err(ctx, "not a configuration descriptor for '%s'", device_id); + LOOP_BREAK(LIBUSB_ERROR_IO); + } + + usbi_dbg("cached config descriptor %d (bConfigurationValue=%u, %u bytes)", + i, cd_data->bConfigurationValue, cd_data->wTotalLength); + + // Cache the descriptor + priv->config_descriptor[i] = malloc(cd_data->wTotalLength); + if (priv->config_descriptor[i] == NULL) + LOOP_BREAK(LIBUSB_ERROR_NO_MEM); + memcpy(priv->config_descriptor[i], cd_data, cd_data->wTotalLength); + } + return LIBUSB_SUCCESS; +} + +/* + * Populate a libusb device structure + */ +static int init_device(struct libusb_device *dev, struct libusb_device *parent_dev, + uint8_t port_number, char *device_id, DWORD devinst) +{ + HANDLE handle; + DWORD size; + USB_NODE_CONNECTION_INFORMATION_EX conn_info; + USB_NODE_CONNECTION_INFORMATION_EX_V2 conn_info_v2; + struct windows_device_priv *priv, *parent_priv; + struct libusb_context *ctx; + struct libusb_device *tmp_dev; + unsigned long tmp_id; + unsigned i; + + if ((dev == NULL) || (parent_dev == NULL)) + return LIBUSB_ERROR_NOT_FOUND; + + ctx = DEVICE_CTX(dev); + priv = _device_priv(dev); + parent_priv = _device_priv(parent_dev); + if (parent_priv->apib->id != USB_API_HUB) { + usbi_warn(ctx, "parent for device '%s' is not a hub", device_id); + return LIBUSB_ERROR_NOT_FOUND; + } + + // It is possible for the parent hub not to have been initialized yet + // If that's the case, lookup the ancestors to set the bus number + if (parent_dev->bus_number == 0) { + for (i = 2; ; i++) { + tmp_id = get_ancestor_session_id(devinst, i); + if (tmp_id == 0) + break; + + tmp_dev = usbi_get_device_by_session_id(ctx, tmp_id); + if (tmp_dev == NULL) + continue; + + if (tmp_dev->bus_number != 0) { + usbi_dbg("got bus number from ancestor #%u", i); + parent_dev->bus_number = tmp_dev->bus_number; + libusb_unref_device(tmp_dev); + break; + } + + libusb_unref_device(tmp_dev); + } + } + + if (parent_dev->bus_number == 0) { + usbi_err(ctx, "program assertion failed: unable to find ancestor bus number for '%s'", device_id); + return LIBUSB_ERROR_NOT_FOUND; + } + + dev->bus_number = parent_dev->bus_number; + priv->port = port_number; + dev->port_number = port_number; + priv->depth = parent_priv->depth + 1; + dev->parent_dev = parent_dev; + + // If the device address is already set, we can stop here + if (dev->device_address != 0) + return LIBUSB_SUCCESS; + + memset(&conn_info, 0, sizeof(conn_info)); + if (priv->depth != 0) { // Not a HCD hub + handle = CreateFileA(parent_priv->path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, NULL); + if (handle == INVALID_HANDLE_VALUE) { + usbi_warn(ctx, "could not open hub %s: %s", parent_priv->path, windows_error_str(0)); + return LIBUSB_ERROR_ACCESS; + } + + size = sizeof(conn_info); + conn_info.ConnectionIndex = (ULONG)port_number; + // coverity[tainted_data_argument] + if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, size, + &conn_info, size, &size, NULL)) { + usbi_warn(ctx, "could not get node connection information for device '%s': %s", + device_id, windows_error_str(0)); + safe_closehandle(handle); + return LIBUSB_ERROR_NO_DEVICE; + } + + if (conn_info.ConnectionStatus == NoDeviceConnected) { + usbi_err(ctx, "device '%s' is no longer connected!", device_id); + safe_closehandle(handle); + return LIBUSB_ERROR_NO_DEVICE; + } + + memcpy(&priv->dev_descriptor, &(conn_info.DeviceDescriptor), sizeof(USB_DEVICE_DESCRIPTOR)); + dev->num_configurations = priv->dev_descriptor.bNumConfigurations; + priv->active_config = conn_info.CurrentConfigurationValue; + usbi_dbg("found %u configurations (active conf: %u)", dev->num_configurations, priv->active_config); + + // If we can't read the config descriptors, just set the number of confs to zero + if (cache_config_descriptors(dev, handle, device_id) != LIBUSB_SUCCESS) { + dev->num_configurations = 0; + priv->dev_descriptor.bNumConfigurations = 0; + } + + // In their great wisdom, Microsoft decided to BREAK the USB speed report between Windows 7 and Windows 8 + if (windows_version >= WINDOWS_8) { + memset(&conn_info_v2, 0, sizeof(conn_info_v2)); + size = sizeof(conn_info_v2); + conn_info_v2.ConnectionIndex = (ULONG)port_number; + conn_info_v2.Length = size; + conn_info_v2.SupportedUsbProtocols.Usb300 = 1; + if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2, + &conn_info_v2, size, &conn_info_v2, size, &size, NULL)) { + usbi_warn(ctx, "could not get node connection information (V2) for device '%s': %s", + device_id, windows_error_str(0)); + } else if (conn_info_v2.Flags.DeviceIsOperatingAtSuperSpeedOrHigher) { + conn_info.Speed = 3; + } + } + + safe_closehandle(handle); + + if (conn_info.DeviceAddress > UINT8_MAX) + usbi_err(ctx, "program assertion failed: device address overflow"); + + dev->device_address = (uint8_t)conn_info.DeviceAddress + 1; + if (dev->device_address == 1) + usbi_err(ctx, "program assertion failed: device address collision with root hub"); + + switch (conn_info.Speed) { + case 0: dev->speed = LIBUSB_SPEED_LOW; break; + case 1: dev->speed = LIBUSB_SPEED_FULL; break; + case 2: dev->speed = LIBUSB_SPEED_HIGH; break; + case 3: dev->speed = LIBUSB_SPEED_SUPER; break; + default: + usbi_warn(ctx, "Got unknown device speed %u", conn_info.Speed); + break; + } + } else { + dev->device_address = 1; // root hubs are set to use device number 1 + force_hcd_device_descriptor(dev); + } + + usbi_sanitize_device(dev); + + usbi_dbg("(bus: %u, addr: %u, depth: %u, port: %u): '%s'", + dev->bus_number, dev->device_address, priv->depth, priv->port, device_id); + + return LIBUSB_SUCCESS; +} + +// Returns the api type, or 0 if not found/unsupported +static void get_api_type(struct libusb_context *ctx, HDEVINFO *dev_info, + SP_DEVINFO_DATA *dev_info_data, int *api, int *sub_api) +{ + // Precedence for filter drivers vs driver is in the order of this array + struct driver_lookup lookup[3] = { + {"\0\0", SPDRP_SERVICE, "driver"}, + {"\0\0", SPDRP_UPPERFILTERS, "upper filter driver"}, + {"\0\0", SPDRP_LOWERFILTERS, "lower filter driver"} + }; + DWORD size, reg_type; + unsigned k, l; + int i, j; + + *api = USB_API_UNSUPPORTED; + *sub_api = SUB_API_NOTSET; + + // Check the service & filter names to know the API we should use + for (k = 0; k < 3; k++) { + if (pSetupDiGetDeviceRegistryPropertyA(*dev_info, dev_info_data, lookup[k].reg_prop, + ®_type, (BYTE *)lookup[k].list, MAX_KEY_LENGTH, &size)) { + // Turn the REG_SZ SPDRP_SERVICE into REG_MULTI_SZ + if (lookup[k].reg_prop == SPDRP_SERVICE) + // our buffers are MAX_KEY_LENGTH + 1 so we can overflow if needed + lookup[k].list[safe_strlen(lookup[k].list) + 1] = 0; + + // MULTI_SZ is a pain to work with. Turn it into something much more manageable + // NB: none of the driver names we check against contain LIST_SEPARATOR, + // (currently ';'), so even if an unsuported one does, it's not an issue + for (l = 0; (lookup[k].list[l] != 0) || (lookup[k].list[l + 1] != 0); l++) { + if (lookup[k].list[l] == 0) + lookup[k].list[l] = LIST_SEPARATOR; + } + usbi_dbg("%s(s): %s", lookup[k].designation, lookup[k].list); + } else { + if (GetLastError() != ERROR_INVALID_DATA) + usbi_dbg("could not access %s: %s", lookup[k].designation, windows_error_str(0)); + lookup[k].list[0] = 0; + } + } + + for (i = 1; i < USB_API_MAX; i++) { + for (k = 0; k < 3; k++) { + j = get_sub_api(lookup[k].list, i); + if (j >= 0) { + usbi_dbg("matched %s name against %s", lookup[k].designation, + (i != USB_API_WINUSBX) ? usb_api_backend[i].designation : sub_api_name[j]); + *api = i; + *sub_api = j; + return; + } + } + } +} + +static int set_composite_interface(struct libusb_context *ctx, struct libusb_device *dev, + char *dev_interface_path, char *device_id, int api, int sub_api) +{ + unsigned i; + struct windows_device_priv *priv = _device_priv(dev); + int interface_number; + + if (priv->apib->id != USB_API_COMPOSITE) { + usbi_err(ctx, "program assertion failed: '%s' is not composite", device_id); + return LIBUSB_ERROR_NO_DEVICE; + } + + // Because MI_## are not necessarily in sequential order (some composite + // devices will have only MI_00 & MI_03 for instance), we retrieve the actual + // interface number from the path's MI value + interface_number = 0; + for (i = 0; device_id[i] != 0; ) { + if ((device_id[i++] == 'M') && (device_id[i++] == 'I') + && (device_id[i++] == '_')) { + interface_number = (device_id[i++] - '0') * 10; + interface_number += device_id[i] - '0'; + break; + } + } + + if (device_id[i] == 0) + usbi_warn(ctx, "failure to read interface number for %s. Using default value %d", + device_id, interface_number); + + if (priv->usb_interface[interface_number].path != NULL) { + if (api == USB_API_HID) { + // HID devices can have multiple collections (COL##) for each MI_## interface + usbi_dbg("interface[%d] already set - ignoring HID collection: %s", + interface_number, device_id); + return LIBUSB_ERROR_ACCESS; + } + // In other cases, just use the latest data + safe_free(priv->usb_interface[interface_number].path); + } + + usbi_dbg("interface[%d] = %s", interface_number, dev_interface_path); + priv->usb_interface[interface_number].path = dev_interface_path; + priv->usb_interface[interface_number].apib = &usb_api_backend[api]; + priv->usb_interface[interface_number].sub_api = sub_api; + if ((api == USB_API_HID) && (priv->hid == NULL)) { + priv->hid = calloc(1, sizeof(struct hid_device_priv)); + if (priv->hid == NULL) + return LIBUSB_ERROR_NO_MEM; + } + + return LIBUSB_SUCCESS; +} + +static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *dev, + char *dev_interface_path) +{ + int i; + struct windows_device_priv *priv = _device_priv(dev); + + if (priv->hid == NULL) { + usbi_err(ctx, "program assertion failed: parent is not HID"); + return LIBUSB_ERROR_NO_DEVICE; + } else if (priv->hid->nb_interfaces == USB_MAXINTERFACES) { + usbi_err(ctx, "program assertion failed: max USB interfaces reached for HID device"); + return LIBUSB_ERROR_NO_DEVICE; + } + + for (i = 0; i < priv->hid->nb_interfaces; i++) { + if (safe_strcmp(priv->usb_interface[i].path, dev_interface_path) == 0) { + usbi_dbg("interface[%d] already set to %s", i, dev_interface_path); + return LIBUSB_ERROR_ACCESS; + } + } + + priv->usb_interface[priv->hid->nb_interfaces].path = dev_interface_path; + priv->usb_interface[priv->hid->nb_interfaces].apib = &usb_api_backend[USB_API_HID]; + usbi_dbg("interface[%u] = %s", priv->hid->nb_interfaces, dev_interface_path); + priv->hid->nb_interfaces++; + return LIBUSB_SUCCESS; +} + +/* + * get_device_list: libusb backend device enumeration function + */ +static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs) +{ + struct discovered_devs *discdevs; + HDEVINFO dev_info = { 0 }; + const char *usb_class[] = {"USB", "NUSB3", "IUSB3", "IARUSB3"}; + SP_DEVINFO_DATA dev_info_data = { 0 }; + SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL; + GUID hid_guid; +#define MAX_ENUM_GUIDS 64 + const GUID *guid[MAX_ENUM_GUIDS]; +#define HCD_PASS 0 +#define HUB_PASS 1 +#define GEN_PASS 2 +#define DEV_PASS 3 +#define HID_PASS 4 + int r = LIBUSB_SUCCESS; + int api, sub_api; + size_t class_index = 0; + unsigned int nb_guids, pass, i, j, ancestor; + char path[MAX_PATH_LENGTH]; + char strbuf[MAX_PATH_LENGTH]; + struct libusb_device *dev, *parent_dev; + struct windows_device_priv *priv, *parent_priv; + char *dev_interface_path = NULL; + char *dev_id_path = NULL; + unsigned long session_id; + DWORD size, reg_type, port_nr, install_state; + HKEY key; + WCHAR guid_string_w[MAX_GUID_STRING_LENGTH]; + GUID *if_guid; + LONG s; + // Keep a list of newly allocated devs to unref + libusb_device **unref_list, **new_unref_list; + unsigned int unref_size = 64; + unsigned int unref_cur = 0; + + // PASS 1 : (re)enumerate HCDs (allows for HCD hotplug) + // PASS 2 : (re)enumerate HUBS + // PASS 3 : (re)enumerate generic USB devices (including driverless) + // and list additional USB device interface GUIDs to explore + // PASS 4 : (re)enumerate master USB devices that have a device interface + // PASS 5+: (re)enumerate device interfaced GUIDs (including HID) and + // set the device interfaces. + + // Init the GUID table + guid[HCD_PASS] = &GUID_DEVINTERFACE_USB_HOST_CONTROLLER; + guid[HUB_PASS] = &GUID_DEVINTERFACE_USB_HUB; + guid[GEN_PASS] = NULL; + guid[DEV_PASS] = &GUID_DEVINTERFACE_USB_DEVICE; + HidD_GetHidGuid(&hid_guid); + guid[HID_PASS] = &hid_guid; + nb_guids = HID_PASS + 1; + + unref_list = calloc(unref_size, sizeof(libusb_device *)); + if (unref_list == NULL) + return LIBUSB_ERROR_NO_MEM; + + for (pass = 0; ((pass < nb_guids) && (r == LIBUSB_SUCCESS)); pass++) { +//#define ENUM_DEBUG +#if defined(ENABLE_LOGGING) && defined(ENUM_DEBUG) + const char *passname[] = { "HCD", "HUB", "GEN", "DEV", "HID", "EXT" }; + usbi_dbg("#### PROCESSING %ss %s", passname[(pass <= HID_PASS) ? pass : (HID_PASS + 1)], + (pass != GEN_PASS) ? guid_to_string(guid[pass]) : ""); +#endif + for (i = 0; ; i++) { + // safe loop: free up any (unprotected) dynamic resource + // NB: this is always executed before breaking the loop + safe_free(dev_interface_details); + safe_free(dev_interface_path); + safe_free(dev_id_path); + priv = parent_priv = NULL; + dev = parent_dev = NULL; + + // Safe loop: end of loop conditions + if (r != LIBUSB_SUCCESS) + break; + + if ((pass == HCD_PASS) && (i == UINT8_MAX)) { + usbi_warn(ctx, "program assertion failed - found more than %d buses, skipping the rest.", UINT8_MAX); + break; + } + + if (pass != GEN_PASS) { + // Except for GEN, all passes deal with device interfaces + dev_interface_details = get_interface_details(ctx, &dev_info, &dev_info_data, guid[pass], i); + if (dev_interface_details == NULL) + break; + + dev_interface_path = sanitize_path(dev_interface_details->DevicePath); + if (dev_interface_path == NULL) { + usbi_warn(ctx, "could not sanitize device interface path for '%s'", dev_interface_details->DevicePath); + continue; + } + } else { + // Workaround for a Nec/Renesas USB 3.0 driver bug where root hubs are + // being listed under the "NUSB3" PnP Symbolic Name rather than "USB". + // The Intel USB 3.0 driver behaves similar, but uses "IUSB3" + // The Intel Alpine Ridge USB 3.1 driver uses "IARUSB3" + for (; class_index < ARRAYSIZE(usb_class); class_index++) { + if (get_devinfo_data(ctx, &dev_info, &dev_info_data, usb_class[class_index], i)) + break; + i = 0; + } + if (class_index >= ARRAYSIZE(usb_class)) + break; + } + + // Read the Device ID path. This is what we'll use as UID + // Note that if the device is plugged in a different port or hub, the Device ID changes + if (CM_Get_Device_IDA(dev_info_data.DevInst, path, sizeof(path), 0) != CR_SUCCESS) { + usbi_warn(ctx, "could not read the device id path for devinst %X, skipping", + (unsigned int)dev_info_data.DevInst); + continue; + } + + dev_id_path = sanitize_path(path); + if (dev_id_path == NULL) { + usbi_warn(ctx, "could not sanitize device id path for devinst %X, skipping", + (unsigned int)dev_info_data.DevInst); + continue; + } +#ifdef ENUM_DEBUG + usbi_dbg("PRO: %s", dev_id_path); +#endif + + // The SPDRP_ADDRESS for USB devices is the device port number on the hub + port_nr = 0; + if ((pass >= HUB_PASS) && (pass <= GEN_PASS)) { + if ((!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_ADDRESS, + ®_type, (BYTE *)&port_nr, 4, &size)) || (size != 4)) { + usbi_warn(ctx, "could not retrieve port number for device '%s', skipping: %s", + dev_id_path, windows_error_str(0)); + continue; + } + } + + // Set API to use or get additional data from generic pass + api = USB_API_UNSUPPORTED; + sub_api = SUB_API_NOTSET; + switch (pass) { + case HCD_PASS: + break; + case GEN_PASS: + // We use the GEN pass to detect driverless devices... + size = sizeof(strbuf); + if (!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_DRIVER, + ®_type, (BYTE *)strbuf, size, &size)) { + usbi_info(ctx, "The following device has no driver: '%s'", dev_id_path); + usbi_info(ctx, "libusb will not be able to access it."); + } + // ...and to add the additional device interface GUIDs + key = pSetupDiOpenDevRegKey(dev_info, &dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); + if (key != INVALID_HANDLE_VALUE) { + size = sizeof(guid_string_w); + s = pRegQueryValueExW(key, L"DeviceInterfaceGUIDs", NULL, ®_type, + (BYTE *)guid_string_w, &size); + pRegCloseKey(key); + if (s == ERROR_SUCCESS) { + if (nb_guids >= MAX_ENUM_GUIDS) { + // If this assert is ever reported, grow a GUID table dynamically + usbi_err(ctx, "program assertion failed: too many GUIDs"); + LOOP_BREAK(LIBUSB_ERROR_OVERFLOW); + } + if_guid = calloc(1, sizeof(GUID)); + if (if_guid == NULL) { + usbi_err(ctx, "could not calloc for if_guid: not enough memory"); + LOOP_BREAK(LIBUSB_ERROR_NO_MEM); + } + pCLSIDFromString(guid_string_w, if_guid); + guid[nb_guids++] = if_guid; + usbi_dbg("extra GUID: %s", guid_to_string(if_guid)); + } + } + break; + case HID_PASS: + api = USB_API_HID; + break; + default: + // Get the API type (after checking that the driver installation is OK) + if ((!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_INSTALL_STATE, + ®_type, (BYTE *)&install_state, 4, &size)) || (size != 4)) { + usbi_warn(ctx, "could not detect installation state of driver for '%s': %s", + dev_id_path, windows_error_str(0)); + } else if (install_state != 0) { + usbi_warn(ctx, "driver for device '%s' is reporting an issue (code: %u) - skipping", + dev_id_path, (unsigned int)install_state); + continue; + } + get_api_type(ctx, &dev_info, &dev_info_data, &api, &sub_api); + break; + } + + // Find parent device (for the passes that need it) + switch (pass) { + case HCD_PASS: + case DEV_PASS: + case HUB_PASS: + break; + default: + // Go through the ancestors until we see a face we recognize + parent_dev = NULL; + for (ancestor = 1; parent_dev == NULL; ancestor++) { + session_id = get_ancestor_session_id(dev_info_data.DevInst, ancestor); + if (session_id == 0) + break; + + parent_dev = usbi_get_device_by_session_id(ctx, session_id); + } + + if (parent_dev == NULL) { + usbi_dbg("unlisted ancestor for '%s' (non USB HID, newly connected, etc.) - ignoring", dev_id_path); + continue; + } + + parent_priv = _device_priv(parent_dev); + // virtual USB devices are also listed during GEN - don't process these yet + if ((pass == GEN_PASS) && (parent_priv->apib->id != USB_API_HUB)) { + libusb_unref_device(parent_dev); + continue; + } + + break; + } + + // Create new or match existing device, using the (hashed) device_id as session id + if (pass <= DEV_PASS) { // For subsequent passes, we'll lookup the parent + // These are the passes that create "new" devices + session_id = htab_hash(dev_id_path); + dev = usbi_get_device_by_session_id(ctx, session_id); + if (dev == NULL) { + if (pass == DEV_PASS) { + // This can occur if the OS only reports a newly plugged device after we started enum + usbi_warn(ctx, "'%s' was only detected in late pass (newly connected device?)" + " - ignoring", dev_id_path); + continue; + } + + usbi_dbg("allocating new device for session [%lX]", session_id); + dev = usbi_alloc_device(ctx, session_id); + if (dev == NULL) + LOOP_BREAK(LIBUSB_ERROR_NO_MEM); + + priv = windows_device_priv_init(dev); + } else { + usbi_dbg("found existing device for session [%lX] (%u.%u)", + session_id, dev->bus_number, dev->device_address); + + priv = _device_priv(dev); + if ((parent_dev != NULL) && (dev->parent_dev != NULL)) { + if (dev->parent_dev != parent_dev) { + // It is possible for the actual parent device to not have existed at the + // time of enumeration, so the currently assigned parent may in fact be a + // grandparent. If the devices differ, we assume the "new" parent device + // is in fact closer to the device. + usbi_dbg("updating parent device [session %lX -> %lX]", + dev->parent_dev->session_data, parent_dev->session_data); + libusb_unref_device(dev->parent_dev); + dev->parent_dev = parent_dev; + } else { + // We hold a reference to parent_dev instance, but this device already + // has a parent_dev reference (only one per child) + libusb_unref_device(parent_dev); + } + } + } + + // Keep track of devices that need unref + unref_list[unref_cur++] = dev; + if (unref_cur >= unref_size) { + unref_size += 64; + new_unref_list = usbi_reallocf(unref_list, unref_size * sizeof(libusb_device *)); + if (new_unref_list == NULL) { + usbi_err(ctx, "could not realloc list for unref - aborting."); + LOOP_BREAK(LIBUSB_ERROR_NO_MEM); + } else { + unref_list = new_unref_list; + } + } + } + + // Setup device + switch (pass) { + case HCD_PASS: + // If the hcd has already been setup, don't do it again + if (priv->path != NULL) + break; + dev->bus_number = (uint8_t)(i + 1); // bus 0 is reserved for disconnected + dev->device_address = 0; + dev->num_configurations = 0; + priv->apib = &usb_api_backend[USB_API_HUB]; + priv->sub_api = SUB_API_NOTSET; + priv->depth = UINT8_MAX; // Overflow to 0 for HCD Hubs + priv->path = dev_interface_path; + dev_interface_path = NULL; + break; + case HUB_PASS: + case DEV_PASS: + // If the device has already been setup, don't do it again + if (priv->path != NULL) + break; + // Take care of API initialization + priv->path = dev_interface_path; + dev_interface_path = NULL; + priv->apib = &usb_api_backend[api]; + priv->sub_api = sub_api; + switch(api) { + case USB_API_COMPOSITE: + case USB_API_HUB: + break; + case USB_API_HID: + priv->hid = calloc(1, sizeof(struct hid_device_priv)); + if (priv->hid == NULL) + LOOP_BREAK(LIBUSB_ERROR_NO_MEM); + + priv->hid->nb_interfaces = 0; + break; + default: + // For other devices, the first interface is the same as the device + priv->usb_interface[0].path = _strdup(priv->path); + if (priv->usb_interface[0].path == NULL) + usbi_warn(ctx, "could not duplicate interface path '%s'", priv->path); + // The following is needed if we want API calls to work for both simple + // and composite devices. + for(j = 0; j < USB_MAXINTERFACES; j++) + priv->usb_interface[j].apib = &usb_api_backend[api]; + + break; + } + break; + case GEN_PASS: + r = init_device(dev, parent_dev, (uint8_t)port_nr, dev_id_path, dev_info_data.DevInst); + if (r == LIBUSB_SUCCESS) { + // Append device to the list of discovered devices + discdevs = discovered_devs_append(*_discdevs, dev); + if (!discdevs) + LOOP_BREAK(LIBUSB_ERROR_NO_MEM); + + *_discdevs = discdevs; + } else if (r == LIBUSB_ERROR_NO_DEVICE) { + // This can occur if the device was disconnected but Windows hasn't + // refreshed its enumeration yet - in that case, we ignore the device + r = LIBUSB_SUCCESS; + } + break; + default: // HID_PASS and later + if (parent_priv->apib->id == USB_API_HID || parent_priv->apib->id == USB_API_COMPOSITE) { + if (parent_priv->apib->id == USB_API_HID) { + usbi_dbg("setting HID interface for [%lX]:", parent_dev->session_data); + r = set_hid_interface(ctx, parent_dev, dev_interface_path); + } else { + usbi_dbg("setting composite interface for [%lX]:", parent_dev->session_data); + r = set_composite_interface(ctx, parent_dev, dev_interface_path, dev_id_path, api, sub_api); + } + switch (r) { + case LIBUSB_SUCCESS: + dev_interface_path = NULL; + break; + case LIBUSB_ERROR_ACCESS: + // interface has already been set => make sure dev_interface_path is freed then + r = LIBUSB_SUCCESS; + break; + default: + LOOP_BREAK(r); + break; + } + } + libusb_unref_device(parent_dev); + break; + } + } + } + + // Free any additional GUIDs + for (pass = HID_PASS + 1; pass < nb_guids; pass++) + safe_free(guid[pass]); + + // Unref newly allocated devs + for (i = 0; i < unref_cur; i++) + safe_unref_device(unref_list[i]); + free(unref_list); + + return r; +} + +/* + * exit: libusb backend deinitialization function + */ +static void windows_exit(void) +{ + int i; + HANDLE semaphore; + char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0' + + sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF)); + semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name); + if (semaphore == NULL) + return; + + // A successful wait brings our semaphore count to 0 (unsignaled) + // => any concurent wait stalls until the semaphore release + if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) { + CloseHandle(semaphore); + return; + } + + // Only works if exits and inits are balanced exactly + if (--concurrent_usage < 0) { // Last exit + for (i = 0; i < USB_API_MAX; i++) + usb_api_backend[i].exit(SUB_API_NOTSET); + exit_dlls(); + exit_polling(); + windows_common_exit(); + usbi_mutex_destroy(&autoclaim_lock); + } + + ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1 + CloseHandle(semaphore); +} + +static int windows_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian) +{ + struct windows_device_priv *priv = _device_priv(dev); + + memcpy(buffer, &priv->dev_descriptor, DEVICE_DESC_LENGTH); + *host_endian = 0; + + return LIBUSB_SUCCESS; +} + +static int windows_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) +{ + struct windows_device_priv *priv = _device_priv(dev); + PUSB_CONFIGURATION_DESCRIPTOR config_header; + size_t size; + + // config index is zero based + if (config_index >= dev->num_configurations) + return LIBUSB_ERROR_INVALID_PARAM; + + if ((priv->config_descriptor == NULL) || (priv->config_descriptor[config_index] == NULL)) + return LIBUSB_ERROR_NOT_FOUND; + + config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptor[config_index]; + + size = MIN(config_header->wTotalLength, len); + memcpy(buffer, priv->config_descriptor[config_index], size); + *host_endian = 0; + + return (int)size; +} + +static int windows_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue, + unsigned char **buffer, int *host_endian) +{ + struct windows_device_priv *priv = _device_priv(dev); + PUSB_CONFIGURATION_DESCRIPTOR config_header; + uint8_t index; + + *buffer = NULL; + *host_endian = 0; + + if (priv->config_descriptor == NULL) + return LIBUSB_ERROR_NOT_FOUND; + + for (index = 0; index < dev->num_configurations; index++) { + config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptor[index]; + if (config_header->bConfigurationValue == bConfigurationValue) { + *buffer = priv->config_descriptor[index]; + return (int)config_header->wTotalLength; + } + } + + return LIBUSB_ERROR_NOT_FOUND; +} + +/* + * return the cached copy of the active config descriptor + */ +static int windows_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian) +{ + struct windows_device_priv *priv = _device_priv(dev); + unsigned char *config_desc; + int r; + + if (priv->active_config == 0) + return LIBUSB_ERROR_NOT_FOUND; + + r = windows_get_config_descriptor_by_value(dev, priv->active_config, &config_desc, host_endian); + if (r < 0) + return r; + + len = MIN((size_t)r, len); + memcpy(buffer, config_desc, len); + return (int)len; +} + +static int windows_open(struct libusb_device_handle *dev_handle) +{ + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + + if (priv->apib == NULL) { + usbi_err(ctx, "program assertion failed - device is not initialized"); + return LIBUSB_ERROR_NO_DEVICE; + } + + return priv->apib->open(SUB_API_NOTSET, dev_handle); +} + +static void windows_close(struct libusb_device_handle *dev_handle) +{ + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + + priv->apib->close(SUB_API_NOTSET, dev_handle); +} + +static int windows_get_configuration(struct libusb_device_handle *dev_handle, int *config) +{ + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + + if (priv->active_config == 0) { + *config = 0; + return LIBUSB_ERROR_NOT_FOUND; + } + + *config = priv->active_config; + return LIBUSB_SUCCESS; +} + +/* + * from http://msdn.microsoft.com/en-us/library/ms793522.aspx: "The port driver + * does not currently expose a service that allows higher-level drivers to set + * the configuration." + */ +static int windows_set_configuration(struct libusb_device_handle *dev_handle, int config) +{ + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + int r = LIBUSB_SUCCESS; + + if (config >= USB_MAXCONFIG) + return LIBUSB_ERROR_INVALID_PARAM; + + r = libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_OUT | + LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, + LIBUSB_REQUEST_SET_CONFIGURATION, (uint16_t)config, + 0, NULL, 0, 1000); + + if (r == LIBUSB_SUCCESS) + priv->active_config = (uint8_t)config; + + return r; +} + +static int windows_claim_interface(struct libusb_device_handle *dev_handle, int iface) +{ + int r = LIBUSB_SUCCESS; + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + + safe_free(priv->usb_interface[iface].endpoint); + priv->usb_interface[iface].nb_endpoints = 0; + + r = priv->apib->claim_interface(SUB_API_NOTSET, dev_handle, iface); + + if (r == LIBUSB_SUCCESS) + r = windows_assign_endpoints(dev_handle, iface, 0); + + return r; +} + +static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) +{ + int r = LIBUSB_SUCCESS; + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + + safe_free(priv->usb_interface[iface].endpoint); + priv->usb_interface[iface].nb_endpoints = 0; + + r = priv->apib->set_interface_altsetting(SUB_API_NOTSET, dev_handle, iface, altsetting); + + if (r == LIBUSB_SUCCESS) + r = windows_assign_endpoints(dev_handle, iface, altsetting); + + return r; +} + +static int windows_release_interface(struct libusb_device_handle *dev_handle, int iface) +{ + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + + return priv->apib->release_interface(SUB_API_NOTSET, dev_handle, iface); +} + +static int windows_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) +{ + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + return priv->apib->clear_halt(SUB_API_NOTSET, dev_handle, endpoint); +} + +static int windows_reset_device(struct libusb_device_handle *dev_handle) +{ + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + return priv->apib->reset_device(SUB_API_NOTSET, dev_handle); +} + +// The 3 functions below are unlikely to ever get supported on Windows +static int windows_kernel_driver_active(struct libusb_device_handle *dev_handle, int iface) +{ + return LIBUSB_ERROR_NOT_SUPPORTED; +} + +static int windows_attach_kernel_driver(struct libusb_device_handle *dev_handle, int iface) +{ + return LIBUSB_ERROR_NOT_SUPPORTED; +} + +static int windows_detach_kernel_driver(struct libusb_device_handle *dev_handle, int iface) +{ + return LIBUSB_ERROR_NOT_SUPPORTED; +} + +static void windows_destroy_device(struct libusb_device *dev) +{ + windows_device_priv_release(dev); +} + +void windows_clear_transfer_priv(struct usbi_transfer *itransfer) +{ + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + + usbi_free_fd(&transfer_priv->pollable_fd); + safe_free(transfer_priv->hid_buffer); + // When auto claim is in use, attempt to release the auto-claimed interface + auto_release(itransfer); +} + +static int submit_bulk_transfer(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 windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + int r; + + r = priv->apib->submit_bulk_transfer(SUB_API_NOTSET, itransfer); + if (r != LIBUSB_SUCCESS) + return r; + + usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, + (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT)); + + return LIBUSB_SUCCESS; +} + +static int submit_iso_transfer(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 windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + int r; + + r = priv->apib->submit_iso_transfer(SUB_API_NOTSET, itransfer); + if (r != LIBUSB_SUCCESS) + return r; + + usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, + (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT)); + + return LIBUSB_SUCCESS; +} + +static int submit_control_transfer(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 windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + int r; + + r = priv->apib->submit_control_transfer(SUB_API_NOTSET, itransfer); + if (r != LIBUSB_SUCCESS) + return r; + + usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN); + + return LIBUSB_SUCCESS; +} + +static int windows_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 submit_control_transfer(itransfer); + case LIBUSB_TRANSFER_TYPE_BULK: + case LIBUSB_TRANSFER_TYPE_INTERRUPT: + if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET)) + return LIBUSB_ERROR_NOT_SUPPORTED; + return submit_bulk_transfer(itransfer); + case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: + return submit_iso_transfer(itransfer); + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: + return LIBUSB_ERROR_NOT_SUPPORTED; + default: + usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); + return LIBUSB_ERROR_INVALID_PARAM; + } +} + +static int windows_abort_control(struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + + return priv->apib->abort_control(SUB_API_NOTSET, itransfer); +} + +static int windows_abort_transfers(struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + + return priv->apib->abort_transfers(SUB_API_NOTSET, itransfer); +} + +static int windows_cancel_transfer(struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + + switch (transfer->type) { + case LIBUSB_TRANSFER_TYPE_CONTROL: + return windows_abort_control(itransfer); + case LIBUSB_TRANSFER_TYPE_BULK: + case LIBUSB_TRANSFER_TYPE_INTERRUPT: + case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: + return windows_abort_transfers(itransfer); + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: + return LIBUSB_ERROR_NOT_SUPPORTED; + default: + usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); + return LIBUSB_ERROR_INVALID_PARAM; + } +} + +int windows_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); + return priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, io_size); +} + +struct winfd *windows_get_fd(struct usbi_transfer *transfer) +{ + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(transfer); + return &transfer_priv->pollable_fd; +} + +void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size) +{ + if (HasOverlappedIoCompletedSync(pollable_fd->overlapped)) { + *io_result = NO_ERROR; + *io_size = (DWORD)pollable_fd->overlapped->InternalHigh; + } + else if (GetOverlappedResult(pollable_fd->handle, pollable_fd->overlapped, io_size, false)) { + // Regular async overlapped + *io_result = NO_ERROR; + } + else { + *io_result = GetLastError(); + } +} + +// NB: MSVC6 does not support named initializers. +const struct usbi_os_backend windows_backend = { + "Windows", + USBI_CAP_HAS_HID_ACCESS, + windows_init, + windows_exit, + + windows_get_device_list, + NULL, /* hotplug_poll */ + windows_open, + windows_close, + + windows_get_device_descriptor, + windows_get_active_config_descriptor, + windows_get_config_descriptor, + windows_get_config_descriptor_by_value, + + windows_get_configuration, + windows_set_configuration, + windows_claim_interface, + windows_release_interface, + + windows_set_interface_altsetting, + windows_clear_halt, + windows_reset_device, + + NULL, /* alloc_streams */ + NULL, /* free_streams */ + + NULL, /* dev_mem_alloc */ + NULL, /* dev_mem_free */ + + windows_kernel_driver_active, + windows_detach_kernel_driver, + windows_attach_kernel_driver, + + windows_destroy_device, + + windows_submit_transfer, + windows_cancel_transfer, + windows_clear_transfer_priv, + + windows_handle_events, + NULL, + + windows_clock_gettime, +#if defined(USBI_TIMERFD_AVAILABLE) + NULL, +#endif + sizeof(struct windows_device_priv), + sizeof(struct windows_device_handle_priv), + sizeof(struct windows_transfer_priv), +}; + + +/* + * USB API backends + */ +static int unsupported_init(int sub_api, struct libusb_context *ctx) +{ + return LIBUSB_SUCCESS; +} + +static int unsupported_exit(int sub_api) +{ + return LIBUSB_SUCCESS; +} + +static int unsupported_open(int sub_api, struct libusb_device_handle *dev_handle) +{ + PRINT_UNSUPPORTED_API(open); +} + +static void unsupported_close(int sub_api, struct libusb_device_handle *dev_handle) +{ + usbi_dbg("unsupported API call for 'close'"); +} + +static int unsupported_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface) +{ + PRINT_UNSUPPORTED_API(configure_endpoints); +} + +static int unsupported_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) +{ + PRINT_UNSUPPORTED_API(claim_interface); +} + +static int unsupported_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting) +{ + PRINT_UNSUPPORTED_API(set_interface_altsetting); +} + +static int unsupported_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) +{ + PRINT_UNSUPPORTED_API(release_interface); +} + +static int unsupported_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) +{ + PRINT_UNSUPPORTED_API(clear_halt); +} + +static int unsupported_reset_device(int sub_api, struct libusb_device_handle *dev_handle) +{ + PRINT_UNSUPPORTED_API(reset_device); +} + +static int unsupported_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) +{ + PRINT_UNSUPPORTED_API(submit_bulk_transfer); +} + +static int unsupported_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer) +{ + PRINT_UNSUPPORTED_API(submit_iso_transfer); +} + +static int unsupported_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer) +{ + PRINT_UNSUPPORTED_API(submit_control_transfer); +} + +static int unsupported_abort_control(int sub_api, struct usbi_transfer *itransfer) +{ + PRINT_UNSUPPORTED_API(abort_control); +} + +static int unsupported_abort_transfers(int sub_api, struct usbi_transfer *itransfer) +{ + PRINT_UNSUPPORTED_API(abort_transfers); +} + +static int unsupported_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) +{ + PRINT_UNSUPPORTED_API(copy_transfer_data); +} + +static int common_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface) +{ + return LIBUSB_SUCCESS; +} + +// These names must be uppercase +static const char *hub_driver_names[] = {"USBHUB", "USBHUB3", "USB3HUB", "NUSB3HUB", "RUSB3HUB", "FLXHCIH", "TIHUB3", "ETRONHUB3", "VIAHUB3", "ASMTHUB3", "IUSB3HUB", "VUSB3HUB", "AMDHUB30", "VHHUB", "AUSB3HUB"}; +static const char *composite_driver_names[] = {"USBCCGP"}; +static const char *winusbx_driver_names[] = WINUSBX_DRV_NAMES; +static const char *hid_driver_names[] = {"HIDUSB", "MOUHID", "KBDHID"}; +const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { + { + USB_API_UNSUPPORTED, + "Unsupported API", + NULL, + 0, + unsupported_init, + unsupported_exit, + unsupported_open, + unsupported_close, + unsupported_configure_endpoints, + unsupported_claim_interface, + unsupported_set_interface_altsetting, + unsupported_release_interface, + unsupported_clear_halt, + unsupported_reset_device, + unsupported_submit_bulk_transfer, + unsupported_submit_iso_transfer, + unsupported_submit_control_transfer, + unsupported_abort_control, + unsupported_abort_transfers, + unsupported_copy_transfer_data, + }, + { + USB_API_HUB, + "HUB API", + hub_driver_names, + ARRAYSIZE(hub_driver_names), + unsupported_init, + unsupported_exit, + unsupported_open, + unsupported_close, + unsupported_configure_endpoints, + unsupported_claim_interface, + unsupported_set_interface_altsetting, + unsupported_release_interface, + unsupported_clear_halt, + unsupported_reset_device, + unsupported_submit_bulk_transfer, + unsupported_submit_iso_transfer, + unsupported_submit_control_transfer, + unsupported_abort_control, + unsupported_abort_transfers, + unsupported_copy_transfer_data, + }, + { + USB_API_COMPOSITE, + "Composite API", + composite_driver_names, + ARRAYSIZE(composite_driver_names), + composite_init, + composite_exit, + composite_open, + composite_close, + common_configure_endpoints, + composite_claim_interface, + composite_set_interface_altsetting, + composite_release_interface, + composite_clear_halt, + composite_reset_device, + composite_submit_bulk_transfer, + composite_submit_iso_transfer, + composite_submit_control_transfer, + composite_abort_control, + composite_abort_transfers, + composite_copy_transfer_data, + }, + { + USB_API_WINUSBX, + "WinUSB-like APIs", + winusbx_driver_names, + ARRAYSIZE(winusbx_driver_names), + winusbx_init, + winusbx_exit, + winusbx_open, + winusbx_close, + winusbx_configure_endpoints, + winusbx_claim_interface, + winusbx_set_interface_altsetting, + winusbx_release_interface, + winusbx_clear_halt, + winusbx_reset_device, + winusbx_submit_bulk_transfer, + unsupported_submit_iso_transfer, + winusbx_submit_control_transfer, + winusbx_abort_control, + winusbx_abort_transfers, + winusbx_copy_transfer_data, + }, + { + USB_API_HID, + "HID API", + hid_driver_names, + ARRAYSIZE(hid_driver_names), + hid_init, + hid_exit, + hid_open, + hid_close, + common_configure_endpoints, + hid_claim_interface, + hid_set_interface_altsetting, + hid_release_interface, + hid_clear_halt, + hid_reset_device, + hid_submit_bulk_transfer, + unsupported_submit_iso_transfer, + hid_submit_control_transfer, + hid_abort_transfers, + hid_abort_transfers, + hid_copy_transfer_data, + }, +}; + + +/* + * WinUSB-like (WinUSB, libusb0/libusbK through libusbk DLL) API functions + */ +#define WinUSBX_Set(fn) \ + do { \ + if (native_winusb) \ + WinUSBX[i].fn = (WinUsb_##fn##_t)GetProcAddress(h, "WinUsb_" #fn); \ + else \ + pLibK_GetProcAddress((PVOID *)&WinUSBX[i].fn, i, KUSB_FNID_##fn); \ + } while (0) + +static int winusbx_init(int sub_api, struct libusb_context *ctx) +{ + HMODULE h; + bool native_winusb; + int i; + KLIB_VERSION LibK_Version; + LibK_GetProcAddress_t pLibK_GetProcAddress = NULL; + LibK_GetVersion_t pLibK_GetVersion; + + h = LoadLibraryA("libusbK"); + + if (h == NULL) { + usbi_info(ctx, "libusbK DLL is not available, will use native WinUSB"); + h = LoadLibraryA("WinUSB"); + + if (h == NULL) { + usbi_warn(ctx, "WinUSB DLL is not available either, " + "you will not be able to access devices outside of enumeration"); + return LIBUSB_ERROR_NOT_FOUND; + } + } else { + usbi_dbg("using libusbK DLL for universal access"); + pLibK_GetVersion = (LibK_GetVersion_t)GetProcAddress(h, "LibK_GetVersion"); + if (pLibK_GetVersion != NULL) { + pLibK_GetVersion(&LibK_Version); + usbi_dbg("libusbK version: %d.%d.%d.%d", LibK_Version.Major, LibK_Version.Minor, + LibK_Version.Micro, LibK_Version.Nano); + } + pLibK_GetProcAddress = (LibK_GetProcAddress_t)GetProcAddress(h, "LibK_GetProcAddress"); + if (pLibK_GetProcAddress == NULL) { + usbi_err(ctx, "LibK_GetProcAddress() not found in libusbK DLL"); + FreeLibrary(h); + return LIBUSB_ERROR_NOT_FOUND; + } + } + + native_winusb = (pLibK_GetProcAddress == NULL); + for (i = SUB_API_LIBUSBK; i < SUB_API_MAX; i++) { + WinUSBX_Set(AbortPipe); + WinUSBX_Set(ControlTransfer); + WinUSBX_Set(FlushPipe); + WinUSBX_Set(Free); + WinUSBX_Set(GetAssociatedInterface); + WinUSBX_Set(GetCurrentAlternateSetting); + WinUSBX_Set(GetDescriptor); + WinUSBX_Set(GetOverlappedResult); + WinUSBX_Set(GetPipePolicy); + WinUSBX_Set(GetPowerPolicy); + WinUSBX_Set(Initialize); + WinUSBX_Set(QueryDeviceInformation); + WinUSBX_Set(QueryInterfaceSettings); + WinUSBX_Set(QueryPipe); + WinUSBX_Set(ReadPipe); + WinUSBX_Set(ResetPipe); + WinUSBX_Set(SetCurrentAlternateSetting); + WinUSBX_Set(SetPipePolicy); + WinUSBX_Set(SetPowerPolicy); + WinUSBX_Set(WritePipe); + if (!native_winusb) + WinUSBX_Set(ResetDevice); + + if (WinUSBX[i].Initialize != NULL) { + WinUSBX[i].initialized = true; + usbi_dbg("initalized sub API %s", sub_api_name[i]); + } else { + usbi_warn(ctx, "Failed to initalize sub API %s", sub_api_name[i]); + WinUSBX[i].initialized = false; + } + } + + WinUSBX_handle = h; + return LIBUSB_SUCCESS; +} + +static int winusbx_exit(int sub_api) +{ + if (WinUSBX_handle != NULL) { + FreeLibrary(WinUSBX_handle); + WinUSBX_handle = NULL; + + /* Reset the WinUSBX API structures */ + memset(&WinUSBX, 0, sizeof(WinUSBX)); + } + + return LIBUSB_SUCCESS; +} + +// NB: open and close must ensure that they only handle interface of +// the right API type, as these functions can be called wholesale from +// composite_open(), with interfaces belonging to different APIs +static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + + HANDLE file_handle; + int i; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + // WinUSB requires a separate handle for each interface + for (i = 0; i < USB_MAXINTERFACES; i++) { + if ((priv->usb_interface[i].path != NULL) + && (priv->usb_interface[i].apib->id == USB_API_WINUSBX)) { + file_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + if (file_handle == INVALID_HANDLE_VALUE) { + usbi_err(ctx, "could not open device %s (interface %d): %s", priv->usb_interface[i].path, i, windows_error_str(0)); + switch(GetLastError()) { + case ERROR_FILE_NOT_FOUND: // The device was disconnected + return LIBUSB_ERROR_NO_DEVICE; + case ERROR_ACCESS_DENIED: + return LIBUSB_ERROR_ACCESS; + default: + return LIBUSB_ERROR_IO; + } + } + handle_priv->interface_handle[i].dev_handle = file_handle; + } + } + + return LIBUSB_SUCCESS; +} + +static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle) +{ + struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + HANDLE handle; + int i; + + if (sub_api == SUB_API_NOTSET) + sub_api = priv->sub_api; + + if (!WinUSBX[sub_api].initialized) + return; + + if (priv->apib->id == USB_API_COMPOSITE) { + // If this is a composite device, just free and close all WinUSB-like + // interfaces directly (each is independent and not associated with another) + for (i = 0; i < USB_MAXINTERFACES; i++) { + if (priv->usb_interface[i].apib->id == USB_API_WINUSBX) { + handle = handle_priv->interface_handle[i].api_handle; + if (HANDLE_VALID(handle)) + WinUSBX[sub_api].Free(handle); + + handle = handle_priv->interface_handle[i].dev_handle; + if (HANDLE_VALID(handle)) + CloseHandle(handle); + } + } + } + else { + // If this is a WinUSB device, free all interfaces above interface 0, + // then free and close interface 0 last + for (i = 1; i < USB_MAXINTERFACES; i++) { + handle = handle_priv->interface_handle[i].api_handle; + if (HANDLE_VALID(handle)) + WinUSBX[sub_api].Free(handle); + } + handle = handle_priv->interface_handle[0].api_handle; + if (HANDLE_VALID(handle)) + WinUSBX[sub_api].Free(handle); + + handle = handle_priv->interface_handle[0].dev_handle; + if (HANDLE_VALID(handle)) + CloseHandle(handle); + } +} + +static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface) +{ + struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + HANDLE winusb_handle = handle_priv->interface_handle[iface].api_handle; + UCHAR policy; + ULONG timeout = 0; + uint8_t endpoint_address; + int i; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + // With handle and enpoints set (in parent), we can setup the default pipe properties + // see http://download.microsoft.com/download/D/1/D/D1DD7745-426B-4CC3-A269-ABBBE427C0EF/DVC-T705_DDC08.pptx + for (i = -1; i < priv->usb_interface[iface].nb_endpoints; i++) { + endpoint_address = (i == -1) ? 0 : priv->usb_interface[iface].endpoint[i]; + if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, + PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout)) + usbi_dbg("failed to set PIPE_TRANSFER_TIMEOUT for control endpoint %02X", endpoint_address); + + if ((i == -1) || (sub_api == SUB_API_LIBUSB0)) + continue; // Other policies don't apply to control endpoint or libusb0 + + policy = false; + if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, + SHORT_PACKET_TERMINATE, sizeof(UCHAR), &policy)) + usbi_dbg("failed to disable SHORT_PACKET_TERMINATE for endpoint %02X", endpoint_address); + + if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, + IGNORE_SHORT_PACKETS, sizeof(UCHAR), &policy)) + usbi_dbg("failed to disable IGNORE_SHORT_PACKETS for endpoint %02X", endpoint_address); + + policy = true; + /* ALLOW_PARTIAL_READS must be enabled due to likely libusbK bug. See: + https://sourceforge.net/mailarchive/message.php?msg_id=29736015 */ + if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, + ALLOW_PARTIAL_READS, sizeof(UCHAR), &policy)) + usbi_dbg("failed to enable ALLOW_PARTIAL_READS for endpoint %02X", endpoint_address); + + if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, + AUTO_CLEAR_STALL, sizeof(UCHAR), &policy)) + usbi_dbg("failed to enable AUTO_CLEAR_STALL for endpoint %02X", endpoint_address); + } + + return LIBUSB_SUCCESS; +} + +static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + bool is_using_usbccgp = (priv->apib->id == USB_API_COMPOSITE); + SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL; + HDEVINFO dev_info = INVALID_HANDLE_VALUE; + SP_DEVINFO_DATA dev_info_data; + char *dev_path_no_guid = NULL; + char filter_path[] = "\\\\.\\libusb0-0000"; + bool found_filter = false; + HANDLE file_handle, winusb_handle; + DWORD err; + int i; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + // If the device is composite, but using the default Windows composite parent driver (usbccgp) + // or if it's the first WinUSB-like interface, we get a handle through Initialize(). + if ((is_using_usbccgp) || (iface == 0)) { + // composite device (independent interfaces) or interface 0 + file_handle = handle_priv->interface_handle[iface].dev_handle; + if (!HANDLE_VALID(file_handle)) + return LIBUSB_ERROR_NOT_FOUND; + + if (!WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) { + handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; + err = GetLastError(); + switch(err) { + case ERROR_BAD_COMMAND: + // The device was disconnected + usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(0)); + return LIBUSB_ERROR_NO_DEVICE; + default: + // it may be that we're using the libusb0 filter driver. + // TODO: can we move this whole business into the K/0 DLL? + for (i = 0; ; i++) { + safe_free(dev_interface_details); + safe_free(dev_path_no_guid); + dev_interface_details = get_interface_details_filter(ctx, &dev_info, &dev_info_data, &GUID_DEVINTERFACE_LIBUSB0_FILTER, i, filter_path); + if ((found_filter) || (dev_interface_details == NULL)) + break; + + // ignore GUID part + dev_path_no_guid = sanitize_path(strtok(dev_interface_details->DevicePath, "{")); + if (safe_strncmp(dev_path_no_guid, priv->usb_interface[iface].path, safe_strlen(dev_path_no_guid)) == 0) { + file_handle = CreateFileA(filter_path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + if (file_handle == INVALID_HANDLE_VALUE) { + usbi_err(ctx, "could not open device %s: %s", filter_path, windows_error_str(0)); + } else { + WinUSBX[sub_api].Free(winusb_handle); + if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) + found_filter = true; + else + usbi_err(ctx, "could not initialize filter driver for %s", filter_path); + } + } + } + if (!found_filter) { + usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(err)); + return LIBUSB_ERROR_ACCESS; + } + } + } + handle_priv->interface_handle[iface].api_handle = winusb_handle; + } else { + // For all other interfaces, use GetAssociatedInterface() + winusb_handle = handle_priv->interface_handle[0].api_handle; + // It is a requirement for multiple interface devices on Windows that, to you + // must first claim the first interface before you claim the others + if (!HANDLE_VALID(winusb_handle)) { + file_handle = handle_priv->interface_handle[0].dev_handle; + if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) { + handle_priv->interface_handle[0].api_handle = winusb_handle; + usbi_warn(ctx, "auto-claimed interface 0 (required to claim %d with WinUSB)", iface); + } else { + usbi_warn(ctx, "failed to auto-claim interface 0 (required to claim %d with WinUSB): %s", iface, windows_error_str(0)); + return LIBUSB_ERROR_ACCESS; + } + } + if (!WinUSBX[sub_api].GetAssociatedInterface(winusb_handle, (UCHAR)(iface - 1), + &handle_priv->interface_handle[iface].api_handle)) { + handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; + switch(GetLastError()) { + case ERROR_NO_MORE_ITEMS: // invalid iface + return LIBUSB_ERROR_NOT_FOUND; + case ERROR_BAD_COMMAND: // The device was disconnected + return LIBUSB_ERROR_NO_DEVICE; + case ERROR_ALREADY_EXISTS: // already claimed + return LIBUSB_ERROR_BUSY; + default: + usbi_err(ctx, "could not claim interface %d: %s", iface, windows_error_str(0)); + return LIBUSB_ERROR_ACCESS; + } + } + } + usbi_dbg("claimed interface %d", iface); + handle_priv->active_interface = iface; + + return LIBUSB_SUCCESS; +} + +static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) +{ + struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + HANDLE winusb_handle; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + winusb_handle = handle_priv->interface_handle[iface].api_handle; + if (!HANDLE_VALID(winusb_handle)) + return LIBUSB_ERROR_NOT_FOUND; + + WinUSBX[sub_api].Free(winusb_handle); + handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; + + return LIBUSB_SUCCESS; +} + +/* + * Return the first valid interface (of the same API type), for control transfers + */ +static int get_valid_interface(struct libusb_device_handle *dev_handle, int api_id) +{ + struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + int i; + + if ((api_id < USB_API_WINUSBX) || (api_id > USB_API_HID)) { + usbi_dbg("unsupported API ID"); + return -1; + } + + for (i = 0; i < USB_MAXINTERFACES; i++) { + if (HANDLE_VALID(handle_priv->interface_handle[i].dev_handle) + && HANDLE_VALID(handle_priv->interface_handle[i].api_handle) + && (priv->usb_interface[i].apib->id == api_id)) + return i; + } + + return -1; +} + +/* + * Lookup interface by endpoint address. -1 if not found + */ +static int interface_by_endpoint(struct windows_device_priv *priv, + struct windows_device_handle_priv *handle_priv, uint8_t endpoint_address) +{ + int i, j; + + for (i = 0; i < USB_MAXINTERFACES; i++) { + if (!HANDLE_VALID(handle_priv->interface_handle[i].api_handle)) + continue; + if (priv->usb_interface[i].endpoint == NULL) + continue; + for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) { + if (priv->usb_interface[i].endpoint[j] == endpoint_address) + return i; + } + } + + return -1; +} + +static int winusbx_submit_control_transfer(int sub_api, 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 windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); + WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer; + ULONG size; + HANDLE winusb_handle; + int current_interface; + struct winfd wfd; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + transfer_priv->pollable_fd = INVALID_WINFD; + size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE; + + // Windows places upper limits on the control transfer size + // See: https://msdn.microsoft.com/en-us/library/windows/hardware/ff538112.aspx + if (size > MAX_CTRL_BUFFER_LENGTH) + return LIBUSB_ERROR_INVALID_PARAM; + + current_interface = get_valid_interface(transfer->dev_handle, USB_API_WINUSBX); + if (current_interface < 0) { + if (auto_claim(transfer, ¤t_interface, USB_API_WINUSBX) != LIBUSB_SUCCESS) + return LIBUSB_ERROR_NOT_FOUND; + } + + usbi_dbg("will use interface %d", current_interface); + winusb_handle = handle_priv->interface_handle[current_interface].api_handle; + + wfd = usbi_create_fd(winusb_handle, RW_READ, NULL, NULL); + // Always use the handle returned from usbi_create_fd (wfd.handle) + if (wfd.fd < 0) + return LIBUSB_ERROR_NO_MEM; + + // Sending of set configuration control requests from WinUSB creates issues + if (((setup->request_type & (0x03 << 5)) == LIBUSB_REQUEST_TYPE_STANDARD) + && (setup->request == LIBUSB_REQUEST_SET_CONFIGURATION)) { + if (setup->value != priv->active_config) { + usbi_warn(ctx, "cannot set configuration other than the default one"); + usbi_free_fd(&wfd); + return LIBUSB_ERROR_INVALID_PARAM; + } + wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; + wfd.overlapped->InternalHigh = 0; + } else { + if (!WinUSBX[sub_api].ControlTransfer(wfd.handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, wfd.overlapped)) { + if (GetLastError() != ERROR_IO_PENDING) { + usbi_warn(ctx, "ControlTransfer failed: %s", windows_error_str(0)); + usbi_free_fd(&wfd); + return LIBUSB_ERROR_IO; + } + } else { + wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; + wfd.overlapped->InternalHigh = (DWORD)size; + } + } + + // Use priv_transfer to store data needed for async polling + transfer_priv->pollable_fd = wfd; + transfer_priv->interface_number = (uint8_t)current_interface; + + return LIBUSB_SUCCESS; +} + +static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + HANDLE winusb_handle; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + if (altsetting > 255) + return LIBUSB_ERROR_INVALID_PARAM; + + winusb_handle = handle_priv->interface_handle[iface].api_handle; + if (!HANDLE_VALID(winusb_handle)) { + usbi_err(ctx, "interface must be claimed first"); + return LIBUSB_ERROR_NOT_FOUND; + } + + if (!WinUSBX[sub_api].SetCurrentAlternateSetting(winusb_handle, (UCHAR)altsetting)) { + usbi_err(ctx, "SetCurrentAlternateSetting failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_IO; + } + + return LIBUSB_SUCCESS; +} + +static int winusbx_submit_bulk_transfer(int sub_api, 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 windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); + struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + HANDLE winusb_handle; + bool ret; + int current_interface; + struct winfd wfd; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + transfer_priv->pollable_fd = INVALID_WINFD; + + current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); + if (current_interface < 0) { + usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); + return LIBUSB_ERROR_NOT_FOUND; + } + + usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); + + winusb_handle = handle_priv->interface_handle[current_interface].api_handle; + + wfd = usbi_create_fd(winusb_handle, 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)) { + usbi_dbg("reading %d bytes", transfer->length); + ret = WinUSBX[sub_api].ReadPipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped); + } else { + usbi_dbg("writing %d bytes", transfer->length); + ret = WinUSBX[sub_api].WritePipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped); + } + + if (!ret) { + if (GetLastError() != ERROR_IO_PENDING) { + usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0)); + usbi_free_fd(&wfd); + return LIBUSB_ERROR_IO; + } + } else { + wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; + wfd.overlapped->InternalHigh = (DWORD)transfer->length; + } + + transfer_priv->pollable_fd = wfd; + transfer_priv->interface_number = (uint8_t)current_interface; + + return LIBUSB_SUCCESS; +} + +static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + HANDLE winusb_handle; + int current_interface; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + current_interface = interface_by_endpoint(priv, handle_priv, endpoint); + if (current_interface < 0) { + usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); + return LIBUSB_ERROR_NOT_FOUND; + } + + usbi_dbg("matched endpoint %02X with interface %d", endpoint, current_interface); + winusb_handle = handle_priv->interface_handle[current_interface].api_handle; + + if (!WinUSBX[sub_api].ResetPipe(winusb_handle, endpoint)) { + usbi_err(ctx, "ResetPipe failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_NO_DEVICE; + } + + return LIBUSB_SUCCESS; +} + +/* + * from http://www.winvistatips.com/winusb-bugchecks-t335323.html (confirmed + * through testing as well): + * "You can not call WinUsb_AbortPipe on control pipe. You can possibly cancel + * the control transfer using CancelIo" + */ +static int winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer) +{ + // Cancelling of the I/O is done in the parent + return LIBUSB_SUCCESS; +} + +static int winusbx_abort_transfers(int sub_api, 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 windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + HANDLE winusb_handle; + int current_interface; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + current_interface = transfer_priv->interface_number; + if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) { + usbi_err(ctx, "program assertion failed: invalid interface_number"); + return LIBUSB_ERROR_NOT_FOUND; + } + usbi_dbg("will use interface %d", current_interface); + + winusb_handle = handle_priv->interface_handle[current_interface].api_handle; + + if (!WinUSBX[sub_api].AbortPipe(winusb_handle, transfer->endpoint)) { + usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_NO_DEVICE; + } + + return LIBUSB_SUCCESS; +} + +/* + * from the "How to Use WinUSB to Communicate with a USB Device" Microsoft white paper + * (http://www.microsoft.com/whdc/connect/usb/winusb_howto.mspx): + * "WinUSB does not support host-initiated reset port and cycle port operations" and + * IOCTL_INTERNAL_USB_CYCLE_PORT is only available in kernel mode and the + * IOCTL_USB_HUB_CYCLE_PORT ioctl was removed from Vista => the best we can do is + * cycle the pipes (and even then, the control pipe can not be reset using WinUSB) + */ +// TODO: (post hotplug): see if we can force eject the device and redetect it (reuse hotplug?) +static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + struct winfd wfd; + HANDLE winusb_handle; + int i, j; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + // Reset any available pipe (except control) + for (i = 0; i < USB_MAXINTERFACES; i++) { + winusb_handle = handle_priv->interface_handle[i].api_handle; + for (wfd = handle_to_winfd(winusb_handle); wfd.fd > 0; ) { + // Cancel any pollable I/O + usbi_remove_pollfd(ctx, wfd.fd); + usbi_free_fd(&wfd); + wfd = handle_to_winfd(winusb_handle); + } + + if (HANDLE_VALID(winusb_handle)) { + for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) { + usbi_dbg("resetting ep %02X", priv->usb_interface[i].endpoint[j]); + if (!WinUSBX[sub_api].AbortPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) + usbi_err(ctx, "AbortPipe (pipe address %02X) failed: %s", + priv->usb_interface[i].endpoint[j], windows_error_str(0)); + + // FlushPipe seems to fail on OUT pipes + if (IS_EPIN(priv->usb_interface[i].endpoint[j]) + && (!WinUSBX[sub_api].FlushPipe(winusb_handle, priv->usb_interface[i].endpoint[j]))) + usbi_err(ctx, "FlushPipe (pipe address %02X) failed: %s", + priv->usb_interface[i].endpoint[j], windows_error_str(0)); + + if (!WinUSBX[sub_api].ResetPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) + usbi_err(ctx, "ResetPipe (pipe address %02X) failed: %s", + priv->usb_interface[i].endpoint[j], windows_error_str(0)); + } + } + } + + // libusbK & libusb0 have the ability to issue an actual device reset + if (WinUSBX[sub_api].ResetDevice != NULL) { + winusb_handle = handle_priv->interface_handle[0].api_handle; + if (HANDLE_VALID(winusb_handle)) + WinUSBX[sub_api].ResetDevice(winusb_handle); + } + + return LIBUSB_SUCCESS; +} + +static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) +{ + itransfer->transferred += io_size; + return LIBUSB_TRANSFER_COMPLETED; +} + +/* + * Internal HID Support functions (from libusb-win32) + * Note that functions that complete data transfer synchronously must return + * LIBUSB_COMPLETED instead of LIBUSB_SUCCESS + */ +static int _hid_get_hid_descriptor(struct hid_device_priv *dev, void *data, size_t *size); +static int _hid_get_report_descriptor(struct hid_device_priv *dev, void *data, size_t *size); + +static int _hid_wcslen(WCHAR *str) +{ + int i = 0; + + while (str[i] && (str[i] != 0x409)) + i++; + + return i; +} + +static int _hid_get_device_descriptor(struct hid_device_priv *dev, void *data, size_t *size) +{ + struct libusb_device_descriptor d; + + d.bLength = LIBUSB_DT_DEVICE_SIZE; + d.bDescriptorType = LIBUSB_DT_DEVICE; + d.bcdUSB = 0x0200; /* 2.00 */ + d.bDeviceClass = 0; + d.bDeviceSubClass = 0; + d.bDeviceProtocol = 0; + d.bMaxPacketSize0 = 64; /* fix this! */ + d.idVendor = (uint16_t)dev->vid; + d.idProduct = (uint16_t)dev->pid; + d.bcdDevice = 0x0100; + d.iManufacturer = dev->string_index[0]; + d.iProduct = dev->string_index[1]; + d.iSerialNumber = dev->string_index[2]; + d.bNumConfigurations = 1; + + if (*size > LIBUSB_DT_DEVICE_SIZE) + *size = LIBUSB_DT_DEVICE_SIZE; + memcpy(data, &d, *size); + + return LIBUSB_COMPLETED; +} + +static int _hid_get_config_descriptor(struct hid_device_priv *dev, void *data, size_t *size) +{ + char num_endpoints = 0; + size_t config_total_len = 0; + char tmp[HID_MAX_CONFIG_DESC_SIZE]; + struct libusb_config_descriptor *cd; + struct libusb_interface_descriptor *id; + struct libusb_hid_descriptor *hd; + struct libusb_endpoint_descriptor *ed; + size_t tmp_size; + + if (dev->input_report_size) + num_endpoints++; + if (dev->output_report_size) + num_endpoints++; + + config_total_len = LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE + + LIBUSB_DT_HID_SIZE + num_endpoints * LIBUSB_DT_ENDPOINT_SIZE; + + cd = (struct libusb_config_descriptor *)tmp; + id = (struct libusb_interface_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE); + hd = (struct libusb_hid_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE + + LIBUSB_DT_INTERFACE_SIZE); + ed = (struct libusb_endpoint_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE + + LIBUSB_DT_INTERFACE_SIZE + + LIBUSB_DT_HID_SIZE); + + cd->bLength = LIBUSB_DT_CONFIG_SIZE; + cd->bDescriptorType = LIBUSB_DT_CONFIG; + cd->wTotalLength = (uint16_t)config_total_len; + cd->bNumInterfaces = 1; + cd->bConfigurationValue = 1; + cd->iConfiguration = 0; + cd->bmAttributes = 1 << 7; /* bus powered */ + cd->MaxPower = 50; + + id->bLength = LIBUSB_DT_INTERFACE_SIZE; + id->bDescriptorType = LIBUSB_DT_INTERFACE; + id->bInterfaceNumber = 0; + id->bAlternateSetting = 0; + id->bNumEndpoints = num_endpoints; + id->bInterfaceClass = 3; + id->bInterfaceSubClass = 0; + id->bInterfaceProtocol = 0; + id->iInterface = 0; + + tmp_size = LIBUSB_DT_HID_SIZE; + _hid_get_hid_descriptor(dev, hd, &tmp_size); + + if (dev->input_report_size) { + ed->bLength = LIBUSB_DT_ENDPOINT_SIZE; + ed->bDescriptorType = LIBUSB_DT_ENDPOINT; + ed->bEndpointAddress = HID_IN_EP; + ed->bmAttributes = 3; + ed->wMaxPacketSize = dev->input_report_size - 1; + ed->bInterval = 10; + ed = (struct libusb_endpoint_descriptor *)((char *)ed + LIBUSB_DT_ENDPOINT_SIZE); + } + + if (dev->output_report_size) { + ed->bLength = LIBUSB_DT_ENDPOINT_SIZE; + ed->bDescriptorType = LIBUSB_DT_ENDPOINT; + ed->bEndpointAddress = HID_OUT_EP; + ed->bmAttributes = 3; + ed->wMaxPacketSize = dev->output_report_size - 1; + ed->bInterval = 10; + } + + if (*size > config_total_len) + *size = config_total_len; + memcpy(data, tmp, *size); + + return LIBUSB_COMPLETED; +} + +static int _hid_get_string_descriptor(struct hid_device_priv *dev, int _index, + void *data, size_t *size) +{ + void *tmp = NULL; + size_t tmp_size = 0; + int i; + + /* language ID, EN-US */ + char string_langid[] = {0x09, 0x04}; + + if ((*size < 2) || (*size > 255)) + return LIBUSB_ERROR_OVERFLOW; + + if (_index == 0) { + tmp = string_langid; + tmp_size = sizeof(string_langid) + 2; + } else { + for (i = 0; i < 3; i++) { + if (_index == (dev->string_index[i])) { + tmp = dev->string[i]; + tmp_size = (_hid_wcslen(dev->string[i]) + 1) * sizeof(WCHAR); + break; + } + } + + if (i == 3) // not found + return LIBUSB_ERROR_INVALID_PARAM; + } + + if (!tmp_size) + return LIBUSB_ERROR_INVALID_PARAM; + + if (tmp_size < *size) + *size = tmp_size; + + // 2 byte header + ((uint8_t *)data)[0] = (uint8_t)*size; + ((uint8_t *)data)[1] = LIBUSB_DT_STRING; + memcpy((uint8_t *)data + 2, tmp, *size - 2); + + return LIBUSB_COMPLETED; +} + +static int _hid_get_hid_descriptor(struct hid_device_priv *dev, void *data, size_t *size) +{ + struct libusb_hid_descriptor d; + uint8_t tmp[MAX_HID_DESCRIPTOR_SIZE]; + size_t report_len = MAX_HID_DESCRIPTOR_SIZE; + + _hid_get_report_descriptor(dev, tmp, &report_len); + + d.bLength = LIBUSB_DT_HID_SIZE; + d.bDescriptorType = LIBUSB_DT_HID; + d.bcdHID = 0x0110; /* 1.10 */ + d.bCountryCode = 0; + d.bNumDescriptors = 1; + d.bClassDescriptorType = LIBUSB_DT_REPORT; + d.wClassDescriptorLength = (uint16_t)report_len; + + if (*size > LIBUSB_DT_HID_SIZE) + *size = LIBUSB_DT_HID_SIZE; + memcpy(data, &d, *size); + + return LIBUSB_COMPLETED; +} + +static int _hid_get_report_descriptor(struct hid_device_priv *dev, void *data, size_t *size) +{ + uint8_t d[MAX_HID_DESCRIPTOR_SIZE]; + size_t i = 0; + + /* usage page (0xFFA0 == vendor defined) */ + d[i++] = 0x06; d[i++] = 0xA0; d[i++] = 0xFF; + /* usage (vendor defined) */ + d[i++] = 0x09; d[i++] = 0x01; + /* start collection (application) */ + d[i++] = 0xA1; d[i++] = 0x01; + /* input report */ + if (dev->input_report_size) { + /* usage (vendor defined) */ + d[i++] = 0x09; d[i++] = 0x01; + /* logical minimum (0) */ + d[i++] = 0x15; d[i++] = 0x00; + /* logical maximum (255) */ + d[i++] = 0x25; d[i++] = 0xFF; + /* report size (8 bits) */ + d[i++] = 0x75; d[i++] = 0x08; + /* report count */ + d[i++] = 0x95; d[i++] = (uint8_t)dev->input_report_size - 1; + /* input (data, variable, absolute) */ + d[i++] = 0x81; d[i++] = 0x00; + } + /* output report */ + if (dev->output_report_size) { + /* usage (vendor defined) */ + d[i++] = 0x09; d[i++] = 0x02; + /* logical minimum (0) */ + d[i++] = 0x15; d[i++] = 0x00; + /* logical maximum (255) */ + d[i++] = 0x25; d[i++] = 0xFF; + /* report size (8 bits) */ + d[i++] = 0x75; d[i++] = 0x08; + /* report count */ + d[i++] = 0x95; d[i++] = (uint8_t)dev->output_report_size - 1; + /* output (data, variable, absolute) */ + d[i++] = 0x91; d[i++] = 0x00; + } + /* feature report */ + if (dev->feature_report_size) { + /* usage (vendor defined) */ + d[i++] = 0x09; d[i++] = 0x03; + /* logical minimum (0) */ + d[i++] = 0x15; d[i++] = 0x00; + /* logical maximum (255) */ + d[i++] = 0x25; d[i++] = 0xFF; + /* report size (8 bits) */ + d[i++] = 0x75; d[i++] = 0x08; + /* report count */ + d[i++] = 0x95; d[i++] = (uint8_t)dev->feature_report_size - 1; + /* feature (data, variable, absolute) */ + d[i++] = 0xb2; d[i++] = 0x02; d[i++] = 0x01; + } + + /* end collection */ + d[i++] = 0xC0; + + if (*size > i) + *size = i; + memcpy(data, d, *size); + + return LIBUSB_COMPLETED; +} + +static int _hid_get_descriptor(struct hid_device_priv *dev, HANDLE hid_handle, int recipient, + int type, int _index, void *data, size_t *size) +{ + switch(type) { + case LIBUSB_DT_DEVICE: + usbi_dbg("LIBUSB_DT_DEVICE"); + return _hid_get_device_descriptor(dev, data, size); + case LIBUSB_DT_CONFIG: + usbi_dbg("LIBUSB_DT_CONFIG"); + if (!_index) + return _hid_get_config_descriptor(dev, data, size); + return LIBUSB_ERROR_INVALID_PARAM; + case LIBUSB_DT_STRING: + usbi_dbg("LIBUSB_DT_STRING"); + return _hid_get_string_descriptor(dev, _index, data, size); + case LIBUSB_DT_HID: + usbi_dbg("LIBUSB_DT_HID"); + if (!_index) + return _hid_get_hid_descriptor(dev, data, size); + return LIBUSB_ERROR_INVALID_PARAM; + case LIBUSB_DT_REPORT: + usbi_dbg("LIBUSB_DT_REPORT"); + if (!_index) + return _hid_get_report_descriptor(dev, data, size); + return LIBUSB_ERROR_INVALID_PARAM; + case LIBUSB_DT_PHYSICAL: + usbi_dbg("LIBUSB_DT_PHYSICAL"); + if (HidD_GetPhysicalDescriptor(hid_handle, data, (ULONG)*size)) + return LIBUSB_COMPLETED; + return LIBUSB_ERROR_OTHER; + } + + usbi_dbg("unsupported"); + return LIBUSB_ERROR_NOT_SUPPORTED; +} + +static int _hid_get_report(struct hid_device_priv *dev, HANDLE hid_handle, int id, void *data, + struct windows_transfer_priv *tp, size_t *size, OVERLAPPED *overlapped, int report_type) +{ + uint8_t *buf; + DWORD ioctl_code, read_size, expected_size = (DWORD)*size; + int r = LIBUSB_SUCCESS; + + if (tp->hid_buffer != NULL) + usbi_dbg("program assertion failed: hid_buffer is not NULL"); + + if ((*size == 0) || (*size > MAX_HID_REPORT_SIZE)) { + usbi_dbg("invalid size (%u)", *size); + return LIBUSB_ERROR_INVALID_PARAM; + } + + switch (report_type) { + case HID_REPORT_TYPE_INPUT: + ioctl_code = IOCTL_HID_GET_INPUT_REPORT; + break; + case HID_REPORT_TYPE_FEATURE: + ioctl_code = IOCTL_HID_GET_FEATURE; + break; + default: + usbi_dbg("unknown HID report type %d", report_type); + return LIBUSB_ERROR_INVALID_PARAM; + } + + // Add a trailing byte to detect overflows + buf = calloc(1, expected_size + 1); + if (buf == NULL) + return LIBUSB_ERROR_NO_MEM; + + buf[0] = (uint8_t)id; // Must be set always + usbi_dbg("report ID: 0x%02X", buf[0]); + + tp->hid_expected_size = expected_size; + read_size = expected_size; + + // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0) + if (!DeviceIoControl(hid_handle, ioctl_code, buf, expected_size + 1, + buf, expected_size + 1, &read_size, overlapped)) { + if (GetLastError() != ERROR_IO_PENDING) { + usbi_dbg("Failed to Read HID Report: %s", windows_error_str(0)); + safe_free(buf); + return LIBUSB_ERROR_IO; + } + // Asynchronous wait + tp->hid_buffer = buf; + tp->hid_dest = data; // copy dest, as not necessarily the start of the transfer buffer + return LIBUSB_SUCCESS; + } + + // Transfer completed synchronously => copy and discard extra buffer + if (read_size == 0) { + usbi_warn(NULL, "program assertion failed - read completed synchronously, but no data was read"); + *size = 0; + } else { + if (buf[0] != id) + usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id); + + if ((size_t)read_size > expected_size) { + r = LIBUSB_ERROR_OVERFLOW; + usbi_dbg("OVERFLOW!"); + } else { + r = LIBUSB_COMPLETED; + } + + *size = MIN((size_t)read_size, *size); + if (id == 0) + memcpy(data, buf + 1, *size); // Discard report ID + else + memcpy(data, buf, *size); + } + + safe_free(buf); + return r; +} + +static int _hid_set_report(struct hid_device_priv *dev, HANDLE hid_handle, int id, void *data, + struct windows_transfer_priv *tp, size_t *size, OVERLAPPED *overlapped, int report_type) +{ + uint8_t *buf = NULL; + DWORD ioctl_code, write_size = (DWORD)*size; + + if (tp->hid_buffer != NULL) + usbi_dbg("program assertion failed: hid_buffer is not NULL"); + + if ((*size == 0) || (*size > MAX_HID_REPORT_SIZE)) { + usbi_dbg("invalid size (%u)", *size); + return LIBUSB_ERROR_INVALID_PARAM; + } + + switch (report_type) { + case HID_REPORT_TYPE_OUTPUT: + ioctl_code = IOCTL_HID_SET_OUTPUT_REPORT; + break; + case HID_REPORT_TYPE_FEATURE: + ioctl_code = IOCTL_HID_SET_FEATURE; + break; + default: + usbi_dbg("unknown HID report type %d", report_type); + return LIBUSB_ERROR_INVALID_PARAM; + } + + usbi_dbg("report ID: 0x%02X", id); + // When report IDs are not used (i.e. when id == 0), we must add + // a null report ID. Otherwise, we just use original data buffer + if (id == 0) + write_size++; + + buf = malloc(write_size); + if (buf == NULL) + return LIBUSB_ERROR_NO_MEM; + + if (id == 0) { + buf[0] = 0; + memcpy(buf + 1, data, *size); + } else { + // This seems like a waste, but if we don't duplicate the + // data, we'll get issues when freeing hid_buffer + memcpy(buf, data, *size); + if (buf[0] != id) + usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id); + } + + // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0) + if (!DeviceIoControl(hid_handle, ioctl_code, buf, write_size, + buf, write_size, &write_size, overlapped)) { + if (GetLastError() != ERROR_IO_PENDING) { + usbi_dbg("Failed to Write HID Output Report: %s", windows_error_str(0)); + safe_free(buf); + return LIBUSB_ERROR_IO; + } + tp->hid_buffer = buf; + tp->hid_dest = NULL; + return LIBUSB_SUCCESS; + } + + // Transfer completed synchronously + *size = write_size; + if (write_size == 0) + usbi_dbg("program assertion failed - write completed synchronously, but no data was written"); + + safe_free(buf); + return LIBUSB_COMPLETED; +} + +static int _hid_class_request(struct hid_device_priv *dev, HANDLE hid_handle, int request_type, + int request, int value, int _index, void *data, struct windows_transfer_priv *tp, + size_t *size, OVERLAPPED *overlapped) +{ + int report_type = (value >> 8) & 0xFF; + int report_id = value & 0xFF; + + if ((LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_INTERFACE) + && (LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_DEVICE)) + return LIBUSB_ERROR_INVALID_PARAM; + + if (LIBUSB_REQ_OUT(request_type) && request == HID_REQ_SET_REPORT) + return _hid_set_report(dev, hid_handle, report_id, data, tp, size, overlapped, report_type); + + if (LIBUSB_REQ_IN(request_type) && request == HID_REQ_GET_REPORT) + return _hid_get_report(dev, hid_handle, report_id, data, tp, size, overlapped, report_type); + + return LIBUSB_ERROR_INVALID_PARAM; +} + + +/* + * HID API functions + */ +static int hid_init(int sub_api, struct libusb_context *ctx) +{ + DLL_GET_HANDLE(hid); + DLL_LOAD_FUNC(hid, HidD_GetAttributes, TRUE); + DLL_LOAD_FUNC(hid, HidD_GetHidGuid, TRUE); + DLL_LOAD_FUNC(hid, HidD_GetPreparsedData, TRUE); + DLL_LOAD_FUNC(hid, HidD_FreePreparsedData, TRUE); + DLL_LOAD_FUNC(hid, HidD_GetManufacturerString, TRUE); + DLL_LOAD_FUNC(hid, HidD_GetProductString, TRUE); + DLL_LOAD_FUNC(hid, HidD_GetSerialNumberString, TRUE); + DLL_LOAD_FUNC(hid, HidP_GetCaps, TRUE); + DLL_LOAD_FUNC(hid, HidD_SetNumInputBuffers, TRUE); + DLL_LOAD_FUNC(hid, HidD_SetFeature, TRUE); + DLL_LOAD_FUNC(hid, HidD_GetFeature, TRUE); + DLL_LOAD_FUNC(hid, HidD_GetPhysicalDescriptor, TRUE); + DLL_LOAD_FUNC(hid, HidD_GetInputReport, FALSE); + DLL_LOAD_FUNC(hid, HidD_SetOutputReport, FALSE); + DLL_LOAD_FUNC(hid, HidD_FlushQueue, TRUE); + DLL_LOAD_FUNC(hid, HidP_GetValueCaps, TRUE); + + api_hid_available = true; + return LIBUSB_SUCCESS; +} + +static int hid_exit(int sub_api) +{ + DLL_FREE_HANDLE(hid); + + return LIBUSB_SUCCESS; +} + +// NB: open and close must ensure that they only handle interface of +// the right API type, as these functions can be called wholesale from +// composite_open(), with interfaces belonging to different APIs +static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + HIDD_ATTRIBUTES hid_attributes; + PHIDP_PREPARSED_DATA preparsed_data = NULL; + HIDP_CAPS capabilities; + HIDP_VALUE_CAPS *value_caps; + HANDLE hid_handle = INVALID_HANDLE_VALUE; + int i, j; + // report IDs handling + ULONG size[3]; + int nb_ids[2]; // zero and nonzero report IDs +#if defined(ENABLE_LOGGING) + const char *type[3] = {"input", "output", "feature"}; +#endif + + CHECK_HID_AVAILABLE; + + if (priv->hid == NULL) { + usbi_err(ctx, "program assertion failed - private HID structure is unitialized"); + return LIBUSB_ERROR_NOT_FOUND; + } + + for (i = 0; i < USB_MAXINTERFACES; i++) { + if ((priv->usb_interface[i].path != NULL) + && (priv->usb_interface[i].apib->id == USB_API_HID)) { + hid_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + /* + * http://www.lvr.com/hidfaq.htm: Why do I receive "Access denied" when attempting to access my HID? + * "Windows 2000 and later have exclusive read/write access to HIDs that are configured as a system + * keyboards or mice. An application can obtain a handle to a system keyboard or mouse by not + * requesting READ or WRITE access with CreateFile. Applications can then use HidD_SetFeature and + * HidD_GetFeature (if the device supports Feature reports)." + */ + if (hid_handle == INVALID_HANDLE_VALUE) { + usbi_warn(ctx, "could not open HID device in R/W mode (keyboard or mouse?) - trying without"); + hid_handle = CreateFileA(priv->usb_interface[i].path, 0, FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + if (hid_handle == INVALID_HANDLE_VALUE) { + usbi_err(ctx, "could not open device %s (interface %d): %s", priv->path, i, windows_error_str(0)); + switch(GetLastError()) { + case ERROR_FILE_NOT_FOUND: // The device was disconnected + return LIBUSB_ERROR_NO_DEVICE; + case ERROR_ACCESS_DENIED: + return LIBUSB_ERROR_ACCESS; + default: + return LIBUSB_ERROR_IO; + } + } + priv->usb_interface[i].restricted_functionality = true; + } + handle_priv->interface_handle[i].api_handle = hid_handle; + } + } + + hid_attributes.Size = sizeof(hid_attributes); + do { + if (!HidD_GetAttributes(hid_handle, &hid_attributes)) { + usbi_err(ctx, "could not gain access to HID top collection (HidD_GetAttributes)"); + break; + } + + priv->hid->vid = hid_attributes.VendorID; + priv->hid->pid = hid_attributes.ProductID; + + // Set the maximum available input buffer size + for (i = 32; HidD_SetNumInputBuffers(hid_handle, i); i *= 2); + usbi_dbg("set maximum input buffer size to %d", i / 2); + + // Get the maximum input and output report size + if (!HidD_GetPreparsedData(hid_handle, &preparsed_data) || !preparsed_data) { + usbi_err(ctx, "could not read HID preparsed data (HidD_GetPreparsedData)"); + break; + } + if (HidP_GetCaps(preparsed_data, &capabilities) != HIDP_STATUS_SUCCESS) { + usbi_err(ctx, "could not parse HID capabilities (HidP_GetCaps)"); + break; + } + + // Find out if interrupt will need report IDs + size[0] = capabilities.NumberInputValueCaps; + size[1] = capabilities.NumberOutputValueCaps; + size[2] = capabilities.NumberFeatureValueCaps; + for (j = HidP_Input; j <= HidP_Feature; j++) { + usbi_dbg("%u HID %s report value(s) found", (unsigned int)size[j], type[j]); + priv->hid->uses_report_ids[j] = false; + if (size[j] > 0) { + value_caps = calloc(size[j], sizeof(HIDP_VALUE_CAPS)); + if ((value_caps != NULL) + && (HidP_GetValueCaps((HIDP_REPORT_TYPE)j, value_caps, &size[j], preparsed_data) == HIDP_STATUS_SUCCESS) + && (size[j] >= 1)) { + nb_ids[0] = 0; + nb_ids[1] = 0; + for (i = 0; i < (int)size[j]; i++) { + usbi_dbg(" Report ID: 0x%02X", value_caps[i].ReportID); + if (value_caps[i].ReportID != 0) + nb_ids[1]++; + else + nb_ids[0]++; + } + if (nb_ids[1] != 0) { + if (nb_ids[0] != 0) + usbi_warn(ctx, "program assertion failed: zero and nonzero report IDs used for %s", + type[j]); + priv->hid->uses_report_ids[j] = true; + } + } else { + usbi_warn(ctx, " could not process %s report IDs", type[j]); + } + safe_free(value_caps); + } + } + + // Set the report sizes + priv->hid->input_report_size = capabilities.InputReportByteLength; + priv->hid->output_report_size = capabilities.OutputReportByteLength; + priv->hid->feature_report_size = capabilities.FeatureReportByteLength; + + // Fetch string descriptors + priv->hid->string_index[0] = priv->dev_descriptor.iManufacturer; + if (priv->hid->string_index[0] != 0) + HidD_GetManufacturerString(hid_handle, priv->hid->string[0], sizeof(priv->hid->string[0])); + else + priv->hid->string[0][0] = 0; + + priv->hid->string_index[1] = priv->dev_descriptor.iProduct; + if (priv->hid->string_index[1] != 0) + HidD_GetProductString(hid_handle, priv->hid->string[1], sizeof(priv->hid->string[1])); + else + priv->hid->string[1][0] = 0; + + priv->hid->string_index[2] = priv->dev_descriptor.iSerialNumber; + if (priv->hid->string_index[2] != 0) + HidD_GetSerialNumberString(hid_handle, priv->hid->string[2], sizeof(priv->hid->string[2])); + else + priv->hid->string[2][0] = 0; + } while(0); + + if (preparsed_data) + HidD_FreePreparsedData(preparsed_data); + + return LIBUSB_SUCCESS; +} + +static void hid_close(int sub_api, struct libusb_device_handle *dev_handle) +{ + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + HANDLE file_handle; + int i; + + if (!api_hid_available) + return; + + for (i = 0; i < USB_MAXINTERFACES; i++) { + if (priv->usb_interface[i].apib->id == USB_API_HID) { + file_handle = handle_priv->interface_handle[i].api_handle; + if (HANDLE_VALID(file_handle)) + CloseHandle(file_handle); + } + } +} + +static int hid_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) +{ + struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + + CHECK_HID_AVAILABLE; + + // NB: Disconnection detection is not possible in this function + if (priv->usb_interface[iface].path == NULL) + return LIBUSB_ERROR_NOT_FOUND; // invalid iface + + // We use dev_handle as a flag for interface claimed + if (handle_priv->interface_handle[iface].dev_handle == INTERFACE_CLAIMED) + return LIBUSB_ERROR_BUSY; // already claimed + + + handle_priv->interface_handle[iface].dev_handle = INTERFACE_CLAIMED; + + usbi_dbg("claimed interface %d", iface); + handle_priv->active_interface = iface; + + return LIBUSB_SUCCESS; +} + +static int hid_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) +{ + struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + + CHECK_HID_AVAILABLE; + + if (priv->usb_interface[iface].path == NULL) + return LIBUSB_ERROR_NOT_FOUND; // invalid iface + + if (handle_priv->interface_handle[iface].dev_handle != INTERFACE_CLAIMED) + return LIBUSB_ERROR_NOT_FOUND; // invalid iface + + handle_priv->interface_handle[iface].dev_handle = INVALID_HANDLE_VALUE; + + return LIBUSB_SUCCESS; +} + +static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + + CHECK_HID_AVAILABLE; + + if (altsetting > 255) + return LIBUSB_ERROR_INVALID_PARAM; + + if (altsetting != 0) { + usbi_err(ctx, "set interface altsetting not supported for altsetting >0"); + return LIBUSB_ERROR_NOT_SUPPORTED; + } + + return LIBUSB_SUCCESS; +} + +static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); + struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer; + HANDLE hid_handle; + struct winfd wfd; + int current_interface, config; + size_t size; + int r = LIBUSB_ERROR_INVALID_PARAM; + + CHECK_HID_AVAILABLE; + + transfer_priv->pollable_fd = INVALID_WINFD; + safe_free(transfer_priv->hid_buffer); + transfer_priv->hid_dest = NULL; + size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE; + + if (size > MAX_CTRL_BUFFER_LENGTH) + return LIBUSB_ERROR_INVALID_PARAM; + + current_interface = get_valid_interface(transfer->dev_handle, USB_API_HID); + if (current_interface < 0) { + if (auto_claim(transfer, ¤t_interface, USB_API_HID) != LIBUSB_SUCCESS) + return LIBUSB_ERROR_NOT_FOUND; + } + + usbi_dbg("will use interface %d", current_interface); + hid_handle = handle_priv->interface_handle[current_interface].api_handle; + // Always use the handle returned from usbi_create_fd (wfd.handle) + wfd = usbi_create_fd(hid_handle, RW_READ, NULL, NULL); + if (wfd.fd < 0) + return LIBUSB_ERROR_NOT_FOUND; + + switch(LIBUSB_REQ_TYPE(setup->request_type)) { + case LIBUSB_REQUEST_TYPE_STANDARD: + switch(setup->request) { + case LIBUSB_REQUEST_GET_DESCRIPTOR: + r = _hid_get_descriptor(priv->hid, wfd.handle, LIBUSB_REQ_RECIPIENT(setup->request_type), + (setup->value >> 8) & 0xFF, setup->value & 0xFF, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, &size); + break; + case LIBUSB_REQUEST_GET_CONFIGURATION: + r = windows_get_configuration(transfer->dev_handle, &config); + if (r == LIBUSB_SUCCESS) { + size = 1; + ((uint8_t *)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = (uint8_t)config; + r = LIBUSB_COMPLETED; + } + break; + case LIBUSB_REQUEST_SET_CONFIGURATION: + if (setup->value == priv->active_config) { + r = LIBUSB_COMPLETED; + } else { + usbi_warn(ctx, "cannot set configuration other than the default one"); + r = LIBUSB_ERROR_NOT_SUPPORTED; + } + break; + case LIBUSB_REQUEST_GET_INTERFACE: + size = 1; + ((uint8_t *)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = 0; + r = LIBUSB_COMPLETED; + break; + case LIBUSB_REQUEST_SET_INTERFACE: + r = hid_set_interface_altsetting(0, transfer->dev_handle, setup->index, setup->value); + if (r == LIBUSB_SUCCESS) + r = LIBUSB_COMPLETED; + break; + default: + usbi_warn(ctx, "unsupported HID control request"); + r = LIBUSB_ERROR_NOT_SUPPORTED; + break; + } + break; + case LIBUSB_REQUEST_TYPE_CLASS: + r = _hid_class_request(priv->hid, wfd.handle, setup->request_type, setup->request, setup->value, + setup->index, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, transfer_priv, + &size, wfd.overlapped); + break; + default: + usbi_warn(ctx, "unsupported HID control request"); + r = LIBUSB_ERROR_NOT_SUPPORTED; + break; + } + + if (r == LIBUSB_COMPLETED) { + // Force request to be completed synchronously. Transferred size has been set by previous call + wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; + // http://msdn.microsoft.com/en-us/library/ms684342%28VS.85%29.aspx + // set InternalHigh to the number of bytes transferred + wfd.overlapped->InternalHigh = (DWORD)size; + r = LIBUSB_SUCCESS; + } + + if (r == LIBUSB_SUCCESS) { + // Use priv_transfer to store data needed for async polling + transfer_priv->pollable_fd = wfd; + transfer_priv->interface_number = (uint8_t)current_interface; + } else { + usbi_free_fd(&wfd); + } + + return r; +} + +static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); + struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + struct winfd wfd; + HANDLE hid_handle; + bool direction_in, ret; + int current_interface, length; + DWORD size; + int r = LIBUSB_SUCCESS; + + CHECK_HID_AVAILABLE; + + transfer_priv->pollable_fd = INVALID_WINFD; + transfer_priv->hid_dest = NULL; + safe_free(transfer_priv->hid_buffer); + + current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); + if (current_interface < 0) { + usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); + return LIBUSB_ERROR_NOT_FOUND; + } + + usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); + + hid_handle = handle_priv->interface_handle[current_interface].api_handle; + direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN; + + wfd = usbi_create_fd(hid_handle, direction_in?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 report IDs are not in use, an extra prefix byte must be added + if (((direction_in) && (!priv->hid->uses_report_ids[0])) + || ((!direction_in) && (!priv->hid->uses_report_ids[1]))) + length = transfer->length + 1; + else + length = transfer->length; + + // Add a trailing byte to detect overflows on input + transfer_priv->hid_buffer = calloc(1, length + 1); + if (transfer_priv->hid_buffer == NULL) + return LIBUSB_ERROR_NO_MEM; + + transfer_priv->hid_expected_size = length; + + if (direction_in) { + transfer_priv->hid_dest = transfer->buffer; + usbi_dbg("reading %d bytes (report ID: 0x00)", length); + ret = ReadFile(wfd.handle, transfer_priv->hid_buffer, length + 1, &size, wfd.overlapped); + } else { + if (!priv->hid->uses_report_ids[1]) + memcpy(transfer_priv->hid_buffer + 1, transfer->buffer, transfer->length); + else + // We could actually do without the calloc and memcpy in this case + memcpy(transfer_priv->hid_buffer, transfer->buffer, transfer->length); + + usbi_dbg("writing %d bytes (report ID: 0x%02X)", length, transfer_priv->hid_buffer[0]); + ret = WriteFile(wfd.handle, transfer_priv->hid_buffer, length, &size, wfd.overlapped); + } + + if (!ret) { + if (GetLastError() != ERROR_IO_PENDING) { + usbi_err(ctx, "HID transfer failed: %s", windows_error_str(0)); + usbi_free_fd(&wfd); + safe_free(transfer_priv->hid_buffer); + return LIBUSB_ERROR_IO; + } + } else { + // Only write operations that completed synchronously need to free up + // hid_buffer. For reads, copy_transfer_data() handles that process. + if (!direction_in) + safe_free(transfer_priv->hid_buffer); + + if (size == 0) { + usbi_err(ctx, "program assertion failed - no data was transferred"); + size = 1; + } + if (size > (size_t)length) { + usbi_err(ctx, "OVERFLOW!"); + r = LIBUSB_ERROR_OVERFLOW; + } + wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; + wfd.overlapped->InternalHigh = size; + } + + transfer_priv->pollable_fd = wfd; + transfer_priv->interface_number = (uint8_t)current_interface; + + return r; +} + +static int hid_abort_transfers(int sub_api, struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); + HANDLE hid_handle; + int current_interface; + + CHECK_HID_AVAILABLE; + + current_interface = transfer_priv->interface_number; + hid_handle = handle_priv->interface_handle[current_interface].api_handle; + CancelIo(hid_handle); + + return LIBUSB_SUCCESS; +} + +static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle) +{ + struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + HANDLE hid_handle; + int current_interface; + + CHECK_HID_AVAILABLE; + + // Flushing the queues on all interfaces is the best we can achieve + for (current_interface = 0; current_interface < USB_MAXINTERFACES; current_interface++) { + hid_handle = handle_priv->interface_handle[current_interface].api_handle; + if (HANDLE_VALID(hid_handle)) + HidD_FlushQueue(hid_handle); + } + + return LIBUSB_SUCCESS; +} + +static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + HANDLE hid_handle; + int current_interface; + + CHECK_HID_AVAILABLE; + + current_interface = interface_by_endpoint(priv, handle_priv, endpoint); + if (current_interface < 0) { + usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); + return LIBUSB_ERROR_NOT_FOUND; + } + + usbi_dbg("matched endpoint %02X with interface %d", endpoint, current_interface); + hid_handle = handle_priv->interface_handle[current_interface].api_handle; + + // No endpoint selection with Microsoft's implementation, so we try to flush the + // whole interface. Should be OK for most case scenarios + if (!HidD_FlushQueue(hid_handle)) { + usbi_err(ctx, "Flushing of HID queue failed: %s", windows_error_str(0)); + // Device was probably disconnected + return LIBUSB_ERROR_NO_DEVICE; + } + + return LIBUSB_SUCCESS; +} + +// This extra function is only needed for HID +static int hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + int r = LIBUSB_TRANSFER_COMPLETED; + uint32_t corrected_size = io_size; + + if (transfer_priv->hid_buffer != NULL) { + // If we have a valid hid_buffer, it means the transfer was async + if (transfer_priv->hid_dest != NULL) { // Data readout + if (corrected_size > 0) { + // First, check for overflow + if (corrected_size > transfer_priv->hid_expected_size) { + usbi_err(ctx, "OVERFLOW!"); + corrected_size = (uint32_t)transfer_priv->hid_expected_size; + r = LIBUSB_TRANSFER_OVERFLOW; + } + + if (transfer_priv->hid_buffer[0] == 0) { + // Discard the 1 byte report ID prefix + corrected_size--; + memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer + 1, corrected_size); + } else { + memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer, corrected_size); + } + } + transfer_priv->hid_dest = NULL; + } + // For write, we just need to free the hid buffer + safe_free(transfer_priv->hid_buffer); + } + + itransfer->transferred += corrected_size; + return r; +} + + +/* + * Composite API functions + */ +static int composite_init(int sub_api, struct libusb_context *ctx) +{ + return LIBUSB_SUCCESS; +} + +static int composite_exit(int sub_api) +{ + return LIBUSB_SUCCESS; +} + +static int composite_open(int sub_api, struct libusb_device_handle *dev_handle) +{ + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + int r = LIBUSB_ERROR_NOT_FOUND; + uint8_t i; + // SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID + bool available[SUB_API_MAX + 1] = { 0 }; + + for (i = 0; i < USB_MAXINTERFACES; i++) { + switch (priv->usb_interface[i].apib->id) { + case USB_API_WINUSBX: + if (priv->usb_interface[i].sub_api != SUB_API_NOTSET) + available[priv->usb_interface[i].sub_api] = true; + break; + case USB_API_HID: + available[SUB_API_MAX] = true; + break; + default: + break; + } + } + + for (i = 0; i < SUB_API_MAX; i++) { // WinUSB-like drivers + if (available[i]) { + r = usb_api_backend[USB_API_WINUSBX].open(i, dev_handle); + if (r != LIBUSB_SUCCESS) + return r; + } + } + + if (available[SUB_API_MAX]) // HID driver + r = hid_open(SUB_API_NOTSET, dev_handle); + + return r; +} + +static void composite_close(int sub_api, struct libusb_device_handle *dev_handle) +{ + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + uint8_t i; + // SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID + bool available[SUB_API_MAX + 1] = { 0 }; + + for (i = 0; i < USB_MAXINTERFACES; i++) { + switch (priv->usb_interface[i].apib->id) { + case USB_API_WINUSBX: + if (priv->usb_interface[i].sub_api != SUB_API_NOTSET) + available[priv->usb_interface[i].sub_api] = true; + break; + case USB_API_HID: + available[SUB_API_MAX] = true; + break; + default: + break; + } + } + + for (i = 0; i < SUB_API_MAX; i++) { // WinUSB-like drivers + if (available[i]) + usb_api_backend[USB_API_WINUSBX].close(i, dev_handle); + } + + if (available[SUB_API_MAX]) // HID driver + hid_close(SUB_API_NOTSET, dev_handle); +} + +static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) +{ + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + + return priv->usb_interface[iface].apib-> + claim_interface(priv->usb_interface[iface].sub_api, dev_handle, iface); +} + +static int composite_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting) +{ + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + + return priv->usb_interface[iface].apib-> + set_interface_altsetting(priv->usb_interface[iface].sub_api, dev_handle, iface, altsetting); +} + +static int composite_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) +{ + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + + return priv->usb_interface[iface].apib-> + release_interface(priv->usb_interface[iface].sub_api, dev_handle, iface); +} + +static int composite_submit_control_transfer(int sub_api, 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 windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + struct libusb_config_descriptor *conf_desc; + WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer; + int iface, pass, r; + + // Interface shouldn't matter for control, but it does in practice, with Windows' + // restrictions with regards to accessing HID keyboards and mice. Try to target + // a specific interface first, if possible. + switch (LIBUSB_REQ_RECIPIENT(setup->request_type)) { + case LIBUSB_RECIPIENT_INTERFACE: + iface = setup->index & 0xFF; + break; + case LIBUSB_RECIPIENT_ENDPOINT: + r = libusb_get_active_config_descriptor(transfer->dev_handle->dev, &conf_desc); + if (r == LIBUSB_SUCCESS) { + iface = get_interface_by_endpoint(conf_desc, (setup->index & 0xFF)); + libusb_free_config_descriptor(conf_desc); + break; + } + // Fall through if not able to determine interface + default: + iface = -1; + break; + } + + // Try and target a specific interface if the control setup indicates such + if ((iface >= 0) && (iface < USB_MAXINTERFACES)) { + usbi_dbg("attempting control transfer targeted to interface %d", iface); + if (priv->usb_interface[iface].path != NULL) { + r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer); + if (r == LIBUSB_SUCCESS) + return r; + } + } + + // Either not targeted to a specific interface or no luck in doing so. + // Try a 2 pass approach with all interfaces. + for (pass = 0; pass < 2; pass++) { + for (iface = 0; iface < USB_MAXINTERFACES; iface++) { + if (priv->usb_interface[iface].path != NULL) { + if ((pass == 0) && (priv->usb_interface[iface].restricted_functionality)) { + usbi_dbg("trying to skip restricted interface #%d (HID keyboard or mouse?)", iface); + continue; + } + usbi_dbg("using interface %d", iface); + r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer); + // If not supported on this API, it may be supported on another, so don't give up yet!! + if (r == LIBUSB_ERROR_NOT_SUPPORTED) + continue; + return r; + } + } + } + + usbi_err(ctx, "no libusb supported interfaces to complete request"); + return LIBUSB_ERROR_NOT_FOUND; +} + +static int composite_submit_bulk_transfer(int sub_api, 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 windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); + struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + int current_interface; + + current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); + if (current_interface < 0) { + usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); + return LIBUSB_ERROR_NOT_FOUND; + } + + return priv->usb_interface[current_interface].apib-> + submit_bulk_transfer(priv->usb_interface[current_interface].sub_api, itransfer); +} + +static int composite_submit_iso_transfer(int sub_api, 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 windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); + struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + int current_interface; + + current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); + if (current_interface < 0) { + usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); + return LIBUSB_ERROR_NOT_FOUND; + } + + return priv->usb_interface[current_interface].apib-> + submit_iso_transfer(priv->usb_interface[current_interface].sub_api, itransfer); +} + +static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + int current_interface; + + current_interface = interface_by_endpoint(priv, handle_priv, endpoint); + if (current_interface < 0) { + usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); + return LIBUSB_ERROR_NOT_FOUND; + } + + return priv->usb_interface[current_interface].apib-> + clear_halt(priv->usb_interface[current_interface].sub_api, dev_handle, endpoint); +} + +static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + + return priv->usb_interface[transfer_priv->interface_number].apib-> + abort_control(priv->usb_interface[transfer_priv->interface_number].sub_api, itransfer); +} + +static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + + return priv->usb_interface[transfer_priv->interface_number].apib-> + abort_transfers(priv->usb_interface[transfer_priv->interface_number].sub_api, itransfer); +} + +static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle) +{ + struct windows_device_priv *priv = _device_priv(dev_handle->dev); + int r; + uint8_t i; + bool available[SUB_API_MAX]; + + for (i = 0; i < SUB_API_MAX; i++) + available[i] = false; + + for (i = 0; i < USB_MAXINTERFACES; i++) { + if ((priv->usb_interface[i].apib->id == USB_API_WINUSBX) + && (priv->usb_interface[i].sub_api != SUB_API_NOTSET)) + available[priv->usb_interface[i].sub_api] = true; + } + + for (i = 0; i < SUB_API_MAX; i++) { + if (available[i]) { + r = usb_api_backend[USB_API_WINUSBX].reset_device(i, dev_handle); + if (r != LIBUSB_SUCCESS) + return r; + } + } + + return LIBUSB_SUCCESS; +} + +static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); + + return priv->usb_interface[transfer_priv->interface_number].apib-> + copy_transfer_data(priv->usb_interface[transfer_priv->interface_number].sub_api, itransfer, io_size); +} + +#endif /* !USE_USBDK */ diff --git a/Externals/libusb/libusb/os/windows_winusb.h b/Externals/libusb/libusb/os/windows_winusb.h new file mode 100644 index 0000000000..a259374b1d --- /dev/null +++ b/Externals/libusb/libusb/os/windows_winusb.h @@ -0,0 +1,948 @@ +/* + * Windows backend for libusb 1.0 + * Copyright © 2009-2012 Pete Batard + * 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 "windows_common.h" +#include "windows_nt_common.h" + +#if defined(_MSC_VER) +// disable /W4 MSVC warnings that are benign +#pragma warning(disable:4100) // unreferenced formal parameter +#pragma warning(disable:4127) // conditional expression is constant +#pragma warning(disable:4201) // nameless struct/union +#pragma warning(disable:4214) // bit field types other than int +#pragma warning(disable:4996) // deprecated API calls +#pragma warning(disable:28159) // more deprecated API calls +#endif + +// Missing from MSVC6 setupapi.h +#if !defined(SPDRP_ADDRESS) +#define SPDRP_ADDRESS 28 +#endif +#if !defined(SPDRP_INSTALL_STATE) +#define SPDRP_INSTALL_STATE 34 +#endif + +#define MAX_CTRL_BUFFER_LENGTH 4096 +#define MAX_USB_DEVICES 256 +#define MAX_USB_STRING_LENGTH 128 +#define MAX_HID_REPORT_SIZE 1024 +#define MAX_HID_DESCRIPTOR_SIZE 256 +#define MAX_GUID_STRING_LENGTH 40 +#define MAX_PATH_LENGTH 128 +#define MAX_KEY_LENGTH 256 +#define LIST_SEPARATOR ';' + +// Handle code for HID interface that have been claimed ("dibs") +#define INTERFACE_CLAIMED ((HANDLE)(intptr_t)0xD1B5) +// Additional return code for HID operations that completed synchronously +#define LIBUSB_COMPLETED (LIBUSB_SUCCESS + 1) + +// http://msdn.microsoft.com/en-us/library/ff545978.aspx +// http://msdn.microsoft.com/en-us/library/ff545972.aspx +// http://msdn.microsoft.com/en-us/library/ff545982.aspx +#if !defined(GUID_DEVINTERFACE_USB_HOST_CONTROLLER) +const GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER = { 0x3ABF6F2D, 0x71C4, 0x462A, {0x8A, 0x92, 0x1E, 0x68, 0x61, 0xE6, 0xAF, 0x27} }; +#endif +#if !defined(GUID_DEVINTERFACE_USB_DEVICE) +const GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED} }; +#endif +#if !defined(GUID_DEVINTERFACE_USB_HUB) +const GUID GUID_DEVINTERFACE_USB_HUB = { 0xF18A0E88, 0xC30C, 0x11D0, {0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8} }; +#endif +#if !defined(GUID_DEVINTERFACE_LIBUSB0_FILTER) +const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = { 0xF9F3FF14, 0xAE21, 0x48A0, {0x8A, 0x25, 0x80, 0x11, 0xA7, 0xA9, 0x31, 0xD9} }; +#endif + + +/* + * Multiple USB API backend support + */ +#define USB_API_UNSUPPORTED 0 +#define USB_API_HUB 1 +#define USB_API_COMPOSITE 2 +#define USB_API_WINUSBX 3 +#define USB_API_HID 4 +#define USB_API_MAX 5 +// The following is used to indicate if the HID or composite extra props have already been set. +#define USB_API_SET (1 << USB_API_MAX) + +// Sub-APIs for WinUSB-like driver APIs (WinUSB, libusbK, libusb-win32 through the libusbK DLL) +// Must have the same values as the KUSB_DRVID enum from libusbk.h +#define SUB_API_NOTSET -1 +#define SUB_API_LIBUSBK 0 +#define SUB_API_LIBUSB0 1 +#define SUB_API_WINUSB 2 +#define SUB_API_MAX 3 + +#define WINUSBX_DRV_NAMES {"libusbK", "libusb0", "WinUSB"} + +struct windows_usb_api_backend { + const uint8_t id; + const char *designation; + const char **driver_name_list; // Driver name, without .sys, e.g. "usbccgp" + const uint8_t nb_driver_names; + int (*init)(int sub_api, struct libusb_context *ctx); + int (*exit)(int sub_api); + int (*open)(int sub_api, struct libusb_device_handle *dev_handle); + void (*close)(int sub_api, struct libusb_device_handle *dev_handle); + int (*configure_endpoints)(int sub_api, struct libusb_device_handle *dev_handle, int iface); + int (*claim_interface)(int sub_api, struct libusb_device_handle *dev_handle, int iface); + int (*set_interface_altsetting)(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting); + int (*release_interface)(int sub_api, struct libusb_device_handle *dev_handle, int iface); + int (*clear_halt)(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint); + int (*reset_device)(int sub_api, struct libusb_device_handle *dev_handle); + int (*submit_bulk_transfer)(int sub_api, struct usbi_transfer *itransfer); + int (*submit_iso_transfer)(int sub_api, struct usbi_transfer *itransfer); + int (*submit_control_transfer)(int sub_api, struct usbi_transfer *itransfer); + int (*abort_control)(int sub_api, struct usbi_transfer *itransfer); + int (*abort_transfers)(int sub_api, struct usbi_transfer *itransfer); + int (*copy_transfer_data)(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size); +}; + +extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX]; + +#define PRINT_UNSUPPORTED_API(fname) \ + usbi_dbg("unsupported API call for '" \ + #fname "' (unrecognized device driver)"); \ + return LIBUSB_ERROR_NOT_SUPPORTED; + +/* + * private structures definition + * with inline pseudo constructors/destructors + */ + +// TODO (v2+): move hid desc to libusb.h? +struct libusb_hid_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdHID; + uint8_t bCountryCode; + uint8_t bNumDescriptors; + uint8_t bClassDescriptorType; + uint16_t wClassDescriptorLength; +}; + +#define LIBUSB_DT_HID_SIZE 9 +#define HID_MAX_CONFIG_DESC_SIZE (LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE \ + + LIBUSB_DT_HID_SIZE + 2 * LIBUSB_DT_ENDPOINT_SIZE) +#define HID_MAX_REPORT_SIZE 1024 +#define HID_IN_EP 0x81 +#define HID_OUT_EP 0x02 +#define LIBUSB_REQ_RECIPIENT(request_type) ((request_type) & 0x1F) +#define LIBUSB_REQ_TYPE(request_type) ((request_type) & (0x03 << 5)) +#define LIBUSB_REQ_IN(request_type) ((request_type) & LIBUSB_ENDPOINT_IN) +#define LIBUSB_REQ_OUT(request_type) (!LIBUSB_REQ_IN(request_type)) + +// The following are used for HID reports IOCTLs +#define HID_CTL_CODE(id) \ + CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_NEITHER, FILE_ANY_ACCESS) +#define HID_BUFFER_CTL_CODE(id) \ + CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_BUFFERED, FILE_ANY_ACCESS) +#define HID_IN_CTL_CODE(id) \ + CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_IN_DIRECT, FILE_ANY_ACCESS) +#define HID_OUT_CTL_CODE(id) \ + CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS) + +#define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100) +#define IOCTL_HID_GET_INPUT_REPORT HID_OUT_CTL_CODE(104) +#define IOCTL_HID_SET_FEATURE HID_IN_CTL_CODE(100) +#define IOCTL_HID_SET_OUTPUT_REPORT HID_IN_CTL_CODE(101) + +enum libusb_hid_request_type { + HID_REQ_GET_REPORT = 0x01, + HID_REQ_GET_IDLE = 0x02, + HID_REQ_GET_PROTOCOL = 0x03, + HID_REQ_SET_REPORT = 0x09, + HID_REQ_SET_IDLE = 0x0A, + HID_REQ_SET_PROTOCOL = 0x0B +}; + +enum libusb_hid_report_type { + HID_REPORT_TYPE_INPUT = 0x01, + HID_REPORT_TYPE_OUTPUT = 0x02, + HID_REPORT_TYPE_FEATURE = 0x03 +}; + +struct hid_device_priv { + uint16_t vid; + uint16_t pid; + uint8_t config; + uint8_t nb_interfaces; + bool uses_report_ids[3]; // input, ouptput, feature + uint16_t input_report_size; + uint16_t output_report_size; + uint16_t feature_report_size; + WCHAR string[3][MAX_USB_STRING_LENGTH]; + uint8_t string_index[3]; // man, prod, ser +}; + +struct windows_device_priv { + uint8_t depth; // distance to HCD + uint8_t port; // port number on the hub + uint8_t active_config; + struct windows_usb_api_backend const *apib; + char *path; // device interface path + int sub_api; // for WinUSB-like APIs + struct { + char *path; // each interface needs a device interface path, + struct windows_usb_api_backend const *apib; // an API backend (multiple drivers support), + int sub_api; + int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS) + uint8_t *endpoint; + bool restricted_functionality; // indicates if the interface functionality is restricted + // by Windows (eg. HID keyboards or mice cannot do R/W) + } usb_interface[USB_MAXINTERFACES]; + struct hid_device_priv *hid; + USB_DEVICE_DESCRIPTOR dev_descriptor; + unsigned char **config_descriptor; // list of pointers to the cached config descriptors +}; + +static inline struct windows_device_priv *_device_priv(struct libusb_device *dev) +{ + return (struct windows_device_priv *)dev->os_priv; +} + +static inline struct windows_device_priv *windows_device_priv_init(struct libusb_device *dev) +{ + struct windows_device_priv *p = _device_priv(dev); + int i; + + p->depth = 0; + p->port = 0; + p->path = NULL; + p->apib = &usb_api_backend[USB_API_UNSUPPORTED]; + p->sub_api = SUB_API_NOTSET; + p->hid = NULL; + p->active_config = 0; + p->config_descriptor = NULL; + memset(&p->dev_descriptor, 0, sizeof(USB_DEVICE_DESCRIPTOR)); + for (i = 0; i < USB_MAXINTERFACES; i++) { + p->usb_interface[i].path = NULL; + p->usb_interface[i].apib = &usb_api_backend[USB_API_UNSUPPORTED]; + p->usb_interface[i].sub_api = SUB_API_NOTSET; + p->usb_interface[i].nb_endpoints = 0; + p->usb_interface[i].endpoint = NULL; + p->usb_interface[i].restricted_functionality = false; + } + + return p; +} + +static inline void windows_device_priv_release(struct libusb_device *dev) +{ + struct windows_device_priv *p = _device_priv(dev); + int i; + + safe_free(p->path); + if ((dev->num_configurations > 0) && (p->config_descriptor != NULL)) { + for (i = 0; i < dev->num_configurations; i++) + safe_free(p->config_descriptor[i]); + } + safe_free(p->config_descriptor); + safe_free(p->hid); + for (i = 0; i < USB_MAXINTERFACES; i++) { + safe_free(p->usb_interface[i].path); + safe_free(p->usb_interface[i].endpoint); + } +} + +struct interface_handle_t { + HANDLE dev_handle; // WinUSB needs an extra handle for the file + HANDLE api_handle; // used by the API to communicate with the device +}; + +struct windows_device_handle_priv { + int active_interface; + struct interface_handle_t interface_handle[USB_MAXINTERFACES]; + int autoclaim_count[USB_MAXINTERFACES]; // For auto-release +}; + +static inline struct windows_device_handle_priv *_device_handle_priv( + struct libusb_device_handle *handle) +{ + return (struct windows_device_handle_priv *)handle->os_priv; +} + +// used for async polling functions +struct windows_transfer_priv { + struct winfd pollable_fd; + uint8_t interface_number; + uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID + uint8_t *hid_dest; // transfer buffer destination, required for HID + size_t hid_expected_size; +}; + +// used to match a device driver (including filter drivers) against a supported API +struct driver_lookup { + char list[MAX_KEY_LENGTH + 1]; // REG_MULTI_SZ list of services (driver) names + const DWORD reg_prop; // SPDRP registry key to use to retrieve list + const char* designation; // internal designation (for debug output) +}; + +/* OLE32 dependency */ +DLL_DECLARE_HANDLE(OLE32); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, HRESULT, p, CLSIDFromString, (LPCOLESTR, LPCLSID)); + +/* Kernel32 dependencies */ +DLL_DECLARE_HANDLE(Kernel32); +/* This call is only available from XP SP2 */ +DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, IsWow64Process, (HANDLE, PBOOL)); + +/* SetupAPI dependencies */ +DLL_DECLARE_HANDLE(SetupAPI); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (const GUID*, PCSTR, HWND, DWORD)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInfo, (HDEVINFO, DWORD, PSP_DEVINFO_DATA)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInterfaces, (HDEVINFO, PSP_DEVINFO_DATA, + const GUID*, DWORD, PSP_DEVICE_INTERFACE_DATA)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInterfaceDetailA, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, + PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiDestroyDeviceInfoList, (HDEVINFO)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO, + PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDeviceInterfaceRegKey, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, DWORD, DWORD)); + +/* AdvAPI32 dependencies */ +DLL_DECLARE_HANDLE(AdvAPI32); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegQueryValueExW, (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegCloseKey, (HKEY)); + +/* + * Windows DDK API definitions. Most of it copied from MinGW's includes + */ +typedef DWORD DEVNODE, DEVINST; +typedef DEVNODE *PDEVNODE, *PDEVINST; +typedef DWORD RETURN_TYPE; +typedef RETURN_TYPE CONFIGRET; + +#define CR_SUCCESS 0x00000000 +#define CR_NO_SUCH_DEVNODE 0x0000000D + +#define USB_DEVICE_DESCRIPTOR_TYPE LIBUSB_DT_DEVICE +#define USB_CONFIGURATION_DESCRIPTOR_TYPE LIBUSB_DT_CONFIG +#define USB_STRING_DESCRIPTOR_TYPE LIBUSB_DT_STRING +#define USB_INTERFACE_DESCRIPTOR_TYPE LIBUSB_DT_INTERFACE +#define USB_ENDPOINT_DESCRIPTOR_TYPE LIBUSB_DT_ENDPOINT + +#define USB_REQUEST_GET_STATUS LIBUSB_REQUEST_GET_STATUS +#define USB_REQUEST_CLEAR_FEATURE LIBUSB_REQUEST_CLEAR_FEATURE +#define USB_REQUEST_SET_FEATURE LIBUSB_REQUEST_SET_FEATURE +#define USB_REQUEST_SET_ADDRESS LIBUSB_REQUEST_SET_ADDRESS +#define USB_REQUEST_GET_DESCRIPTOR LIBUSB_REQUEST_GET_DESCRIPTOR +#define USB_REQUEST_SET_DESCRIPTOR LIBUSB_REQUEST_SET_DESCRIPTOR +#define USB_REQUEST_GET_CONFIGURATION LIBUSB_REQUEST_GET_CONFIGURATION +#define USB_REQUEST_SET_CONFIGURATION LIBUSB_REQUEST_SET_CONFIGURATION +#define USB_REQUEST_GET_INTERFACE LIBUSB_REQUEST_GET_INTERFACE +#define USB_REQUEST_SET_INTERFACE LIBUSB_REQUEST_SET_INTERFACE +#define USB_REQUEST_SYNC_FRAME LIBUSB_REQUEST_SYNCH_FRAME + +#define USB_GET_NODE_INFORMATION 258 +#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260 +#define USB_GET_NODE_CONNECTION_NAME 261 +#define USB_GET_HUB_CAPABILITIES 271 +#if !defined(USB_GET_NODE_CONNECTION_INFORMATION_EX) +#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274 +#endif +#if !defined(USB_GET_HUB_CAPABILITIES_EX) +#define USB_GET_HUB_CAPABILITIES_EX 276 +#endif +#if !defined(USB_GET_NODE_CONNECTION_INFORMATION_EX_V2) +#define USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 279 +#endif + +#ifndef METHOD_BUFFERED +#define METHOD_BUFFERED 0 +#endif +#ifndef FILE_ANY_ACCESS +#define FILE_ANY_ACCESS 0x00000000 +#endif +#ifndef FILE_DEVICE_UNKNOWN +#define FILE_DEVICE_UNKNOWN 0x00000022 +#endif +#ifndef FILE_DEVICE_USB +#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN +#endif + +#ifndef CTL_CODE +#define CTL_CODE(DeviceType, Function, Method, Access) \ + (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) +#endif + +typedef enum USB_CONNECTION_STATUS { + NoDeviceConnected, + DeviceConnected, + DeviceFailedEnumeration, + DeviceGeneralFailure, + DeviceCausedOvercurrent, + DeviceNotEnoughPower, + DeviceNotEnoughBandwidth, + DeviceHubNestedTooDeeply, + DeviceInLegacyHub +} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS; + +typedef enum USB_HUB_NODE { + UsbHub, + UsbMIParent +} USB_HUB_NODE; + +/* Cfgmgr32.dll interface */ +DLL_DECLARE_HANDLE(Cfgmgr32); +DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG)); +DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG)); +DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Sibling, (PDEVINST, DEVINST, ULONG)); +DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Device_IDA, (DEVINST, PCHAR, ULONG, ULONG)); + +#define IOCTL_USB_GET_HUB_CAPABILITIES_EX \ + CTL_CODE( FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES_EX, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_HUB_CAPABILITIES \ + CTL_CODE(FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \ + CTL_CODE(FILE_DEVICE_USB, USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_ROOT_HUB_NAME \ + CTL_CODE(FILE_DEVICE_USB, HCD_GET_ROOT_HUB_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_NODE_INFORMATION \ + CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \ + CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 \ + CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX_V2, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES \ + CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_ATTRIBUTES, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_NODE_CONNECTION_NAME \ + CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// Most of the structures below need to be packed +#pragma pack(push, 1) + +typedef struct USB_INTERFACE_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bInterfaceNumber; + UCHAR bAlternateSetting; + UCHAR bNumEndpoints; + UCHAR bInterfaceClass; + UCHAR bInterfaceSubClass; + UCHAR bInterfaceProtocol; + UCHAR iInterface; +} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR; + +typedef struct USB_CONFIGURATION_DESCRIPTOR_SHORT { + struct { + ULONG ConnectionIndex; + struct { + UCHAR bmRequest; + UCHAR bRequest; + USHORT wValue; + USHORT wIndex; + USHORT wLength; + } SetupPacket; + } req; + USB_CONFIGURATION_DESCRIPTOR data; +} USB_CONFIGURATION_DESCRIPTOR_SHORT; + +typedef struct USB_ENDPOINT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bEndpointAddress; + UCHAR bmAttributes; + USHORT wMaxPacketSize; + UCHAR bInterval; +} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR; + +typedef struct USB_DESCRIPTOR_REQUEST { + ULONG ConnectionIndex; + struct { + UCHAR bmRequest; + UCHAR bRequest; + USHORT wValue; + USHORT wIndex; + USHORT wLength; + } SetupPacket; +// UCHAR Data[0]; +} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST; + +typedef struct USB_HUB_DESCRIPTOR { + UCHAR bDescriptorLength; + UCHAR bDescriptorType; + UCHAR bNumberOfPorts; + USHORT wHubCharacteristics; + UCHAR bPowerOnToPowerGood; + UCHAR bHubControlCurrent; + UCHAR bRemoveAndPowerMask[64]; +} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR; + +typedef struct USB_ROOT_HUB_NAME { + ULONG ActualLength; + WCHAR RootHubName[1]; +} USB_ROOT_HUB_NAME, *PUSB_ROOT_HUB_NAME; + +typedef struct USB_ROOT_HUB_NAME_FIXED { + ULONG ActualLength; + WCHAR RootHubName[MAX_PATH_LENGTH]; +} USB_ROOT_HUB_NAME_FIXED; + +typedef struct USB_NODE_CONNECTION_NAME { + ULONG ConnectionIndex; + ULONG ActualLength; + WCHAR NodeName[1]; +} USB_NODE_CONNECTION_NAME, *PUSB_NODE_CONNECTION_NAME; + +typedef struct USB_NODE_CONNECTION_NAME_FIXED { + ULONG ConnectionIndex; + ULONG ActualLength; + WCHAR NodeName[MAX_PATH_LENGTH]; +} USB_NODE_CONNECTION_NAME_FIXED; + +typedef struct USB_HUB_NAME_FIXED { + union { + USB_ROOT_HUB_NAME_FIXED root; + USB_NODE_CONNECTION_NAME_FIXED node; + } u; +} USB_HUB_NAME_FIXED; + +typedef struct USB_HUB_INFORMATION { + USB_HUB_DESCRIPTOR HubDescriptor; + BOOLEAN HubIsBusPowered; +} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION; + +typedef struct USB_MI_PARENT_INFORMATION { + ULONG NumberOfInterfaces; +} USB_MI_PARENT_INFORMATION, *PUSB_MI_PARENT_INFORMATION; + +typedef struct USB_NODE_INFORMATION { + USB_HUB_NODE NodeType; + union { + USB_HUB_INFORMATION HubInformation; + USB_MI_PARENT_INFORMATION MiParentInformation; + } u; +} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION; + +typedef struct USB_PIPE_INFO { + USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + ULONG ScheduleOffset; +} USB_PIPE_INFO, *PUSB_PIPE_INFO; + +typedef struct USB_NODE_CONNECTION_INFORMATION_EX { + ULONG ConnectionIndex; + USB_DEVICE_DESCRIPTOR DeviceDescriptor; + UCHAR CurrentConfigurationValue; + UCHAR Speed; + BOOLEAN DeviceIsHub; + USHORT DeviceAddress; + ULONG NumberOfOpenPipes; + USB_CONNECTION_STATUS ConnectionStatus; +// USB_PIPE_INFO PipeList[0]; +} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; + +typedef union _USB_PROTOCOLS { + ULONG ul; + struct { + ULONG Usb110:1; + ULONG Usb200:1; + ULONG Usb300:1; + ULONG ReservedMBZ:29; + }; +} USB_PROTOCOLS, *PUSB_PROTOCOLS; + +typedef union _USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS { + ULONG ul; + struct { + ULONG DeviceIsOperatingAtSuperSpeedOrHigher:1; + ULONG DeviceIsSuperSpeedCapableOrHigher:1; + ULONG ReservedMBZ:30; + }; +} USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS, *PUSB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS; + +typedef struct _USB_NODE_CONNECTION_INFORMATION_EX_V2 { + ULONG ConnectionIndex; + ULONG Length; + USB_PROTOCOLS SupportedUsbProtocols; + USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS Flags; +} USB_NODE_CONNECTION_INFORMATION_EX_V2, *PUSB_NODE_CONNECTION_INFORMATION_EX_V2; + +typedef struct USB_HUB_CAP_FLAGS { + ULONG HubIsHighSpeedCapable:1; + ULONG HubIsHighSpeed:1; + ULONG HubIsMultiTtCapable:1; + ULONG HubIsMultiTt:1; + ULONG HubIsRoot:1; + ULONG HubIsArmedWakeOnConnect:1; + ULONG ReservedMBZ:26; +} USB_HUB_CAP_FLAGS, *PUSB_HUB_CAP_FLAGS; + +typedef struct USB_HUB_CAPABILITIES { + ULONG HubIs2xCapable:1; +} USB_HUB_CAPABILITIES, *PUSB_HUB_CAPABILITIES; + +typedef struct USB_HUB_CAPABILITIES_EX { + USB_HUB_CAP_FLAGS CapabilityFlags; +} USB_HUB_CAPABILITIES_EX, *PUSB_HUB_CAPABILITIES_EX; + +#pragma pack(pop) + +/* winusb.dll interface */ + +#define SHORT_PACKET_TERMINATE 0x01 +#define AUTO_CLEAR_STALL 0x02 +#define PIPE_TRANSFER_TIMEOUT 0x03 +#define IGNORE_SHORT_PACKETS 0x04 +#define ALLOW_PARTIAL_READS 0x05 +#define AUTO_FLUSH 0x06 +#define RAW_IO 0x07 +#define MAXIMUM_TRANSFER_SIZE 0x08 +#define AUTO_SUSPEND 0x81 +#define SUSPEND_DELAY 0x83 +#define DEVICE_SPEED 0x01 +#define LowSpeed 0x01 +#define FullSpeed 0x02 +#define HighSpeed 0x03 + +typedef enum USBD_PIPE_TYPE { + UsbdPipeTypeControl, + UsbdPipeTypeIsochronous, + UsbdPipeTypeBulk, + UsbdPipeTypeInterrupt +} USBD_PIPE_TYPE; + +typedef struct { + USBD_PIPE_TYPE PipeType; + UCHAR PipeId; + USHORT MaximumPacketSize; + UCHAR Interval; +} WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION; + +#pragma pack(1) +typedef struct { + UCHAR request_type; + UCHAR request; + USHORT value; + USHORT index; + USHORT length; +} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET; +#pragma pack() + +typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE; + +typedef BOOL (WINAPI *WinUsb_AbortPipe_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR PipeID +); +typedef BOOL (WINAPI *WinUsb_ControlTransfer_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + WINUSB_SETUP_PACKET SetupPacket, + PUCHAR Buffer, + ULONG BufferLength, + PULONG LengthTransferred, + LPOVERLAPPED Overlapped +); +typedef BOOL (WINAPI *WinUsb_FlushPipe_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR PipeID +); +typedef BOOL (WINAPI *WinUsb_Free_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle +); +typedef BOOL (WINAPI *WinUsb_GetAssociatedInterface_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR AssociatedInterfaceIndex, + PWINUSB_INTERFACE_HANDLE AssociatedInterfaceHandle +); +typedef BOOL (WINAPI *WinUsb_GetCurrentAlternateSetting_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + PUCHAR AlternateSetting +); +typedef BOOL (WINAPI *WinUsb_GetDescriptor_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR DescriptorType, + UCHAR Index, + USHORT LanguageID, + PUCHAR Buffer, + ULONG BufferLength, + PULONG LengthTransferred +); +typedef BOOL (WINAPI *WinUsb_GetOverlappedResult_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + LPOVERLAPPED lpOverlapped, + LPDWORD lpNumberOfBytesTransferred, + BOOL bWait +); +typedef BOOL (WINAPI *WinUsb_GetPipePolicy_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR PipeID, + ULONG PolicyType, + PULONG ValueLength, + PVOID Value +); +typedef BOOL (WINAPI *WinUsb_GetPowerPolicy_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + ULONG PolicyType, + PULONG ValueLength, + PVOID Value +); +typedef BOOL (WINAPI *WinUsb_Initialize_t)( + HANDLE DeviceHandle, + PWINUSB_INTERFACE_HANDLE InterfaceHandle +); +typedef BOOL (WINAPI *WinUsb_QueryDeviceInformation_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + ULONG InformationType, + PULONG BufferLength, + PVOID Buffer +); +typedef BOOL (WINAPI *WinUsb_QueryInterfaceSettings_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR AlternateSettingNumber, + PUSB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor +); +typedef BOOL (WINAPI *WinUsb_QueryPipe_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR AlternateInterfaceNumber, + UCHAR PipeIndex, + PWINUSB_PIPE_INFORMATION PipeInformation +); +typedef BOOL (WINAPI *WinUsb_ReadPipe_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR PipeID, + PUCHAR Buffer, + ULONG BufferLength, + PULONG LengthTransferred, + LPOVERLAPPED Overlapped +); +typedef BOOL (WINAPI *WinUsb_ResetPipe_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR PipeID +); +typedef BOOL (WINAPI *WinUsb_SetCurrentAlternateSetting_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR AlternateSetting +); +typedef BOOL (WINAPI *WinUsb_SetPipePolicy_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR PipeID, + ULONG PolicyType, + ULONG ValueLength, + PVOID Value +); +typedef BOOL (WINAPI *WinUsb_SetPowerPolicy_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + ULONG PolicyType, + ULONG ValueLength, + PVOID Value +); +typedef BOOL (WINAPI *WinUsb_WritePipe_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR PipeID, + PUCHAR Buffer, + ULONG BufferLength, + PULONG LengthTransferred, + LPOVERLAPPED Overlapped +); +typedef BOOL (WINAPI *WinUsb_ResetDevice_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle +); + +/* /!\ These must match the ones from the official libusbk.h */ +typedef enum _KUSB_FNID { + KUSB_FNID_Init, + KUSB_FNID_Free, + KUSB_FNID_ClaimInterface, + KUSB_FNID_ReleaseInterface, + KUSB_FNID_SetAltInterface, + KUSB_FNID_GetAltInterface, + KUSB_FNID_GetDescriptor, + KUSB_FNID_ControlTransfer, + KUSB_FNID_SetPowerPolicy, + KUSB_FNID_GetPowerPolicy, + KUSB_FNID_SetConfiguration, + KUSB_FNID_GetConfiguration, + KUSB_FNID_ResetDevice, + KUSB_FNID_Initialize, + KUSB_FNID_SelectInterface, + KUSB_FNID_GetAssociatedInterface, + KUSB_FNID_Clone, + KUSB_FNID_QueryInterfaceSettings, + KUSB_FNID_QueryDeviceInformation, + KUSB_FNID_SetCurrentAlternateSetting, + KUSB_FNID_GetCurrentAlternateSetting, + KUSB_FNID_QueryPipe, + KUSB_FNID_SetPipePolicy, + KUSB_FNID_GetPipePolicy, + KUSB_FNID_ReadPipe, + KUSB_FNID_WritePipe, + KUSB_FNID_ResetPipe, + KUSB_FNID_AbortPipe, + KUSB_FNID_FlushPipe, + KUSB_FNID_IsoReadPipe, + KUSB_FNID_IsoWritePipe, + KUSB_FNID_GetCurrentFrameNumber, + KUSB_FNID_GetOverlappedResult, + KUSB_FNID_GetProperty, + KUSB_FNID_COUNT, +} KUSB_FNID; + +typedef struct _KLIB_VERSION { + INT Major; + INT Minor; + INT Micro; + INT Nano; +} KLIB_VERSION; +typedef KLIB_VERSION* PKLIB_VERSION; + +typedef BOOL (WINAPI *LibK_GetProcAddress_t)( + PVOID *ProcAddress, + ULONG DriverID, + ULONG FunctionID +); + +typedef VOID (WINAPI *LibK_GetVersion_t)( + PKLIB_VERSION Version +); + +struct winusb_interface { + bool initialized; + WinUsb_AbortPipe_t AbortPipe; + WinUsb_ControlTransfer_t ControlTransfer; + WinUsb_FlushPipe_t FlushPipe; + WinUsb_Free_t Free; + WinUsb_GetAssociatedInterface_t GetAssociatedInterface; + WinUsb_GetCurrentAlternateSetting_t GetCurrentAlternateSetting; + WinUsb_GetDescriptor_t GetDescriptor; + WinUsb_GetOverlappedResult_t GetOverlappedResult; + WinUsb_GetPipePolicy_t GetPipePolicy; + WinUsb_GetPowerPolicy_t GetPowerPolicy; + WinUsb_Initialize_t Initialize; + WinUsb_QueryDeviceInformation_t QueryDeviceInformation; + WinUsb_QueryInterfaceSettings_t QueryInterfaceSettings; + WinUsb_QueryPipe_t QueryPipe; + WinUsb_ReadPipe_t ReadPipe; + WinUsb_ResetPipe_t ResetPipe; + WinUsb_SetCurrentAlternateSetting_t SetCurrentAlternateSetting; + WinUsb_SetPipePolicy_t SetPipePolicy; + WinUsb_SetPowerPolicy_t SetPowerPolicy; + WinUsb_WritePipe_t WritePipe; + WinUsb_ResetDevice_t ResetDevice; +}; + +/* hid.dll interface */ + +#define HIDP_STATUS_SUCCESS 0x110000 +typedef void * PHIDP_PREPARSED_DATA; + +#pragma pack(1) +typedef struct { + ULONG Size; + USHORT VendorID; + USHORT ProductID; + USHORT VersionNumber; +} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES; +#pragma pack() + +typedef USHORT USAGE; +typedef struct { + USAGE Usage; + USAGE UsagePage; + USHORT InputReportByteLength; + USHORT OutputReportByteLength; + USHORT FeatureReportByteLength; + USHORT Reserved[17]; + USHORT NumberLinkCollectionNodes; + USHORT NumberInputButtonCaps; + USHORT NumberInputValueCaps; + USHORT NumberInputDataIndices; + USHORT NumberOutputButtonCaps; + USHORT NumberOutputValueCaps; + USHORT NumberOutputDataIndices; + USHORT NumberFeatureButtonCaps; + USHORT NumberFeatureValueCaps; + USHORT NumberFeatureDataIndices; +} HIDP_CAPS, *PHIDP_CAPS; + +typedef enum _HIDP_REPORT_TYPE { + HidP_Input, + HidP_Output, + HidP_Feature +} HIDP_REPORT_TYPE; + +typedef struct _HIDP_VALUE_CAPS { + USAGE UsagePage; + UCHAR ReportID; + BOOLEAN IsAlias; + USHORT BitField; + USHORT LinkCollection; + USAGE LinkUsage; + USAGE LinkUsagePage; + BOOLEAN IsRange; + BOOLEAN IsStringRange; + BOOLEAN IsDesignatorRange; + BOOLEAN IsAbsolute; + BOOLEAN HasNull; + UCHAR Reserved; + USHORT BitSize; + USHORT ReportCount; + USHORT Reserved2[5]; + ULONG UnitsExp; + ULONG Units; + LONG LogicalMin, LogicalMax; + LONG PhysicalMin, PhysicalMax; + union { + struct { + USAGE UsageMin, UsageMax; + USHORT StringMin, StringMax; + USHORT DesignatorMin, DesignatorMax; + USHORT DataIndexMin, DataIndexMax; + } Range; + struct { + USAGE Usage, Reserved1; + USHORT StringIndex, Reserved2; + USHORT DesignatorIndex, Reserved3; + USHORT DataIndex, Reserved4; + } NotRange; + } u; +} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS; + +DLL_DECLARE_HANDLE(hid); +DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetAttributes, (HANDLE, PHIDD_ATTRIBUTES)); +DLL_DECLARE_FUNC(WINAPI, VOID, HidD_GetHidGuid, (LPGUID)); +DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetPreparsedData, (HANDLE, PHIDP_PREPARSED_DATA *)); +DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_FreePreparsedData, (PHIDP_PREPARSED_DATA)); +DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetManufacturerString, (HANDLE, PVOID, ULONG)); +DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetProductString, (HANDLE, PVOID, ULONG)); +DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetSerialNumberString, (HANDLE, PVOID, ULONG)); +DLL_DECLARE_FUNC(WINAPI, LONG, HidP_GetCaps, (PHIDP_PREPARSED_DATA, PHIDP_CAPS)); +DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetNumInputBuffers, (HANDLE, ULONG)); +DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetFeature, (HANDLE, PVOID, ULONG)); +DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetFeature, (HANDLE, PVOID, ULONG)); +DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetPhysicalDescriptor, (HANDLE, PVOID, ULONG)); +DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetInputReport, (HANDLE, PVOID, ULONG)); +DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetOutputReport, (HANDLE, PVOID, ULONG)); +DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_FlushQueue, (HANDLE)); +DLL_DECLARE_FUNC(WINAPI, BOOL, HidP_GetValueCaps, (HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PULONG, PHIDP_PREPARSED_DATA)); \ No newline at end of file diff --git a/Externals/libusb/libusb/strerror.c b/Externals/libusb/libusb/strerror.c index a534041a6a..d2be0e2a00 100644 --- a/Externals/libusb/libusb/strerror.c +++ b/Externals/libusb/libusb/strerror.c @@ -34,7 +34,7 @@ static size_t usbi_locale = 0; -/** \ingroup misc +/** \ingroup libusb_misc * How to add a new \ref libusb_strerror() translation: *
    *
  1. Download the latest \c strerror.c from:
    @@ -125,7 +125,7 @@ static const char* usbi_localized_errors[ARRAYSIZE(usbi_locale_supported)][LIBUS } }; -/** \ingroup misc +/** \ingroup libusb_misc * Set the language, and only the language, not the encoding! used for * translatable libusb messages. * @@ -176,7 +176,7 @@ int API_EXPORTED libusb_setlocale(const char *locale) return LIBUSB_SUCCESS; } -/** \ingroup misc +/** \ingroup libusb_misc * Returns a constant string with a short description of the given error code, * this description is intended for displaying to the end user and will be in * the language set by libusb_setlocale(). diff --git a/Externals/libusb/libusb/sync.c b/Externals/libusb/libusb/sync.c index 61a8b9cecd..a609f65f44 100644 --- a/Externals/libusb/libusb/sync.c +++ b/Externals/libusb/libusb/sync.c @@ -27,11 +27,11 @@ #include "libusbi.h" /** - * @defgroup syncio Synchronous device I/O + * @defgroup libusb_syncio Synchronous device I/O * * This page documents libusb's synchronous (blocking) API for USB device I/O. * This interface is easy to use but has some limitations. More advanced users - * may wish to consider using the \ref asyncio "asynchronous I/O API" instead. + * may wish to consider using the \ref libusb_asyncio "asynchronous I/O API" instead. */ static void LIBUSB_CALL sync_transfer_cb(struct libusb_transfer *transfer) @@ -60,7 +60,7 @@ static void sync_transfer_wait_for_completion(struct libusb_transfer *transfer) } } -/** \ingroup syncio +/** \ingroup libusb_syncio * Perform a USB control transfer. * * The direction of the transfer is inferred from the bmRequestType field of @@ -86,17 +86,24 @@ static void sync_transfer_wait_for_completion(struct libusb_transfer *transfer) * \returns LIBUSB_ERROR_PIPE if the control request was not supported by the * device * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns LIBUSB_ERROR_BUSY if called from event handling context + * \returns LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than + * the operating system and/or hardware can support * \returns another LIBUSB_ERROR code on other failures */ int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data, uint16_t wLength, unsigned int timeout) { - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer; unsigned char *buffer; int completed = 0; int r; + if (usbi_handling_events(HANDLE_CTX(dev_handle))) + return LIBUSB_ERROR_BUSY; + + transfer = libusb_alloc_transfer(0); if (!transfer) return LIBUSB_ERROR_NO_MEM; @@ -160,10 +167,14 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle, unsigned char endpoint, unsigned char *buffer, int length, int *transferred, unsigned int timeout, unsigned char type) { - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer; int completed = 0; int r; + if (usbi_handling_events(HANDLE_CTX(dev_handle))) + return LIBUSB_ERROR_BUSY; + + transfer = libusb_alloc_transfer(0); if (!transfer) return LIBUSB_ERROR_NO_MEM; @@ -179,7 +190,9 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle, sync_transfer_wait_for_completion(transfer); - *transferred = transfer->actual_length; + if (transferred) + *transferred = transfer->actual_length; + switch (transfer->status) { case LIBUSB_TRANSFER_COMPLETED: r = 0; @@ -210,7 +223,7 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle, return r; } -/** \ingroup syncio +/** \ingroup libusb_syncio * Perform a USB bulk transfer. The direction of the transfer is inferred from * the direction bits of the endpoint address. * @@ -236,7 +249,9 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle, * \param length for bulk writes, the number of bytes from data to be sent. for * bulk reads, the maximum number of bytes to receive into the data buffer. * \param transferred output location for the number of bytes actually - * transferred. + * transferred. Since version 1.0.21 (\ref LIBUSB_API_VERSION >= 0x01000105), + * it is legal to pass a NULL pointer if you do not wish to receive this + * information. * \param timeout timeout (in millseconds) that this function should wait * before giving up due to no response being received. For an unlimited * timeout, use value 0. @@ -246,8 +261,9 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle, * transferred) * \returns LIBUSB_ERROR_PIPE if the endpoint halted * \returns LIBUSB_ERROR_OVERFLOW if the device offered more data, see - * \ref packetoverflow + * \ref libusb_packetoverflow * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns LIBUSB_ERROR_BUSY if called from event handling context * \returns another LIBUSB_ERROR code on other failures */ int API_EXPORTED libusb_bulk_transfer(struct libusb_device_handle *dev_handle, @@ -258,7 +274,7 @@ int API_EXPORTED libusb_bulk_transfer(struct libusb_device_handle *dev_handle, transferred, timeout, LIBUSB_TRANSFER_TYPE_BULK); } -/** \ingroup syncio +/** \ingroup libusb_syncio * Perform a USB interrupt transfer. The direction of the transfer is inferred * from the direction bits of the endpoint address. * @@ -286,7 +302,9 @@ int API_EXPORTED libusb_bulk_transfer(struct libusb_device_handle *dev_handle, * \param length for bulk writes, the number of bytes from data to be sent. for * bulk reads, the maximum number of bytes to receive into the data buffer. * \param transferred output location for the number of bytes actually - * transferred. + * transferred. Since version 1.0.21 (\ref LIBUSB_API_VERSION >= 0x01000105), + * it is legal to pass a NULL pointer if you do not wish to receive this + * information. * \param timeout timeout (in millseconds) that this function should wait * before giving up due to no response being received. For an unlimited * timeout, use value 0. @@ -295,8 +313,9 @@ int API_EXPORTED libusb_bulk_transfer(struct libusb_device_handle *dev_handle, * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out * \returns LIBUSB_ERROR_PIPE if the endpoint halted * \returns LIBUSB_ERROR_OVERFLOW if the device offered more data, see - * \ref packetoverflow + * \ref libusb_packetoverflow * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * \returns LIBUSB_ERROR_BUSY if called from event handling context * \returns another LIBUSB_ERROR code on other error */ int API_EXPORTED libusb_interrupt_transfer( diff --git a/Externals/libusb/libusb/version.h b/Externals/libusb/libusb/version.h index 0e3a3633d3..6ce48a7d01 100644 --- a/Externals/libusb/libusb/version.h +++ b/Externals/libusb/libusb/version.h @@ -7,7 +7,7 @@ #define LIBUSB_MINOR 0 #endif #ifndef LIBUSB_MICRO -#define LIBUSB_MICRO 20 +#define LIBUSB_MICRO 21 #endif #ifndef LIBUSB_NANO #define LIBUSB_NANO 0 diff --git a/Externals/libusb/libusb/version_nano.h b/Externals/libusb/libusb/version_nano.h index 4afcd97855..58cb0fbf89 100644 --- a/Externals/libusb/libusb/version_nano.h +++ b/Externals/libusb/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 11004 +#define LIBUSB_NANO 11156 diff --git a/Externals/libusb/libusb_static_2013.vcxproj b/Externals/libusb/libusb_static_2013.vcxproj index f389ea7eed..2aac3e8db1 100644 --- a/Externals/libusb/libusb_static_2013.vcxproj +++ b/Externals/libusb/libusb_static_2013.vcxproj @@ -48,23 +48,26 @@ - - + + + + + - - - + + + - \ No newline at end of file + diff --git a/Externals/libusb/msvc/appveyor.bat b/Externals/libusb/msvc/appveyor.bat new file mode 100644 index 0000000000..779af59d9f --- /dev/null +++ b/Externals/libusb/msvc/appveyor.bat @@ -0,0 +1,28 @@ +echo on +SetLocal EnableDelayedExpansion + +if [%Configuration%] NEQ [Debug] goto releasex64 +if [%Configuration%] NEQ [Release] goto debugx64 + +:debugx64 +if [%Platform%] NEQ [x64] goto debugWin32 +if [%Configuration%] NEQ [Debug] exit 0 +call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /Debug /x64 +msbuild %libusb_2010% /p:Configuration=Debug,Platform=x64 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" + +:releasex64 +if [%Platform%] NEQ [x64] goto releaseWin32 +if [%Configuration%] NEQ [Release] exit 0 +call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /Release /x64 +msbuild %libusb_2010% /p:Configuration=Release,Platform=x64 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" + +:debugWin32 +if [%Platform%] NEQ [Win32] exit 0 +if [%Configuration%] NEQ [Debug] exit 0 +msbuild %libusb_2010% /p:Configuration=Debug,Platform=Win32 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" + +:releaseWin32 +if [%Platform%] NEQ [Win32] exit 0 +if [%Configuration%] NEQ [Release] exit 0 +msbuild %libusb_2010% /p:Configuration=Release,Platform=Win32 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" + diff --git a/Externals/libusb/msvc/config.h b/Externals/libusb/msvc/config.h index 4b418db11d..4f39d78ca5 100644 --- a/Externals/libusb/msvc/config.h +++ b/Externals/libusb/msvc/config.h @@ -5,10 +5,18 @@ #error "Please make sure the msvc/ directory is removed from your build path." #endif +/* Visual Studio 2015 and later defines timespec */ +#if defined(_MSC_VER) && (_MSC_VER >= 1900) +#define _TIMESPEC_DEFINED 1 +#endif + /* Disable: warning C4200: nonstandard extension used : zero-sized array in struct/union */ #pragma warning(disable:4200) /* Disable: warning C6258: Using TerminateThread does not allow proper thread clean up */ #pragma warning(disable: 6258) +/* Disable: warning C4996: 'GetVersionA': was declared deprecated */ +#pragma warning(disable: 4996) + #if defined(_PREFAST_) /* Disable "Banned API" errors when using the MS's WDK OACR/Prefast */ #pragma warning(disable:28719) diff --git a/Externals/libusb/msvc/ddk_build.cmd b/Externals/libusb/msvc/ddk_build.cmd index aadab502e4..c0b905abdd 100644 --- a/Externals/libusb/msvc/ddk_build.cmd +++ b/Externals/libusb/msvc/ddk_build.cmd @@ -3,20 +3,29 @@ ::# you can pass the following arguments (case insensitive): ::# - "DLL" to build a DLL instead of a static library ::# - "/MT" to build a static library compatible with MSVC's /MT option (LIBCMT vs MSVCRT) +::# - "USBDK" to build with UsbDk backend if Test%BUILD_ALT_DIR%==Test goto usage ::# process commandline parameters set TARGET=LIBRARY set STATIC_LIBC= +set WITH_USBDK= set version=1.0 set PWD=%~dp0 set BUILD_CMD=build -bcwgZ -M2 +:more_args + if "%1" == "" goto no_more_args ::# /I for case insensitive if /I Test%1==TestDLL set TARGET=DYNLINK if /I Test%1==Test/MT set STATIC_LIBC=1 +if /I Test%1==TestUSBDK set WITH_USBDK=1 + +shift +goto more_args + :no_more_args cd ..\libusb\os diff --git a/Externals/libusb/msvc/fxload_2015.vcxproj b/Externals/libusb/msvc/fxload_2015.vcxproj new file mode 100644 index 0000000000..1ef31d3a96 --- /dev/null +++ b/Externals/libusb/msvc/fxload_2015.vcxproj @@ -0,0 +1,174 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + fxload + {9E166F7A-A793-9FB6-0A67-F0AED8AE8C88} + examples + Win32Proj + + + + Application + Unicode + true + v140 + + + Application + Unicode + v140 + + + Application + Unicode + true + v140 + + + Application + Unicode + v140 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\ + + + + $(IntDir)$(ProjectName).htm + + + Disabled + .;..\examples\getopt;..\libusb;%(AdditionalIncludeDirectories) + WIN32;__GNU_LIBRARY__;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreadedDebug + Level3 + ProgramDatabase + + + %(AdditionalLibraryDirectories) + true + Console + MachineX86 + + + + + $(IntDir)$(ProjectName).htm + + + X64 + + + Disabled + .;..\examples\getopt;..\libusb;%(AdditionalIncludeDirectories) + WIN32;__GNU_LIBRARY__;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreadedDebug + Level3 + ProgramDatabase + + + %(AdditionalLibraryDirectories) + true + Console + MachineX64 + + + + + $(IntDir)$(ProjectName).htm + + + .;..\examples\getopt;..\libusb;%(AdditionalIncludeDirectories) + WIN32;__GNU_LIBRARY__;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Level3 + + + %(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(IntDir)$(ProjectName).htm + + + X64 + + + .;..\examples\getopt;..\libusb;%(AdditionalIncludeDirectories) + WIN32;__GNU_LIBRARY__;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Level3 + + + %(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + + + + + {349ee8f9-7d25-4909-aaf5-ff3fade72187} + false + + + {ae83e1b4-ce06-47ee-b7a3-c3a1d7c2d71e} + + + + + + + + + \ No newline at end of file diff --git a/Externals/libusb/msvc/getopt_2015.vcxproj b/Externals/libusb/msvc/getopt_2015.vcxproj new file mode 100644 index 0000000000..d1c81a0881 --- /dev/null +++ b/Externals/libusb/msvc/getopt_2015.vcxproj @@ -0,0 +1,136 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E} + getopt + getopt + + + + StaticLibrary + Unicode + true + v140 + + + StaticLibrary + Unicode + v140 + + + StaticLibrary + Unicode + true + v140 + + + StaticLibrary + Unicode + v140 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\getopt\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\getopt\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\getopt\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\getopt\ + + + + HAVE_STRING_H;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreadedDebug + Level3 + ProgramDatabase + + + true + + + + + X64 + + + HAVE_STRING_H;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDebug + Level3 + ProgramDatabase + + + true + + + + + MaxSpeed + HAVE_STRING_H;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Level3 + + + true + + + + + X64 + + + HAVE_STRING_H;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Level3 + + + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/Externals/libusb/msvc/hotplugtest_2015.vcxproj b/Externals/libusb/msvc/hotplugtest_2015.vcxproj new file mode 100644 index 0000000000..377e1c5f2b --- /dev/null +++ b/Externals/libusb/msvc/hotplugtest_2015.vcxproj @@ -0,0 +1,167 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + hotplugtest + {99D2AC64-DC66-4422-91CE-6715C403C9E5} + examples + Win32Proj + + + + Application + Unicode + true + v140 + + + Application + Unicode + v140 + + + Application + Unicode + true + v140 + + + Application + Unicode + v140 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\ + + + + $(IntDir)$(ProjectName).htm + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreadedDebug + Level3 + ProgramDatabase + + + %(AdditionalLibraryDirectories) + true + Console + MachineX86 + + + + + $(IntDir)$(ProjectName).htm + + + X64 + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreadedDebug + Level3 + ProgramDatabase + + + %(AdditionalLibraryDirectories) + true + Console + MachineX64 + + + + + $(IntDir)$(ProjectName).htm + + + .;..\libusb;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Level3 + + + %(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(IntDir)$(ProjectName).htm + + + X64 + + + .;..\libusb;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Level3 + + + %(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + + + + {349ee8f9-7d25-4909-aaf5-ff3fade72187} + false + + + + + + \ No newline at end of file diff --git a/Externals/libusb/msvc/libusb_2013.sln b/Externals/libusb/msvc/libusb_2013.sln index 58cc316162..d1cddb35bf 100644 --- a/Externals/libusb/msvc/libusb_2013.sln +++ b/Externals/libusb/msvc/libusb_2013.sln @@ -21,6 +21,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stress", "stress_2013.vcxpr EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hotplugtest", "hotplugtest_2013.vcxproj", "{99D2AC64-DC66-4422-91CE-6715C403C9E5}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-usbdk-1.0 (dll)", "libusb_usbdk_dll_2013.vcxproj", "{F53A5974-2319-48EB-A67B-27933AEDF14A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-usbdk-1.0 (static)", "libusb_usbdk_static_2013.vcxproj", "{0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -93,6 +97,22 @@ Global {99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release|Win32.Build.0 = Release|Win32 {99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release|x64.ActiveCfg = Release|x64 {99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release|x64.Build.0 = Release|x64 + {F53A5974-2319-48EB-A67B-27933AEDF14A}.Debug|Win32.ActiveCfg = Debug|Win32 + {F53A5974-2319-48EB-A67B-27933AEDF14A}.Debug|Win32.Build.0 = Debug|Win32 + {F53A5974-2319-48EB-A67B-27933AEDF14A}.Debug|x64.ActiveCfg = Debug|x64 + {F53A5974-2319-48EB-A67B-27933AEDF14A}.Debug|x64.Build.0 = Debug|x64 + {F53A5974-2319-48EB-A67B-27933AEDF14A}.Release|Win32.ActiveCfg = Release|Win32 + {F53A5974-2319-48EB-A67B-27933AEDF14A}.Release|Win32.Build.0 = Release|Win32 + {F53A5974-2319-48EB-A67B-27933AEDF14A}.Release|x64.ActiveCfg = Release|x64 + {F53A5974-2319-48EB-A67B-27933AEDF14A}.Release|x64.Build.0 = Release|x64 + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}.Debug|Win32.ActiveCfg = Debug|Win32 + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}.Debug|Win32.Build.0 = Debug|Win32 + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}.Debug|x64.ActiveCfg = Debug|x64 + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}.Debug|x64.Build.0 = Debug|x64 + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}.Release|Win32.ActiveCfg = Release|Win32 + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}.Release|Win32.Build.0 = Release|Win32 + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}.Release|x64.ActiveCfg = Release|x64 + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Externals/libusb/msvc/libusb_2015.sln b/Externals/libusb/msvc/libusb_2015.sln new file mode 100644 index 0000000000..6a251d5a2c --- /dev/null +++ b/Externals/libusb/msvc/libusb_2015.sln @@ -0,0 +1,120 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (static)", "libusb_static_2015.vcxproj", "{349EE8F9-7D25-4909-AAF5-FF3FADE72187}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (dll)", "libusb_dll_2015.vcxproj", "{349EE8FA-7D25-4909-AAF5-FF3FADE72187}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "listdevs", "listdevs_2015.vcxproj", "{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xusb", "xusb_2015.vcxproj", "{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fxload", "fxload_2015.vcxproj", "{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}" + ProjectSection(ProjectDependencies) = postProject + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E} = {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getopt", "getopt_2015.vcxproj", "{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stress", "stress_2015.vcxproj", "{53942EFF-C810-458D-B3CB-EE5CE9F1E781}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hotplugtest", "hotplugtest_2015.vcxproj", "{99D2AC64-DC66-4422-91CE-6715C403C9E5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-usbdk-1.0 (dll)", "libusb_usbdk_dll_2015.vcxproj", "{F53A5974-2319-48EB-A67B-27933AEDF14A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-usbdk-1.0 (static)", "libusb_usbdk_static_2015.vcxproj", "{0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.ActiveCfg = Debug|Win32 + {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.Build.0 = Debug|Win32 + {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64 + {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.Build.0 = Debug|x64 + {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.ActiveCfg = Release|Win32 + {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.Build.0 = Release|Win32 + {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.ActiveCfg = Release|x64 + {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.Build.0 = Release|x64 + {349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.ActiveCfg = Debug|Win32 + {349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.Build.0 = Debug|Win32 + {349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64 + {349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.Build.0 = Debug|x64 + {349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.ActiveCfg = Release|Win32 + {349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.Build.0 = Release|Win32 + {349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|x64.ActiveCfg = Release|x64 + {349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|x64.Build.0 = Release|x64 + {F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|Win32.ActiveCfg = Debug|Win32 + {F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|Win32.Build.0 = Debug|Win32 + {F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|x64.ActiveCfg = Debug|x64 + {F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|x64.Build.0 = Debug|x64 + {F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|Win32.ActiveCfg = Release|Win32 + {F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|Win32.Build.0 = Release|Win32 + {F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|x64.ActiveCfg = Release|x64 + {F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|x64.Build.0 = Release|x64 + {3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|Win32.ActiveCfg = Debug|Win32 + {3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|Win32.Build.0 = Debug|Win32 + {3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|x64.ActiveCfg = Debug|x64 + {3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|x64.Build.0 = Debug|x64 + {3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|Win32.ActiveCfg = Release|Win32 + {3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|Win32.Build.0 = Release|Win32 + {3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|x64.ActiveCfg = Release|x64 + {3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|x64.Build.0 = Release|x64 + {9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|Win32.ActiveCfg = Debug|Win32 + {9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|Win32.Build.0 = Debug|Win32 + {9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|x64.ActiveCfg = Debug|x64 + {9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|x64.Build.0 = Debug|x64 + {9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release|Win32.ActiveCfg = Release|Win32 + {9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release|Win32.Build.0 = Release|Win32 + {9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release|x64.ActiveCfg = Release|x64 + {9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release|x64.Build.0 = Release|x64 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|Win32.ActiveCfg = Debug|Win32 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|Win32.Build.0 = Debug|Win32 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x64.ActiveCfg = Debug|x64 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x64.Build.0 = Debug|x64 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|Win32.ActiveCfg = Release|Win32 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|Win32.Build.0 = Release|Win32 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x64.ActiveCfg = Release|x64 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x64.Build.0 = Release|x64 + {53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug|Win32.ActiveCfg = Debug|Win32 + {53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug|Win32.Build.0 = Debug|Win32 + {53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug|x64.ActiveCfg = Debug|x64 + {53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug|x64.Build.0 = Debug|x64 + {53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release|Win32.ActiveCfg = Release|Win32 + {53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release|Win32.Build.0 = Release|Win32 + {53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release|x64.ActiveCfg = Release|x64 + {53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release|x64.Build.0 = Release|x64 + {99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug|Win32.ActiveCfg = Debug|Win32 + {99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug|Win32.Build.0 = Debug|Win32 + {99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug|x64.ActiveCfg = Debug|x64 + {99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug|x64.Build.0 = Debug|x64 + {99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release|Win32.ActiveCfg = Release|Win32 + {99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release|Win32.Build.0 = Release|Win32 + {99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release|x64.ActiveCfg = Release|x64 + {99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release|x64.Build.0 = Release|x64 + {F53A5974-2319-48EB-A67B-27933AEDF14A}.Debug|Win32.ActiveCfg = Debug|Win32 + {F53A5974-2319-48EB-A67B-27933AEDF14A}.Debug|Win32.Build.0 = Debug|Win32 + {F53A5974-2319-48EB-A67B-27933AEDF14A}.Debug|x64.ActiveCfg = Debug|x64 + {F53A5974-2319-48EB-A67B-27933AEDF14A}.Debug|x64.Build.0 = Debug|x64 + {F53A5974-2319-48EB-A67B-27933AEDF14A}.Release|Win32.ActiveCfg = Release|Win32 + {F53A5974-2319-48EB-A67B-27933AEDF14A}.Release|Win32.Build.0 = Release|Win32 + {F53A5974-2319-48EB-A67B-27933AEDF14A}.Release|x64.ActiveCfg = Release|x64 + {F53A5974-2319-48EB-A67B-27933AEDF14A}.Release|x64.Build.0 = Release|x64 + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}.Debug|Win32.ActiveCfg = Debug|Win32 + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}.Debug|Win32.Build.0 = Debug|Win32 + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}.Debug|x64.ActiveCfg = Debug|x64 + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}.Debug|x64.Build.0 = Debug|x64 + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}.Release|Win32.ActiveCfg = Release|Win32 + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}.Release|Win32.Build.0 = Release|Win32 + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}.Release|x64.ActiveCfg = Release|x64 + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Externals/libusb/msvc/libusb_dll.dsp b/Externals/libusb/msvc/libusb_dll.dsp index 34f4bdaedc..f6a894566a 100644 --- a/Externals/libusb/msvc/libusb_dll.dsp +++ b/Externals/libusb/msvc/libusb_dll.dsp @@ -135,7 +135,7 @@ SOURCE=..\libusb\os\threads_windows.c # End Source File # Begin Source File -SOURCE=..\libusb\os\windows_usb.c +SOURCE=..\libusb\os\windows_winusb.c # End Source File # End Group # Begin Group "Header Files" @@ -179,7 +179,7 @@ SOURCE=..\libusb\os\threads_windows.h # End Source File # Begin Source File -SOURCE=..\libusb\os\windows_usb.h +SOURCE=..\libusb\os\windows_winusb.h # End Source File # Begin Source File diff --git a/Externals/libusb/msvc/libusb_dll_2005.vcproj b/Externals/libusb/msvc/libusb_dll_2005.vcproj index 347aa9591c..2801f7fd0a 100644 --- a/Externals/libusb/msvc/libusb_dll_2005.vcproj +++ b/Externals/libusb/msvc/libusb_dll_2005.vcproj @@ -374,7 +374,7 @@ > @@ -408,7 +408,7 @@ > - + + @@ -155,8 +156,11 @@ - + + + + diff --git a/Externals/libusb/msvc/libusb_dll_2010.vcxproj.filters b/Externals/libusb/msvc/libusb_dll_2010.vcxproj.filters index c3714de399..4e1ccab5c1 100644 --- a/Externals/libusb/msvc/libusb_dll_2010.vcxproj.filters +++ b/Externals/libusb/msvc/libusb_dll_2010.vcxproj.filters @@ -38,7 +38,7 @@ Source Files - + Source Files @@ -61,7 +61,7 @@ Header Files - + Header Files diff --git a/Externals/libusb/msvc/libusb_dll_2012.vcxproj b/Externals/libusb/msvc/libusb_dll_2012.vcxproj index a26d240700..004bf112cc 100644 --- a/Externals/libusb/msvc/libusb_dll_2012.vcxproj +++ b/Externals/libusb/msvc/libusb_dll_2012.vcxproj @@ -150,18 +150,21 @@ - + + - - - + - + + + + + diff --git a/Externals/libusb/msvc/libusb_dll_2012.vcxproj.filters b/Externals/libusb/msvc/libusb_dll_2012.vcxproj.filters index f00a0d098a..65e44f96a3 100644 --- a/Externals/libusb/msvc/libusb_dll_2012.vcxproj.filters +++ b/Externals/libusb/msvc/libusb_dll_2012.vcxproj.filters @@ -35,7 +35,7 @@ Source Files - + Source Files @@ -58,7 +58,7 @@ Header Files - + Header Files diff --git a/Externals/libusb/msvc/libusb_dll_2013.vcxproj b/Externals/libusb/msvc/libusb_dll_2013.vcxproj index 5881c6dfee..80d1a29391 100644 --- a/Externals/libusb/msvc/libusb_dll_2013.vcxproj +++ b/Externals/libusb/msvc/libusb_dll_2013.vcxproj @@ -150,18 +150,21 @@ - + + - - - + - + + + + + diff --git a/Externals/libusb/msvc/libusb_dll_2015.vcxproj b/Externals/libusb/msvc/libusb_dll_2015.vcxproj new file mode 100644 index 0000000000..202f6c0a0f --- /dev/null +++ b/Externals/libusb/msvc/libusb_dll_2015.vcxproj @@ -0,0 +1,178 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + libusb-1.0 (dll) + {349EE8FA-7D25-4909-AAF5-FF3FADE72187} + libusbdll + + + + DynamicLibrary + Unicode + true + v140 + + + DynamicLibrary + Unicode + v140 + + + DynamicLibrary + Unicode + true + v140 + + + DynamicLibrary + Unicode + v140 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-1.0\ + libusb-1.0 + libusb-1.0 + libusb-1.0 + libusb-1.0 + + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + $(OutDir)libusb-1.0.dll + ..\libusb\libusb-1.0.def + libusb-1.0.rc;%(EmbedManagedResourceFile) + true + + + + + X64 + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_WIN64;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + $(OutDir)libusb-1.0.dll + ..\libusb\libusb-1.0.def + libusb-1.0.rc;%(EmbedManagedResourceFile) + true + + + + + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + Level4 + + + $(OutDir)libusb-1.0.dll + ..\libusb\libusb-1.0.def + libusb-1.0.rc;%(EmbedManagedResourceFile) + + + + + X64 + + + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_WIN64;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + Level4 + + + $(OutDir)libusb-1.0.dll + ..\libusb\libusb-1.0.def + libusb-1.0.rc;%(EmbedManagedResourceFile) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Externals/libusb/msvc/libusb_sources b/Externals/libusb/msvc/libusb_sources index 308a6663f3..591d7f6136 100644 --- a/Externals/libusb/msvc/libusb_sources +++ b/Externals/libusb/msvc/libusb_sources @@ -12,8 +12,12 @@ USE_LIBCMT=1 USE_MSVCRT=1 !ENDIF +!IFDEF WITH_USBDK +BACKEND_DEFINES="/DUSE_USBDK" +!ENDIF + INCLUDES=..;..\..\msvc;$(DDK_INC_PATH) -C_DEFINES= $(C_DEFINES) $(LIBUSB_DEFINES) /DDDKBUILD +C_DEFINES= $(C_DEFINES) $(LIBUSB_DEFINES) $(BACKEND_DEFINES) /DDDKBUILD # http://jpassing.com/2009/10/21/ltcg-issues-with-the-win7amd64-environment-of-wdk-7600/ # prevents the following error when using the 64 bit static lib with Visual Studio 2010: @@ -34,5 +38,7 @@ SOURCES=..\core.c \ ..\hotplug.c \ threads_windows.c \ poll_windows.c \ - windows_usb.c \ + windows_winusb.c \ + windows_usbdk.c \ + windows_nt_common.c \ ..\libusb-1.0.rc diff --git a/Externals/libusb/msvc/libusb_static.dsp b/Externals/libusb/msvc/libusb_static.dsp index d703a58ef3..b138cd0ebe 100644 --- a/Externals/libusb/msvc/libusb_static.dsp +++ b/Externals/libusb/msvc/libusb_static.dsp @@ -119,7 +119,7 @@ SOURCE=..\libusb\os\threads_windows.c # End Source File # Begin Source File -SOURCE=..\libusb\os\windows_usb.c +SOURCE=..\libusb\os\windows_winusb.c # End Source File # End Group # Begin Group "Header Files" @@ -163,7 +163,7 @@ SOURCE=..\libusb\os\threads_windows.h # End Source File # Begin Source File -SOURCE=..\libusb\os\windows_usb.h +SOURCE=..\libusb\os\windows_winusb.h # End Source File # Begin Source File diff --git a/Externals/libusb/msvc/libusb_static_2005.vcproj b/Externals/libusb/msvc/libusb_static_2005.vcproj index 18f92f9a1b..a649db3d5f 100644 --- a/Externals/libusb/msvc/libusb_static_2005.vcproj +++ b/Externals/libusb/msvc/libusb_static_2005.vcproj @@ -314,7 +314,7 @@ > @@ -348,7 +348,7 @@ > - + + - - - + + + + diff --git a/Externals/libusb/msvc/libusb_static_2010.vcxproj.filters b/Externals/libusb/msvc/libusb_static_2010.vcxproj.filters index 62770c5f40..2c396e34cc 100644 --- a/Externals/libusb/msvc/libusb_static_2010.vcxproj.filters +++ b/Externals/libusb/msvc/libusb_static_2010.vcxproj.filters @@ -32,7 +32,7 @@ Source Files - + Source Files @@ -55,7 +55,7 @@ Header Files - + Header Files diff --git a/Externals/libusb/msvc/libusb_static_2012.vcxproj b/Externals/libusb/msvc/libusb_static_2012.vcxproj index 7bd8c6851a..896794f3d7 100644 --- a/Externals/libusb/msvc/libusb_static_2012.vcxproj +++ b/Externals/libusb/msvc/libusb_static_2012.vcxproj @@ -140,19 +140,21 @@ - + + - - - + - + + + + diff --git a/Externals/libusb/msvc/libusb_static_2012.vcxproj.filters b/Externals/libusb/msvc/libusb_static_2012.vcxproj.filters index 62770c5f40..2c396e34cc 100644 --- a/Externals/libusb/msvc/libusb_static_2012.vcxproj.filters +++ b/Externals/libusb/msvc/libusb_static_2012.vcxproj.filters @@ -32,7 +32,7 @@ Source Files - + Source Files @@ -55,7 +55,7 @@ Header Files - + Header Files diff --git a/Externals/libusb/msvc/libusb_static_2013.vcxproj b/Externals/libusb/msvc/libusb_static_2013.vcxproj index 0f71d7fd5d..7966a0d14b 100644 --- a/Externals/libusb/msvc/libusb_static_2013.vcxproj +++ b/Externals/libusb/msvc/libusb_static_2013.vcxproj @@ -140,19 +140,21 @@ - + + - - - + - + + + + diff --git a/Externals/libusb/msvc/libusb_static_2015.vcxproj b/Externals/libusb/msvc/libusb_static_2015.vcxproj new file mode 100644 index 0000000000..275cd72f43 --- /dev/null +++ b/Externals/libusb/msvc/libusb_static_2015.vcxproj @@ -0,0 +1,162 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + libusb-1.0 (static) + {349EE8F9-7D25-4909-AAF5-FF3FADE72187} + libusb + + + + StaticLibrary + Unicode + true + v140 + + + StaticLibrary + Unicode + v140 + + + StaticLibrary + Unicode + true + v140 + + + StaticLibrary + Unicode + v140 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\libusb-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\libusb-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\libusb-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\libusb-1.0\ + libusb-1.0 + libusb-1.0 + libusb-1.0 + libusb-1.0 + + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + Level4 + ProgramDatabase + $(IntDir)$(TargetName).pdb + + + $(OutDir)libusb-1.0.lib + + + + + X64 + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_WIN64;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + Level4 + ProgramDatabase + $(IntDir)$(TargetName).pdb + + + $(OutDir)libusb-1.0.lib + + + + + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + Level4 + $(IntDir)$(TargetName).pdb + + + $(OutDir)libusb-1.0.lib + + + + + X64 + + + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_WIN64;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + Level4 + $(IntDir)$(TargetName).pdb + + + $(OutDir)libusb-1.0.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Externals/libusb/msvc/libusb_usbdk_dll_2013.vcxproj b/Externals/libusb/msvc/libusb_usbdk_dll_2013.vcxproj new file mode 100644 index 0000000000..8695556e86 --- /dev/null +++ b/Externals/libusb/msvc/libusb_usbdk_dll_2013.vcxproj @@ -0,0 +1,178 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + libusb-usbdk-1.0 (dll) + {F53A5974-2319-48EB-A67B-27933AEDF14A} + libusbdll + + + + DynamicLibrary + Unicode + true + v120 + + + DynamicLibrary + Unicode + v120 + + + DynamicLibrary + Unicode + true + v120 + + + DynamicLibrary + Unicode + v120 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-usbdk-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-usbdk-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-usbdk-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-usbdk-1.0\ + libusb-usbdk-1.0 + libusb-usbdk-1.0 + libusb-usbdk-1.0 + libusb-usbdk-1.0 + + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;USE_USBDK;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + $(OutDir)libusb-usbdk-1.0.dll + ..\libusb\libusb-1.0.def + libusb-1.0.rc;%(EmbedManagedResourceFile) + true + + + + + X64 + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_WIN64;_DEBUG;_CRT_SECURE_NO_WARNINGS;USE_USBDK;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + $(OutDir)libusb-usbdk-1.0.dll + ..\libusb\libusb-1.0.def + libusb-1.0.rc;%(EmbedManagedResourceFile) + true + + + + + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_LIB;_CRT_SECURE_NO_WARNINGS;USE_USBDK;%(PreprocessorDefinitions) + MultiThreadedDLL + Level4 + + + $(OutDir)libusb-usbdk-1.0.dll + ..\libusb\libusb-1.0.def + libusb-1.0.rc;%(EmbedManagedResourceFile) + + + + + X64 + + + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_WIN64;_LIB;_CRT_SECURE_NO_WARNINGS;USE_USBDK;%(PreprocessorDefinitions) + MultiThreadedDLL + Level4 + + + $(OutDir)libusb-usbdk-1.0.dll + ..\libusb\libusb-1.0.def + libusb-1.0.rc;%(EmbedManagedResourceFile) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Externals/libusb/msvc/libusb_usbdk_dll_2015.vcxproj b/Externals/libusb/msvc/libusb_usbdk_dll_2015.vcxproj new file mode 100644 index 0000000000..5408fd458f --- /dev/null +++ b/Externals/libusb/msvc/libusb_usbdk_dll_2015.vcxproj @@ -0,0 +1,178 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + libusb-usbdk-1.0 (dll) + {F53A5974-2319-48EB-A67B-27933AEDF14A} + libusbdll + + + + DynamicLibrary + Unicode + true + v140 + + + DynamicLibrary + Unicode + v140 + + + DynamicLibrary + Unicode + true + v140 + + + DynamicLibrary + Unicode + v140 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-usbdk-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-usbdk-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-usbdk-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\ + $(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-usbdk-1.0\ + libusb-usbdk-1.0 + libusb-usbdk-1.0 + libusb-usbdk-1.0 + libusb-usbdk-1.0 + + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;USE_USBDK;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + $(OutDir)libusb-usbdk-1.0.dll + ..\libusb\libusb-1.0.def + libusb-1.0.rc;%(EmbedManagedResourceFile) + true + + + + + X64 + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_WIN64;_DEBUG;_CRT_SECURE_NO_WARNINGS;USE_USBDK;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level4 + ProgramDatabase + + + $(OutDir)libusb-usbdk-1.0.dll + ..\libusb\libusb-1.0.def + libusb-1.0.rc;%(EmbedManagedResourceFile) + true + + + + + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_LIB;_CRT_SECURE_NO_WARNINGS;USE_USBDK;%(PreprocessorDefinitions) + MultiThreadedDLL + Level4 + + + $(OutDir)libusb-usbdk-1.0.dll + ..\libusb\libusb-1.0.def + libusb-1.0.rc;%(EmbedManagedResourceFile) + + + + + X64 + + + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_WIN64;_LIB;_CRT_SECURE_NO_WARNINGS;USE_USBDK;%(PreprocessorDefinitions) + MultiThreadedDLL + Level4 + + + $(OutDir)libusb-usbdk-1.0.dll + ..\libusb\libusb-1.0.def + libusb-1.0.rc;%(EmbedManagedResourceFile) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Externals/libusb/msvc/libusb_usbdk_static_2013.vcxproj b/Externals/libusb/msvc/libusb_usbdk_static_2013.vcxproj new file mode 100644 index 0000000000..c9af0e9016 --- /dev/null +++ b/Externals/libusb/msvc/libusb_usbdk_static_2013.vcxproj @@ -0,0 +1,162 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + libusb-usbdk-1.0 (static) + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED} + libusb + + + + StaticLibrary + Unicode + true + v120 + + + StaticLibrary + Unicode + v120 + + + StaticLibrary + Unicode + true + v120 + + + StaticLibrary + Unicode + v120 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\libusb-usbdk-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\libusb-usbdk-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\libusb-usbdk-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\libusb-usbdk-1.0\ + libusb-usbdk-1.0 + libusb-usbdk-1.0 + libusb-usbdk-1.0 + libusb-usbdk-1.0 + + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;USE_USBDK;%(PreprocessorDefinitions) + MultiThreadedDebug + Level4 + ProgramDatabase + + + $(OutDir)libusb-usbdk-1.0.lib + + + + + X64 + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_WIN64;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;USE_USBDK;%(PreprocessorDefinitions) + MultiThreadedDebug + Level4 + ProgramDatabase + + + $(OutDir)libusb-usbdk-1.0.lib + + + + + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_LIB;_CRT_SECURE_NO_WARNINGS;USE_USBDK;%(PreprocessorDefinitions) + MultiThreaded + Level4 + + + $(OutDir)libusb-usbdk-1.0.lib + + + + + X64 + + + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_WIN64;_LIB;_CRT_SECURE_NO_WARNINGS;USE_USBDK;%(PreprocessorDefinitions) + MultiThreaded + Level4 + + + $(OutDir)libusb-usbdk-1.0.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Externals/libusb/msvc/libusb_usbdk_static_2015.vcxproj b/Externals/libusb/msvc/libusb_usbdk_static_2015.vcxproj new file mode 100644 index 0000000000..67944bafb7 --- /dev/null +++ b/Externals/libusb/msvc/libusb_usbdk_static_2015.vcxproj @@ -0,0 +1,162 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + libusb-usbdk-1.0 (static) + {0B3D86CF-5D70-41A9-B391-A2E7C5C969ED} + libusb + + + + StaticLibrary + Unicode + true + v140 + + + StaticLibrary + Unicode + v140 + + + StaticLibrary + Unicode + true + v140 + + + StaticLibrary + Unicode + v140 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\libusb-usbdk-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\libusb-usbdk-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\libusb-usbdk-1.0\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\ + $(SolutionDir)..\$(Platform)\$(Configuration)\lib\libusb-usbdk-1.0\ + libusb-usbdk-1.0 + libusb-usbdk-1.0 + libusb-usbdk-1.0 + libusb-usbdk-1.0 + + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;USE_USBDK;%(PreprocessorDefinitions) + MultiThreadedDebug + Level4 + ProgramDatabase + + + $(OutDir)libusb-usbdk-1.0.lib + + + + + X64 + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_WIN64;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;USE_USBDK;%(PreprocessorDefinitions) + MultiThreadedDebug + Level4 + ProgramDatabase + + + $(OutDir)libusb-usbdk-1.0.lib + + + + + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_LIB;_CRT_SECURE_NO_WARNINGS;USE_USBDK;%(PreprocessorDefinitions) + MultiThreaded + Level4 + + + $(OutDir)libusb-usbdk-1.0.lib + + + + + X64 + + + .;..\libusb;%(AdditionalIncludeDirectories) + _WIN32;_WIN64;_LIB;_CRT_SECURE_NO_WARNINGS;USE_USBDK;%(PreprocessorDefinitions) + MultiThreaded + Level4 + + + $(OutDir)libusb-usbdk-1.0.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Externals/libusb/msvc/listdevs_2015.vcxproj b/Externals/libusb/msvc/listdevs_2015.vcxproj new file mode 100644 index 0000000000..9224d8bddc --- /dev/null +++ b/Externals/libusb/msvc/listdevs_2015.vcxproj @@ -0,0 +1,169 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + listdevs + {F4938DB0-3DE7-4737-9C5A-EAD1BE819F87} + examples + Win32Proj + + + + Application + Unicode + true + v140 + + + Application + Unicode + v140 + + + Application + Unicode + true + v140 + + + Application + Unicode + v140 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\ + + + + $(IntDir)$(ProjectName).htm + + + Disabled + ..\libusb;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDebug + Level3 + ProgramDatabase + + + %(AdditionalLibraryDirectories) + true + $(TargetDir)$(ProjectName).pdb + Console + MachineX86 + + + + + $(IntDir)$(ProjectName).htm + + + X64 + + + Disabled + ..\libusb;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDebug + Level3 + ProgramDatabase + + + %(AdditionalLibraryDirectories) + true + $(TargetDir)$(ProjectName).pdb + Console + MachineX64 + + + + + $(IntDir)$(ProjectName).htm + + + ..\libusb;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Level3 + + + %(AdditionalLibraryDirectories) + $(TargetDir)$(ProjectName).pdb + Console + MachineX86 + + + + + $(IntDir)$(ProjectName).htm + + + X64 + + + ..\libusb;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Level3 + + + %(AdditionalLibraryDirectories) + $(TargetDir)$(ProjectName).pdb + Console + MachineX64 + + + + + + + + {349ee8f9-7d25-4909-aaf5-ff3fade72187} + false + + + + + + \ No newline at end of file diff --git a/Externals/libusb/msvc/stress_2015.vcxproj b/Externals/libusb/msvc/stress_2015.vcxproj new file mode 100644 index 0000000000..18733c833b --- /dev/null +++ b/Externals/libusb/msvc/stress_2015.vcxproj @@ -0,0 +1,171 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + stress + {53942EFF-C810-458D-B3CB-EE5CE9F1E781} + tests + Win32Proj + + + + Application + Unicode + true + v140 + + + Application + Unicode + v140 + + + Application + Unicode + true + v140 + + + Application + Unicode + v140 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)..\$(Platform)\$(Configuration)\tests\ + $(SolutionDir)..\$(Platform)\$(Configuration)\tests\$(ProjectName)\ + $(SolutionDir)..\$(Platform)\$(Configuration)\tests\ + $(SolutionDir)..\$(Platform)\$(Configuration)\tests\$(ProjectName)\ + $(SolutionDir)..\$(Platform)\$(Configuration)\tests\ + $(SolutionDir)..\$(Platform)\$(Configuration)\tests\$(ProjectName)\ + $(SolutionDir)..\$(Platform)\$(Configuration)\tests\ + $(SolutionDir)..\$(Platform)\$(Configuration)\tests\$(ProjectName)\ + + + + $(IntDir)$(ProjectName).htm + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreadedDebug + Level3 + ProgramDatabase + + + %(AdditionalLibraryDirectories) + true + Console + MachineX86 + + + + + $(IntDir)$(ProjectName).htm + + + X64 + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreadedDebug + Level3 + ProgramDatabase + + + %(AdditionalLibraryDirectories) + true + Console + MachineX64 + + + + + $(IntDir)$(ProjectName).htm + + + .;..\libusb;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Level3 + + + %(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(IntDir)$(ProjectName).htm + + + X64 + + + .;..\libusb;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Level3 + + + %(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + + + + + {349ee8f9-7d25-4909-aaf5-ff3fade72187} + false + + + + + + + + + \ No newline at end of file diff --git a/Externals/libusb/msvc/xusb_2015.vcxproj b/Externals/libusb/msvc/xusb_2015.vcxproj new file mode 100644 index 0000000000..e63663892f --- /dev/null +++ b/Externals/libusb/msvc/xusb_2015.vcxproj @@ -0,0 +1,167 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + xusb + {3F3138D0-7AB7-4268-9BF3-1A3EA5503A11} + examples + Win32Proj + + + + Application + Unicode + true + v140 + + + Application + Unicode + v140 + + + Application + Unicode + true + v140 + + + Application + Unicode + v140 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\ + $(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\ + + + + $(IntDir)$(ProjectName).htm + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreadedDebug + Level3 + ProgramDatabase + + + %(AdditionalLibraryDirectories) + true + Console + MachineX86 + + + + + $(IntDir)$(ProjectName).htm + + + X64 + + + Disabled + .;..\libusb;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreadedDebug + Level3 + ProgramDatabase + + + %(AdditionalLibraryDirectories) + true + Console + MachineX64 + + + + + $(IntDir)$(ProjectName).htm + + + .;..\libusb;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Level3 + + + %(AdditionalLibraryDirectories) + Console + MachineX86 + + + + + $(IntDir)$(ProjectName).htm + + + X64 + + + .;..\libusb;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Level3 + + + %(AdditionalLibraryDirectories) + Console + MachineX64 + + + + + + + + {349ee8f9-7d25-4909-aaf5-ff3fade72187} + false + + + + + + \ No newline at end of file