diff options
165 files changed, 5830 insertions, 3393 deletions
@@ -23,6 +23,7 @@ config.h* !msvc/config.h !android/config.h !Xcode/config.h +!tests/config.h .vs config.log config.status @@ -38,6 +39,8 @@ examples/hotplugtest examples/sam3u_benchmark examples/testlibusb tests/stress +android/libs +android/obj *.exe *.pc doc/api-1.0 diff --git a/.private/wbs.txt b/.private/wbs.txt index cbf376b..752e6da 100644 --- a/.private/wbs.txt +++ b/.private/wbs.txt @@ -2,7 +2,7 @@ ********************************************************************* * The latest version of this snapshot can always be downloaded at: * - * https://sourceforge.net/projects/libusb/files/ * + * https://github.com/libusb/libusb/releases * ********************************************************************* o Visual Studio: @@ -37,6 +37,9 @@ o Additional information: - For some libusb samples (including source), please have a look in examples/ - For additional information on the libusb 1.0 Windows backend please visit: http://windows.libusb.info + - Using the UsbDk backend is now a run-time choice rather than a compile-time + choice. For additional information, including example usage, please visit: + http://windows.libusb.info/#Driver_Installation - The MinGW and MS generated DLLs are fully interchangeable, provided that you use the import libs provided or generate one from the .def also provided. - If you find any issue, please visit http://libusb.info/ and check the diff --git a/.travis.yml b/.travis.yml index 47ce5aa..35326e3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,12 @@ git: matrix: include: - os: linux + dist: focal + compiler: clang + - os: linux + dist: focal + compiler: gcc + - os: linux dist: bionic compiler: clang - os: linux @@ -18,13 +24,13 @@ matrix: dist: xenial compiler: gcc - os: osx - osx_image: xcode11.3 + osx_image: xcode12.2 compiler: clang - os: osx - osx_image: xcode9.4 + osx_image: xcode11.3 compiler: clang - os: osx - osx_image: xcode7.3 + osx_image: xcode9.4 compiler: clang addons: @@ -11,11 +11,18 @@ Copyright © 2012-2013 Toby Gray <toby.gray@realvnc.com> Copyright © 2013-2018 Chris Dickens <christopher.a.dickens@gmail.com> Other contributors: +Aaron Luft Adrian Bunk +Adrien Destugues Akshay Jaggi Alan Ott Alan Stern +Aleksandr Mezin +Alexander Pyhalov +Alexander Schlarb +Alexander Stein Alex Vatchenko +Andrew Aldridge Andrew Fernandes Andy Chunyu Andy McFadden @@ -25,18 +32,25 @@ Anthony Clay Antonio Ospite Artem Egorkine Aurelien Jarno +Axel Gembe +Aymeric Vincent +Baruch Siach Bastien Nocera Bei Zhang +Bence Csokas Benjamin Dobell Brent Rector Carl Karsten +Chris Zhu Christophe Zeitouny +Chunyu Xie Colin Walters Dave Camarillo David Engraf -David Moore Davidlohr Bueso +David Moore Dmitry Fleytman +Dmitry Kostjuchenko Doug Johnston Evan Hunter Federico Manzan @@ -44,60 +58,85 @@ Felipe Balbi Florian Albrechtskirchinger Francesco Montorsi Francisco Facioni +Frank Li +Frederik Carlier Gaurav Gupta Graeme Gill +Greg Kroah-Hartman Gustavo Zacarias Hans Ulrich Niedermann +Harry Mallon Hector Martin Hoi-Ho Chan +Ido Yariv +Igor Anokhin +Ihor Dutchak Ilya Konstantinov Jakub Klama James Hanko Jeffrey Nichols +Jie Zhang Johann Richard +John Keeping John Sheu +Jonas Malaco Jonathon Jongsma Joost Muller Josh Gao Joshua Blake +Joshua Hou +Juan Cruz Viotti Justin Bischoff -KIMURA Masaru Karsten Koenig +Kenjiro Tsuji +KIMURA Masaru Konrad Rzepecki Kuangye Guo Lars Kanis Lars Wirzenius Lei Chen +Léo Lam Luca Longinotti Marcus Meissner Markus Heidelberg Martin Ettl Martin Koegler +Martin Thierer Matthew Stapleton Matthias Bolte Michel Zou Mike Frysinger Mikhail Gusarov +Mikolaj Kucharski Morgan Leborgne Moritz Fischer -Ларионов Даниил +Nia Alarie Nicholas Corgan Omri Iluz Orin Eman +Patrick Stewart Paul Fertser +Paul Qureshi Pekka Nikander +Philémon Favrod +Pino Toscano Rob Walker Romain Vimont Roman Kalashnikov +Saleem Rashid Sameeh Jubran Sean McBride Sebastian Pipping +Sebastian von Ohr Sergey Serb Simon Haggett Simon Newton +Slash Gordon Stefan Agner Stefan Tauner Steinar H. Gunderson +Stephen Groat +Theo Buehler Thomas Röfer Tim Hutt Tim Roberts @@ -106,14 +145,25 @@ Toby Peterson Tormod Volden Trygve Laugstøl Uri Lublin +Uwe Bonnes Vasily Khoruzhick Vegard Storheil Eriksen Venkatesh Shukla Vianney le Clément de Saint-Marcq Victor Toso +Vinicius Tinti Vitali Lovich +Vladimir Beloborodov +William Orr William Skellenger Xiaofan Chen +Zhiqiang Liu Zoltán Kovács +Сергей Валерьевич +Ларионов Даниил Роман Донченко +liangyunwang parafin +RipleyTom +saur0n +winterrace @@ -1,6 +1,30 @@ For detailed information about the changes below, please see the git log or visit: http://log.libusb.info +2020-12-09: v1.0.24 +* Add new platform abstraction (#252) +* Add Null POSIX backend +* Add support for eventfd +* Add support for thread IDs on Haiku, NetBSD and Solaris +* New API libusb_hotplug_get_user_data() +* Darwin (macOS): Fix race condition that results in segmentation fault (#701) +* Darwin (macOS): Fix stale descriptor information post reset (#733) +* Darwin (macOS): use IOUSBDevice as darwin_device_class explicitly (#693) +* Linux: Drop support for kernel older than 2.6.32 +* Linux: Provide an event thread name (#689) +* Linux: Wait until all USBs have been reaped before freeing them (#607) +* NetBSD: Recognize device timeouts (#710) +* OpenBSD: Allow opening ugen devices multiple times (#763) +* OpenBSD: Support libusb_get_port_number() (#764) +* SunOS: Fix a memory leak (#756) +* SunOS: Various fixes (#627, #628, #629) +* Windows: Add Visual Studio 2019 support +* Windows: Drop support for WinCE and Visual Studio older than 2013 +* Windows: Drop support for Windows XP +* Windows: Support building all examples using Visual Studio (#151) +* Documentation fixes and improvements +* Various other bug fixes and improvements + 2019-08-28: v1.0.23 * Add German translation (#446) * Add Hungarian translation (#493) @@ -22,7 +46,7 @@ visit: http://log.libusb.info * Windows: Add support for isochronous transfers with WinUSB * Various other bug fixes and improvements -2018-03-24: v1.0.22: +2018-03-24: v1.0.22 * New libusb_set_option() API * Fix transfer timeout not being cleared upon resubmission * Report super speed plus devices on modern Linux and macOS @@ -40,7 +64,7 @@ visit: http://log.libusb.info * Windows: Support cancelation of individual transfers (Vista and later) * Various other bug fixes and improvements -2016-10-01: v1.0.21: +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 diff --git a/INSTALL_WIN.txt b/INSTALL_WIN.txt index 783a479..3ee364d 100644 --- a/INSTALL_WIN.txt +++ b/INSTALL_WIN.txt @@ -1,13 +1,15 @@ Installation Instructions for Windows ************************************* -If you are compiling for MinGW or cygwin, please refer to the INSTALL file. +If you are compiling for MinGW or cygwin, please refer to the INSTALL file, +which is automatically generated by autotools (e.g. running bootstrap.sh). If you are using Microsoft Visual Studio: - Open the relevant solution file in /msvc: libusb_2013.sln for Visual Studio 2013, libusb_2015.sln for Visual Studio 2015, - libusb_2017.sln for Visual Studio 2017 or later. + libusb_2017.sln for Visual Studio 2017, + libusb_2019.sln for Visual Studio 2019 or later. - If you want to debug the library, uncomment the ENABLE_DEBUG_LOGGING define in msvc\config.h - Select your configuration and compile the project @@ -47,6 +49,3 @@ Links Additional information related to the Windows backend: http://windows.libusb.info - -Microsoft Windows SDK Archive: - https://developer.microsoft.com/en-us/windows/downloads/sdk-archive
\ No newline at end of file @@ -1 +1,32 @@ -README.md
\ No newline at end of file +# 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, macOS, +Windows, OpenBSD/NetBSD, Haiku and Solaris 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](COPYING)). + +libusb is abstracted internally in such a way that it can hopefully +be ported to other operating systems. Please see the [PORTING](PORTING) +file for more information. + +libusb homepage: +http://libusb.info/ + +Developers will wish to consult the API documentation: +http://api.libusb.info + +Use the mailing list for questions, comments, etc: +http://mailing-list.libusb.info + +- Hans de Goede <hdegoede@redhat.com> +- Xiaofan Chen <xiaofanc@gmail.com> +- Ludovic Rousseau <ludovic.rousseau@gmail.com> +- Nathan Hjelm <hjelmn@cs.unm.edu> +- Chris Dickens <christopher.a.dickens@gmail.com> + +(Please use the mailing list rather than mailing developers directly) diff --git a/README.md b/README.md index a47b4bd..100b938 100644..120000 --- a/README.md +++ b/README.md @@ -1,32 +1 @@ -# 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, macOS, -Windows, OpenBSD/NetBSD, Haiku and Solaris 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](COPYING)). - -libusb is abstracted internally in such a way that it can hopefully -be ported to other operating systems. Please see the [PORTING](PORTING) -file for more information. - -libusb homepage: -http://libusb.info/ - -Developers will wish to consult the API documentation: -http://api.libusb.info - -Use the mailing list for questions, comments, etc: -http://mailing-list.libusb.info - -- Hans de Goede <hdegoede@redhat.com> -- Xiaofan Chen <xiaofanc@gmail.com> -- Ludovic Rousseau <ludovic.rousseau@gmail.com> -- Nathan Hjelm <hjelmn@cs.unm.edu> -- Chris Dickens <christopher.a.dickens@gmail.com> - -(Please use the mailing list rather than mailing developers directly) +README
\ No newline at end of file diff --git a/Xcode/config.h b/Xcode/config.h index 2366078..73dc2de 100644 --- a/Xcode/config.h +++ b/Xcode/config.h @@ -1,36 +1,151 @@ -/* config.h. Manually generated for Xcode. */ - -#include <AvailabilityMacros.h> +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ /* Define to the attribute for default visibility. */ #define DEFAULT_VISIBILITY __attribute__ ((visibility ("default"))) +/* Define to 1 to start with debug message logging enabled. */ +/* #define ENABLE_DEBUG_LOGGING 1 */ + /* Define to 1 to enable message logging. */ #define ENABLE_LOGGING 1 -/* On 10.12 and later, use newly available clock_*() functions */ -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101200 +/* Define to 1 if you have the <asm/types.h> header file. */ +/* #undef HAVE_ASM_TYPES_H */ + /* Define to 1 if you have the `clock_gettime' function. */ #define HAVE_CLOCK_GETTIME 1 -#endif -/* On 10.6 and later, use newly available pthread_threadid_np() function */ -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 -/* Define to 1 if you have the 'pthread_threadid_np' function. */ -#define HAVE_PTHREAD_THREADID_NP 1 -#endif +/* Define to 1 if you have the declaration of `EFD_CLOEXEC', and to 0 if you + don't. */ +/* #undef HAVE_DECL_EFD_CLOEXEC */ + +/* Define to 1 if you have the declaration of `EFD_NONBLOCK', and to 0 if you + don't. */ +/* #undef HAVE_DECL_EFD_NONBLOCK */ + +/* Define to 1 if you have the declaration of `TFD_CLOEXEC', and to 0 if you + don't. */ +/* #undef HAVE_DECL_TFD_CLOEXEC */ + +/* Define to 1 if you have the declaration of `TFD_NONBLOCK', and to 0 if you + don't. */ +/* #undef HAVE_DECL_TFD_NONBLOCK */ + +/* Define to 1 if you have the <dlfcn.h> header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if the system has eventfd functionality. */ +/* #undef HAVE_EVENTFD */ + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `udev' library (-ludev). */ +/* #undef HAVE_LIBUDEV */ + +/* Define to 1 if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 /* Define to 1 if the system has the type `nfds_t'. */ #define HAVE_NFDS_T 1 +/* Define to 1 if you have the `pipe2' function. */ +/* #undef HAVE_PIPE2 */ + +/* Define to 1 if you have the `pthread_condattr_setclock' function. */ +/* #undef HAVE_PTHREAD_CONDATTR_SETCLOCK */ + +/* Define to 1 if you have the `pthread_setname_np' function. */ +/* #undef HAVE_PTHREAD_SETNAME_NP */ + +/* Define to 1 if you have the `pthread_threadid_np' function. */ +#define HAVE_PTHREAD_THREADID_NP 1 + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if the system has the type `struct timespec'. */ +/* #undef HAVE_STRUCT_TIMESPEC */ + +/* Define to 1 if you have the `syslog' function. */ +/* #undef HAVE_SYSLOG */ + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + /* Define to 1 if you have the <sys/time.h> header file. */ #define HAVE_SYS_TIME_H 1 -/* Define to 1 if using the POSIX poll() implementation. */ -#define POLL_POSIX 1 +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if the system has timerfd functionality. */ +/* #undef HAVE_TIMERFD */ + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Name of package */ +#define PACKAGE "libusb-1.0" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "libusb-devel@lists.sourceforge.net" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libusb-1.0" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libusb-1.0 1.0.24" -/* Define to 1 if using POSIX threads. */ -#define THREADS_POSIX 1 +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libusb-1.0" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "http://libusb.info" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.0.24" + +/* Define to 1 if compiling for a POSIX platform. */ +#define PLATFORM_POSIX 1 + +/* Define to 1 if compiling for a Windows platform. */ +/* #undef PLATFORM_WINDOWS */ + +/* Define to the attribute for enabling parameter checks on printf-like + functions. */ +#define PRINTF_FORMAT(a, b) __attribute__ ((__format__ (__printf__, a, b))) + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 to output logging messages to the systemwide log. */ +/* #undef USE_SYSTEM_LOGGING_FACILITY */ + +/* Version number of package */ +#define VERSION "1.0.24" /* Enable GNU extensions. */ #define _GNU_SOURCE 1 + +/* Define to the oldest supported Windows version. */ +/* #undef _WIN32_WINNT */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif diff --git a/Xcode/libusb.xcodeproj/project.pbxproj b/Xcode/libusb.xcodeproj/project.pbxproj index 54e0ff7..fcda7e2 100644 --- a/Xcode/libusb.xcodeproj/project.pbxproj +++ b/Xcode/libusb.xcodeproj/project.pbxproj @@ -34,15 +34,13 @@ 006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; }; 008A23DA236C85AF004854AA /* stress.c in Sources */ = {isa = PBXBuildFile; fileRef = 008A23C6236C8445004854AA /* stress.c */; }; 008A23DB236C85AF004854AA /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 008A23CB236C849A004854AA /* testlib.c */; }; - 008A23DC236C85BD004854AA /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; }; 008FBF861628B7E800BC5BE2 /* core.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBF541628B7E800BC5BE2 /* core.c */; }; 008FBF871628B7E800BC5BE2 /* descriptor.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBF551628B7E800BC5BE2 /* descriptor.c */; }; 008FBF881628B7E800BC5BE2 /* io.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBF561628B7E800BC5BE2 /* io.c */; }; - 008FBF891628B7E800BC5BE2 /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; }; + 008FBF891628B7E800BC5BE2 /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; settings = {ATTRIBUTES = (Public, ); }; }; 008FBF901628B7E800BC5BE2 /* libusbi.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF671628B7E800BC5BE2 /* libusbi.h */; }; 008FBF921628B7E800BC5BE2 /* darwin_usb.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBF6C1628B7E800BC5BE2 /* darwin_usb.c */; }; 008FBF931628B7E800BC5BE2 /* darwin_usb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF6D1628B7E800BC5BE2 /* darwin_usb.h */; }; - 008FBF971628B7E800BC5BE2 /* poll_posix.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF711628B7E800BC5BE2 /* poll_posix.h */; }; 008FBF9A1628B7E800BC5BE2 /* threads_posix.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBF741628B7E800BC5BE2 /* threads_posix.c */; }; 008FBF9B1628B7E800BC5BE2 /* threads_posix.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF751628B7E800BC5BE2 /* threads_posix.h */; }; 008FBFA01628B7E800BC5BE2 /* sync.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBF7A1628B7E800BC5BE2 /* sync.c */; }; @@ -53,24 +51,21 @@ 008FBFA91628B88000BC5BE2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBFA81628B88000BC5BE2 /* IOKit.framework */; }; 008FBFAB1628B8CB00BC5BE2 /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBFAA1628B8CB00BC5BE2 /* libobjc.dylib */; }; 008FBFEF1628BA3500BC5BE2 /* xusb.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBFED1628BA0E00BC5BE2 /* xusb.c */; }; - 008FBFF01628BA3A00BC5BE2 /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; }; 008FBFFF1628BB9600BC5BE2 /* dpfp.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBFD71628BA0E00BC5BE2 /* dpfp.c */; }; - 008FC0001628BBCD00BC5BE2 /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; }; - 008FC00F1628BBE400BC5BE2 /* dpfp_threaded.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBFDB1628BA0E00BC5BE2 /* dpfp_threaded.c */; }; - 008FC0101628BBE900BC5BE2 /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; }; 008FC01F1628BC1500BC5BE2 /* fxload.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBFE11628BA0E00BC5BE2 /* fxload.c */; }; - 008FC0201628BC1B00BC5BE2 /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; }; 008FC0211628BC5200BC5BE2 /* ezusb.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBFDC1628BA0E00BC5BE2 /* ezusb.c */; }; 008FC0301628BC7400BC5BE2 /* listdevs.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBFE71628BA0E00BC5BE2 /* listdevs.c */; }; - 008FC0311628BC7800BC5BE2 /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; }; 1438D77A17A2ED9F00166101 /* hotplug.c in Sources */ = {isa = PBXBuildFile; fileRef = 1438D77817A2ED9F00166101 /* hotplug.c */; }; 1438D77B17A2ED9F00166101 /* hotplug.h in Headers */ = {isa = PBXBuildFile; fileRef = 1438D77917A2ED9F00166101 /* hotplug.h */; }; - 1438D77D17A2EDCD00166101 /* poll_posix.c in Sources */ = {isa = PBXBuildFile; fileRef = 1438D77C17A2EDCD00166101 /* poll_posix.c */; }; 1438D77F17A2F0EA00166101 /* strerror.c in Sources */ = {isa = PBXBuildFile; fileRef = 1438D77E17A2F0EA00166101 /* strerror.c */; }; + 2018D95F24E453BA001589B2 /* events_posix.c in Sources */ = {isa = PBXBuildFile; fileRef = 2018D95E24E453BA001589B2 /* events_posix.c */; }; + 2018D96124E453D0001589B2 /* events_posix.h in Headers */ = {isa = PBXBuildFile; fileRef = 2018D96024E453D0001589B2 /* events_posix.h */; }; 20468D70243298C100650534 /* sam3u_benchmark.c in Sources */ = {isa = PBXBuildFile; fileRef = 20468D6E243298C100650534 /* sam3u_benchmark.c */; }; 20468D7E2432990100650534 /* testlibusb.c in Sources */ = {isa = PBXBuildFile; fileRef = 20468D7C2432990000650534 /* testlibusb.c */; }; - 20468D7F2432993300650534 /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; }; - 20468D802432993C00650534 /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; }; + 20951C0325630F5F00ED6351 /* dpfp.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBFD71628BA0E00BC5BE2 /* dpfp.c */; settings = {COMPILER_FLAGS = "-DDPFP_THREADED"; }; }; + 20951C0625630F8F00ED6351 /* ezusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFDD1628BA0E00BC5BE2 /* ezusb.h */; }; + 20951C0F25630FD300ED6351 /* libusb_testlib.h in Headers */ = {isa = PBXBuildFile; fileRef = 008A23CA236C849A004854AA /* libusb_testlib.h */; }; + 20951C152563125200ED6351 /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -209,90 +204,6 @@ }; /* End PBXContainerItemProxy section */ -/* Begin PBXCopyFilesBuildPhase section */ - 006AD41A1C8C5A90007F8C6A /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 008A23D1236C8594004854AA /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 008FBFBB1628B9FE00BC5BE2 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 008FBFF31628BB8B00BC5BE2 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 008FC0031628BBDB00BC5BE2 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 008FC0131628BC0300BC5BE2 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 008FC0241628BC6B00BC5BE2 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 20468D65243298AE00650534 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 20468D73243298D300650534 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; -/* End PBXCopyFilesBuildPhase section */ - /* Begin PBXFileReference section */ 006AD41C1C8C5A90007F8C6A /* hotplugtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = hotplugtest; sourceTree = BUILT_PRODUCTS_DIR; }; 006AD4231C8C5AAE007F8C6A /* hotplugtest.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = hotplugtest.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; }; @@ -308,7 +219,6 @@ 008FBF671628B7E800BC5BE2 /* libusbi.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = libusbi.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; }; 008FBF6C1628B7E800BC5BE2 /* darwin_usb.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = darwin_usb.c; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; }; 008FBF6D1628B7E800BC5BE2 /* darwin_usb.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = darwin_usb.h; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; }; - 008FBF711628B7E800BC5BE2 /* poll_posix.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = poll_posix.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; }; 008FBF741628B7E800BC5BE2 /* threads_posix.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = threads_posix.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; }; 008FBF751628B7E800BC5BE2 /* threads_posix.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = threads_posix.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; }; 008FBF7A1628B7E800BC5BE2 /* sync.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = sync.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; }; @@ -320,7 +230,6 @@ 008FBFAA1628B8CB00BC5BE2 /* libobjc.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libobjc.dylib; path = usr/lib/libobjc.dylib; sourceTree = SDKROOT; }; 008FBFBD1628B9FE00BC5BE2 /* xusb */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = xusb; sourceTree = BUILT_PRODUCTS_DIR; }; 008FBFD71628BA0E00BC5BE2 /* dpfp.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = dpfp.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; }; - 008FBFDB1628BA0E00BC5BE2 /* dpfp_threaded.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = dpfp_threaded.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; }; 008FBFDC1628BA0E00BC5BE2 /* ezusb.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = ezusb.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; }; 008FBFDD1628BA0E00BC5BE2 /* ezusb.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = ezusb.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; }; 008FBFE11628BA0E00BC5BE2 /* fxload.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = fxload.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; }; @@ -332,7 +241,6 @@ 008FC0261628BC6B00BC5BE2 /* listdevs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = listdevs; sourceTree = BUILT_PRODUCTS_DIR; }; 1438D77817A2ED9F00166101 /* hotplug.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = hotplug.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; }; 1438D77917A2ED9F00166101 /* hotplug.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = hotplug.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; }; - 1438D77C17A2EDCD00166101 /* poll_posix.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = poll_posix.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; }; 1438D77E17A2F0EA00166101 /* strerror.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = strerror.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; }; 1443EE8416417E63007E0579 /* common.xcconfig */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = text.xcconfig; path = common.xcconfig; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 1; }; 1443EE8516417E63007E0579 /* debug.xcconfig */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = text.xcconfig; path = debug.xcconfig; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 1; }; @@ -340,6 +248,8 @@ 1443EE8716417E63007E0579 /* libusb.xcconfig */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = text.xcconfig; path = libusb.xcconfig; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 1; }; 1443EE8816417E63007E0579 /* release.xcconfig */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = text.xcconfig; path = release.xcconfig; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 1; }; 1443EE8916417EA6007E0579 /* libusb_release.xcconfig */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = text.xcconfig; path = libusb_release.xcconfig; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 1; }; + 2018D95E24E453BA001589B2 /* events_posix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = events_posix.c; sourceTree = "<group>"; }; + 2018D96024E453D0001589B2 /* events_posix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = events_posix.h; sourceTree = "<group>"; }; 20468D67243298AE00650534 /* sam3u_benchmark */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sam3u_benchmark; sourceTree = BUILT_PRODUCTS_DIR; }; 20468D6E243298C100650534 /* sam3u_benchmark.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sam3u_benchmark.c; sourceTree = "<group>"; usesTabs = 1; }; 20468D75243298D300650534 /* testlibusb */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testlibusb; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -359,7 +269,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 008A23DC236C85BD004854AA /* libusb-1.0.0.dylib in Frameworks */, + 006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -377,7 +287,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 008FBFF01628BA3A00BC5BE2 /* libusb-1.0.0.dylib in Frameworks */, + 006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -385,7 +295,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 008FC0001628BBCD00BC5BE2 /* libusb-1.0.0.dylib in Frameworks */, + 006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -393,7 +303,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 008FC0101628BBE900BC5BE2 /* libusb-1.0.0.dylib in Frameworks */, + 006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -401,7 +311,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 008FC0201628BC1B00BC5BE2 /* libusb-1.0.0.dylib in Frameworks */, + 006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -409,7 +319,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 008FC0311628BC7800BC5BE2 /* libusb-1.0.0.dylib in Frameworks */, + 006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -417,7 +327,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 20468D7F2432993300650534 /* libusb-1.0.0.dylib in Frameworks */, + 006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -425,7 +335,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 20468D802432993C00650534 /* libusb-1.0.0.dylib in Frameworks */, + 006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -498,8 +408,8 @@ children = ( 008FBF6C1628B7E800BC5BE2 /* darwin_usb.c */, 008FBF6D1628B7E800BC5BE2 /* darwin_usb.h */, - 1438D77C17A2EDCD00166101 /* poll_posix.c */, - 008FBF711628B7E800BC5BE2 /* poll_posix.h */, + 2018D95E24E453BA001589B2 /* events_posix.c */, + 2018D96024E453D0001589B2 /* events_posix.h */, 008FBF741628B7E800BC5BE2 /* threads_posix.c */, 008FBF751628B7E800BC5BE2 /* threads_posix.h */, ); @@ -510,7 +420,6 @@ isa = PBXGroup; children = ( 008FBFD71628BA0E00BC5BE2 /* dpfp.c */, - 008FBFDB1628BA0E00BC5BE2 /* dpfp_threaded.c */, 008FBFDC1628BA0E00BC5BE2 /* ezusb.c */, 008FBFDD1628BA0E00BC5BE2 /* ezusb.h */, 008FBFE11628BA0E00BC5BE2 /* fxload.c */, @@ -556,18 +465,101 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 008FBF891628B7E800BC5BE2 /* libusb.h in Headers */, 008FBFA51628B84200BC5BE2 /* config.h in Headers */, 008FBF931628B7E800BC5BE2 /* darwin_usb.h in Headers */, + 2018D96124E453D0001589B2 /* events_posix.h in Headers */, 1438D77B17A2ED9F00166101 /* hotplug.h in Headers */, - 008FBF891628B7E800BC5BE2 /* libusb.h in Headers */, 008FBF901628B7E800BC5BE2 /* libusbi.h in Headers */, - 008FBF971628B7E800BC5BE2 /* poll_posix.h in Headers */, 008FBF9B1628B7E800BC5BE2 /* threads_posix.h in Headers */, 008FBFA11628B7E800BC5BE2 /* version.h in Headers */, 008FBFA21628B7E800BC5BE2 /* version_nano.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; + 20951BFF25630EBE00ED6351 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 008FBFA51628B84200BC5BE2 /* config.h in Headers */, + 20951C152563125200ED6351 /* libusb.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 20951C0125630F4100ED6351 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 008FBFA51628B84200BC5BE2 /* config.h in Headers */, + 20951C152563125200ED6351 /* libusb.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 20951C0425630F7600ED6351 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 008FBFA51628B84200BC5BE2 /* config.h in Headers */, + 20951C0625630F8F00ED6351 /* ezusb.h in Headers */, + 20951C152563125200ED6351 /* libusb.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 20951C0725630F9D00ED6351 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 008FBFA51628B84200BC5BE2 /* config.h in Headers */, + 20951C152563125200ED6351 /* libusb.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 20951C0925630FA900ED6351 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 008FBFA51628B84200BC5BE2 /* config.h in Headers */, + 20951C152563125200ED6351 /* libusb.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 20951C0B25630FB400ED6351 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 008FBFA51628B84200BC5BE2 /* config.h in Headers */, + 20951C152563125200ED6351 /* libusb.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 20951C0D25630FC000ED6351 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 008FBFA51628B84200BC5BE2 /* config.h in Headers */, + 20951C0F25630FD300ED6351 /* libusb_testlib.h in Headers */, + 20951C152563125200ED6351 /* libusb.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 20951C1025630FE300ED6351 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 008FBFA51628B84200BC5BE2 /* config.h in Headers */, + 20951C152563125200ED6351 /* libusb.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 20951C1225630FEE00ED6351 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 008FBFA51628B84200BC5BE2 /* config.h in Headers */, + 20951C152563125200ED6351 /* libusb.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ @@ -575,9 +567,9 @@ isa = PBXNativeTarget; buildConfigurationList = 006AD4221C8C5A90007F8C6A /* Build configuration list for PBXNativeTarget "hotplugtest" */; buildPhases = ( + 20951C0725630F9D00ED6351 /* Headers */, 006AD4181C8C5A90007F8C6A /* Sources */, 006AD4191C8C5A90007F8C6A /* Frameworks */, - 006AD41A1C8C5A90007F8C6A /* CopyFiles */, ); buildRules = ( ); @@ -593,9 +585,9 @@ isa = PBXNativeTarget; buildConfigurationList = 008A23D7236C8594004854AA /* Build configuration list for PBXNativeTarget "stress" */; buildPhases = ( + 20951C0D25630FC000ED6351 /* Headers */, 008A23CF236C8594004854AA /* Sources */, 008A23D0236C8594004854AA /* Frameworks */, - 008A23D1236C8594004854AA /* CopyFiles */, ); buildRules = ( ); @@ -611,9 +603,9 @@ isa = PBXNativeTarget; buildConfigurationList = 008FBF351628B79300BC5BE2 /* Build configuration list for PBXNativeTarget "libusb" */; buildPhases = ( + 008FBF2F1628B79300BC5BE2 /* Headers */, 008FBF2D1628B79300BC5BE2 /* Sources */, 008FBF2E1628B79300BC5BE2 /* Frameworks */, - 008FBF2F1628B79300BC5BE2 /* Headers */, ); buildRules = ( ); @@ -628,9 +620,9 @@ isa = PBXNativeTarget; buildConfigurationList = 008FBFC61628B9FE00BC5BE2 /* Build configuration list for PBXNativeTarget "xusb" */; buildPhases = ( + 20951C1225630FEE00ED6351 /* Headers */, 008FBFB91628B9FE00BC5BE2 /* Sources */, 008FBFBA1628B9FE00BC5BE2 /* Frameworks */, - 008FBFBB1628B9FE00BC5BE2 /* CopyFiles */, ); buildRules = ( ); @@ -646,9 +638,9 @@ isa = PBXNativeTarget; buildConfigurationList = 008FBFFC1628BB8C00BC5BE2 /* Build configuration list for PBXNativeTarget "dpfp" */; buildPhases = ( + 20951BFF25630EBE00ED6351 /* Headers */, 008FBFF11628BB8B00BC5BE2 /* Sources */, 008FBFF21628BB8B00BC5BE2 /* Frameworks */, - 008FBFF31628BB8B00BC5BE2 /* CopyFiles */, ); buildRules = ( ); @@ -664,9 +656,9 @@ isa = PBXNativeTarget; buildConfigurationList = 008FC00C1628BBDB00BC5BE2 /* Build configuration list for PBXNativeTarget "dpfp_threaded" */; buildPhases = ( + 20951C0125630F4100ED6351 /* Headers */, 008FC0011628BBDB00BC5BE2 /* Sources */, 008FC0021628BBDB00BC5BE2 /* Frameworks */, - 008FC0031628BBDB00BC5BE2 /* CopyFiles */, ); buildRules = ( ); @@ -682,9 +674,9 @@ isa = PBXNativeTarget; buildConfigurationList = 008FC01C1628BC0300BC5BE2 /* Build configuration list for PBXNativeTarget "fxload" */; buildPhases = ( + 20951C0425630F7600ED6351 /* Headers */, 008FC0111628BC0300BC5BE2 /* Sources */, 008FC0121628BC0300BC5BE2 /* Frameworks */, - 008FC0131628BC0300BC5BE2 /* CopyFiles */, ); buildRules = ( ); @@ -700,9 +692,9 @@ isa = PBXNativeTarget; buildConfigurationList = 008FC02D1628BC6B00BC5BE2 /* Build configuration list for PBXNativeTarget "listdevs" */; buildPhases = ( + 20951C0925630FA900ED6351 /* Headers */, 008FC0221628BC6B00BC5BE2 /* Sources */, 008FC0231628BC6B00BC5BE2 /* Frameworks */, - 008FC0241628BC6B00BC5BE2 /* CopyFiles */, ); buildRules = ( ); @@ -718,9 +710,9 @@ isa = PBXNativeTarget; buildConfigurationList = 20468D6B243298AE00650534 /* Build configuration list for PBXNativeTarget "sam3u_benchmark" */; buildPhases = ( + 20951C0B25630FB400ED6351 /* Headers */, 20468D63243298AE00650534 /* Sources */, 20468D64243298AE00650534 /* Frameworks */, - 20468D65243298AE00650534 /* CopyFiles */, ); buildRules = ( ); @@ -736,9 +728,9 @@ isa = PBXNativeTarget; buildConfigurationList = 20468D79243298D300650534 /* Build configuration list for PBXNativeTarget "testlibusb" */; buildPhases = ( + 20951C1025630FE300ED6351 /* Headers */, 20468D71243298D300650534 /* Sources */, 20468D72243298D300650534 /* Frameworks */, - 20468D73243298D300650534 /* CopyFiles */, ); buildRules = ( ); @@ -826,9 +818,9 @@ 008FBF861628B7E800BC5BE2 /* core.c in Sources */, 008FBF921628B7E800BC5BE2 /* darwin_usb.c in Sources */, 008FBF871628B7E800BC5BE2 /* descriptor.c in Sources */, + 2018D95F24E453BA001589B2 /* events_posix.c in Sources */, 1438D77A17A2ED9F00166101 /* hotplug.c in Sources */, 008FBF881628B7E800BC5BE2 /* io.c in Sources */, - 1438D77D17A2EDCD00166101 /* poll_posix.c in Sources */, 1438D77F17A2F0EA00166101 /* strerror.c in Sources */, 008FBFA01628B7E800BC5BE2 /* sync.c in Sources */, 008FBF9A1628B7E800BC5BE2 /* threads_posix.c in Sources */, @@ -855,7 +847,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 008FC00F1628BBE400BC5BE2 /* dpfp_threaded.c in Sources */, + 20951C0325630F5F00ED6351 /* dpfp.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/android/config.h b/android/config.h index 341c01f..1092f65 100644 --- a/android/config.h +++ b/android/config.h @@ -41,11 +41,12 @@ /* Define to 1 if you have the <sys/time.h> header file. */ #define HAVE_SYS_TIME_H 1 -/* Define to 1 if using the POSIX poll() implementation. */ -#define POLL_POSIX 1 +/* Define to 1 if compiling for a POSIX platform. */ +#define PLATFORM_POSIX 1 -/* Define to 1 if using POSIX threads. */ -#define THREADS_POSIX 1 +/* Define to the attribute for enabling parameter checks on printf-like + functions. */ +#define PRINTF_FORMAT(a, b) __attribute__ ((__format__ (__printf__, a, b))) /* Define to 1 to output logging messages to the systemwide log. */ #define USE_SYSTEM_LOGGING_FACILITY 1 diff --git a/android/jni/examples.mk b/android/jni/examples.mk index 74139ce..30b5c84 100644 --- a/android/jni/examples.mk +++ b/android/jni/examples.mk @@ -28,6 +28,7 @@ LOCAL_SRC_FILES := \ $(LIBUSB_ROOT_REL)/examples/dpfp.c LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/.. \ $(LIBUSB_ROOT_ABS) LOCAL_SHARED_LIBRARIES += libusb1.0 @@ -41,12 +42,13 @@ include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ - $(LIBUSB_ROOT_REL)/examples/dpfp_threaded.c + $(LIBUSB_ROOT_REL)/examples/dpfp.c LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/.. \ $(LIBUSB_ROOT_ABS) -LOCAL_CFLAGS := -pthread +LOCAL_CFLAGS := -DDPFP_THREADED -pthread LOCAL_SHARED_LIBRARIES += libusb1.0 @@ -63,6 +65,7 @@ LOCAL_SRC_FILES := \ $(LIBUSB_ROOT_REL)/examples/fxload.c LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/.. \ $(LIBUSB_ROOT_ABS) LOCAL_SHARED_LIBRARIES += libusb1.0 @@ -79,6 +82,7 @@ LOCAL_SRC_FILES := \ $(LIBUSB_ROOT_REL)/examples/hotplugtest.c LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/.. \ $(LIBUSB_ROOT_ABS) LOCAL_SHARED_LIBRARIES += libusb1.0 @@ -95,6 +99,7 @@ LOCAL_SRC_FILES := \ $(LIBUSB_ROOT_REL)/examples/listdevs.c LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/.. \ $(LIBUSB_ROOT_ABS) LOCAL_SHARED_LIBRARIES += libusb1.0 @@ -111,6 +116,7 @@ LOCAL_SRC_FILES := \ $(LIBUSB_ROOT_REL)/examples/sam3u_benchmark.c LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/.. \ $(LIBUSB_ROOT_ABS) LOCAL_SHARED_LIBRARIES += libusb1.0 @@ -127,6 +133,7 @@ LOCAL_SRC_FILES := \ $(LIBUSB_ROOT_REL)/examples/xusb.c LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/.. \ $(LIBUSB_ROOT_ABS) LOCAL_SHARED_LIBRARIES += libusb1.0 diff --git a/android/jni/libusb.mk b/android/jni/libusb.mk index 3308e79..dacf1ee 100644 --- a/android/jni/libusb.mk +++ b/android/jni/libusb.mk @@ -24,9 +24,6 @@ LIBUSB_ROOT_ABS := $(LOCAL_PATH)/../.. include $(CLEAR_VARS) -LIBUSB_ROOT_REL := ../.. -LIBUSB_ROOT_ABS := $(LOCAL_PATH)/../.. - LOCAL_SRC_FILES := \ $(LIBUSB_ROOT_REL)/libusb/core.c \ $(LIBUSB_ROOT_REL)/libusb/descriptor.c \ @@ -35,7 +32,7 @@ LOCAL_SRC_FILES := \ $(LIBUSB_ROOT_REL)/libusb/sync.c \ $(LIBUSB_ROOT_REL)/libusb/strerror.c \ $(LIBUSB_ROOT_REL)/libusb/os/linux_usbfs.c \ - $(LIBUSB_ROOT_REL)/libusb/os/poll_posix.c \ + $(LIBUSB_ROOT_REL)/libusb/os/events_posix.c \ $(LIBUSB_ROOT_REL)/libusb/os/threads_posix.c \ $(LIBUSB_ROOT_REL)/libusb/os/linux_netlink.c diff --git a/android/jni/tests.mk b/android/jni/tests.mk index 6136f58..b42bd1c 100644 --- a/android/jni/tests.mk +++ b/android/jni/tests.mk @@ -29,6 +29,7 @@ LOCAL_SRC_FILES := \ $(LIBUSB_ROOT_REL)/tests/testlib.c LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/.. \ $(LIBUSB_ROOT_ABS) LOCAL_SHARED_LIBRARIES += libusb1.0 @@ -3,6 +3,6 @@ set -e ./bootstrap.sh -if test -z "$NOCONFIGURE"; then +if [ -z "$NOCONFIGURE" ]; then exec ./configure --enable-examples-build --enable-tests-build "$@" fi diff --git a/bootstrap.sh b/bootstrap.sh index dc56539..cfd2b45 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -1,6 +1,8 @@ #!/bin/sh -if ! test -d m4 ; then +set -e + +if [ ! -d m4 ]; then mkdir m4 fi -autoreconf -ivf || exit 1 +exec autoreconf -ivf diff --git a/configure.ac b/configure.ac index d386053..5b880f6 100644 --- a/configure.ac +++ b/configure.ac @@ -31,9 +31,9 @@ dnl Library versioning dnl These numbers should be tweaked on every release. Read carefully: dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html dnl http://sourceware.org/autobook/autobook/autobook_91.html -lt_current=2 +lt_current=3 lt_revision=0 -lt_age=2 +lt_age=3 LT_LDFLAGS="-version-info ${lt_current}:${lt_revision}:${lt_age} -no-undefined" m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) @@ -67,6 +67,7 @@ CFLAGS="${saved_CFLAGS}" AC_DEFINE([_GNU_SOURCE], [1], [Enable GNU extensions.]) AC_DEFINE([DEFAULT_VISIBILITY], [__attribute__ ((visibility ("default")))], [Define to the attribute for default visibility.]) +AC_DEFINE([PRINTF_FORMAT(a, b)], [__attribute__ ((__format__ (__printf__, a, b)))], [Define to the attribute for enabling parameter checks on printf-like functions.]) create_import_lib= is_android_linux= @@ -75,14 +76,12 @@ case $host in *-darwin*) AC_MSG_RESULT([Darwin/Mac OS X]) backend=darwin - poll=posix - threads=posix + platform=posix ;; *-haiku*) AC_MSG_RESULT([Haiku]) backend=haiku - poll=posix - threads=posix + platform=posix ;; *-linux* | *-uclinux*) dnl on Android Linux, some functions are in different places @@ -96,63 +95,49 @@ case $host in ;; esac backend=linux - poll=posix - threads=posix + platform=posix ;; *-netbsd*) AC_MSG_RESULT([NetBSD]) backend=netbsd - poll=posix - threads=posix + platform=posix ;; *-openbsd*) AC_MSG_RESULT([OpenBSD]) backend=openbsd - poll=posix - threads=posix + platform=posix ;; *-solaris*) AC_MSG_RESULT([SunOS]) backend=sunos - poll=posix - threads=posix + platform=posix ;; *-cygwin*) AC_MSG_RESULT([Windows (using Cygwin)]) backend=windows - poll=windows - threads=posix + platform=windows + EXTRA_CFLAGS="-mwin32" ;; *-mingw* | *msys*) AC_MSG_RESULT([Windows]) backend=windows - poll=windows - threads=windows + platform=windows test "x$enable_shared" = xyes && create_import_lib=yes - EXTRA_CFLAGS="-fno-omit-frame-pointer" + EXTRA_CFLAGS="-mwin32 -fno-omit-frame-pointer" ;; *) AC_MSG_RESULT([Null]) AC_MSG_WARN([The host being compiled for is not supported.]) AC_MSG_WARN([The library may compile but will not function in any useful manner.]) - backend="null" - poll=posix - threads="posix" + backend=null + platform=posix ;; esac -if test "x$poll" = xposix; then - AC_DEFINE([POLL_POSIX], [1], [Define to 1 if using the POSIX poll() implementation.]) +if test "x$platform" = xposix; then + AC_DEFINE([PLATFORM_POSIX], [1], [Define to 1 if compiling for a POSIX platform.]) AC_CHECK_TYPES([nfds_t], [], [], [[#include <poll.h>]]) AC_CHECK_FUNCS([pipe2]) -elif test "x$poll" = xwindows; then - AC_DEFINE([POLL_WINDOWS], [1], [Define to 1 if using the Windows poll() implementation.]) -else - AC_MSG_ERROR([Unknown poll implementation]) -fi - -if test "x$threads" = xposix; then - AC_DEFINE([THREADS_POSIX], [1], [Define to 1 if using POSIX threads.]) dnl Some compilers do not support the '-pthread' option so check for it here saved_CFLAGS="${CFLAGS}" CFLAGS="-Wall -Werror -pthread" @@ -167,10 +152,10 @@ if test "x$threads" = xposix; then AC_SEARCH_LIBS([pthread_create], [pthread], [test "x$ac_cv_search_pthread_create" != "xnone required" && AC_SUBST(THREAD_LIBS, [-lpthread])], [], []) -elif test "x$threads" = xwindows; then - AC_DEFINE([THREADS_WINDOWS], [1], [Define to 1 if using Windows threads.]) +elif test "x$platform" = xwindows; then + AC_DEFINE([PLATFORM_WINDOWS], [1], [Define to 1 if compiling for a Windows platform.]) else - AC_MSG_ERROR([Unknown threads implementation]) + AC_MSG_ERROR([Unknown platform]) fi case $backend in @@ -203,9 +188,6 @@ sunos) windows) AC_CHECK_TYPES([struct timespec], [], [], [[#include <time.h>]]) AC_DEFINE([_WIN32_WINNT], [_WIN32_WINNT_VISTA], [Define to the oldest supported Windows version.]) - dnl Cygwin and MSYS compilers do not define _WIN32 as MinGW and MSVC do - dnl simplify checks for Windows compilation by ensuring it is always defined - EXTRA_CPPFLAGS="-D_WIN32" LT_LDFLAGS="${LT_LDFLAGS} -avoid-version -Wl,--add-stdcall-alias" ;; *) @@ -216,13 +198,57 @@ esac dnl headers not available on all platforms but required on others AC_CHECK_HEADERS([sys/time.h]) -dnl the clock_gettime() function needs certain clock IDs defined -AC_CHECK_FUNCS([clock_gettime], [have_clock_gettime=yes], [have_clock_gettime=]) -if test "x$have_clock_gettime" = xyes; then - AC_CHECK_DECL([CLOCK_REALTIME], [], [AC_MSG_ERROR([C library headers missing definition for CLOCK_REALTIME])], [[#include <time.h>]]) - AC_CHECK_DECL([CLOCK_MONOTONIC], [], [AC_MSG_ERROR([C library headers missing definition for CLOCK_MONOTONIC])], [[#include <time.h>]]) -elif test "x$backend" != xdarwin && test "x$backend" != xwindows; then - AC_MSG_ERROR([clock_gettime() is required on this platform]) +if test "x$platform" = xposix; then + dnl the clock_gettime() function needs certain clock IDs defined + AC_CHECK_FUNCS([clock_gettime], [have_clock_gettime=yes], [have_clock_gettime=]) + if test "x$have_clock_gettime" = xyes; then + AC_CHECK_DECL([CLOCK_MONOTONIC], [], [AC_MSG_ERROR([C library headers missing definition for CLOCK_MONOTONIC])], [[#include <time.h>]]) + dnl use the monotonic clock for condition variable timed waits if possible + AC_CHECK_FUNCS([pthread_condattr_setclock], [need_clock_realtime=], [need_clock_realtime=yes]) + if test "x$need_clock_realtime" = xyes; then + AC_CHECK_DECL([CLOCK_REALTIME], [], [AC_MSG_ERROR([C library headers missing definition for CLOCK_REALTIME])], [[#include <time.h>]]) + fi + elif test "x$backend" != xdarwin; then + AC_MSG_ERROR([clock_gettime() is required on this platform]) + fi +fi + +dnl eventfd support +if test "x$backend" = xlinux || test "x$backend" = xsunos; then + AC_ARG_ENABLE([eventfd], + [AS_HELP_STRING([--enable-eventfd], [use eventfd for signalling [default=auto]])], + [use_eventfd=$enableval], + [use_eventfd=auto]) + if test "x$use_eventfd" != xno; then + AC_CHECK_HEADER([sys/eventfd.h], [eventfd_h=yes], [eventfd_h=]) + if test "x$eventfd_h" = xyes; then + AC_CHECK_DECLS([EFD_NONBLOCK, EFD_CLOEXEC], [eventfd_h_ok=yes], [eventfd_h_ok=], [[#include <sys/eventfd.h>]]) + if test "x$eventfd_h_ok" = xyes; then + AC_CHECK_FUNC([eventfd], [eventfd_ok=yes], [eventfd_ok=]) + if test "x$eventfd_ok" = xyes; then + AC_DEFINE([HAVE_EVENTFD], [1], [Define to 1 if the system has eventfd functionality.]) + elif test "x$use_eventfd" = xyes; then + AC_MSG_ERROR([eventfd() function not found; glibc 2.9+ required]) + fi + elif test "x$use_eventfd" = xyes; then + AC_MSG_ERROR([eventfd header not usable; glibc 2.9+ required]) + fi + elif test "x$use_eventfd" = xyes; then + AC_MSG_ERROR([eventfd header not available; glibc 2.9+ required]) + fi + fi + AC_MSG_CHECKING([whether to use eventfd for signalling]) + if test "x$use_eventfd" = xno; then + AC_MSG_RESULT([no (disabled by user)]) + elif test "x$eventfd_h" != xyes; then + AC_MSG_RESULT([no (header not available)]) + elif test "x$eventfd_h_ok" != xyes; then + AC_MSG_RESULT([no (header not usable)]) + elif test "x$eventfd_ok" != xyes; then + AC_MSG_RESULT([no (functions not available)]) + else + AC_MSG_RESULT([yes]) + fi fi dnl timerfd support @@ -300,10 +326,6 @@ AC_ARG_ENABLE([examples-build], [AS_HELP_STRING([--enable-examples-build], [build example applications [default=no]])], [build_examples=$enableval], [build_examples=no]) -if test "x$build_examples" != xno; then - dnl sigaction needed for some example programs - AC_CHECK_FUNC([sigaction], [have_sigaction=yes], [have_sigaction=]) -fi dnl Tests build AC_ARG_ENABLE([tests-build], @@ -314,7 +336,6 @@ AC_ARG_ENABLE([tests-build], AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$build_examples" != xno]) AM_CONDITIONAL([BUILD_TESTS], [test "x$build_tests" != xno]) AM_CONDITIONAL([CREATE_IMPORT_LIB], [test "x$create_import_lib" = xyes]) -AM_CONDITIONAL([HAVE_SIGACTION], [test "x$have_sigaction" = xyes]) AM_CONDITIONAL([OS_DARWIN], [test "x$backend" = xdarwin]) AM_CONDITIONAL([OS_HAIKU], [test "x$backend" = xhaiku]) AM_CONDITIONAL([OS_LINUX], [test "x$backend" = xlinux]) @@ -323,10 +344,8 @@ AM_CONDITIONAL([OS_NULL], [test "x$backend" = xnull]) AM_CONDITIONAL([OS_OPENBSD], [test "x$backend" = xopenbsd]) AM_CONDITIONAL([OS_SUNOS], [test "x$backend" = xsunos]) AM_CONDITIONAL([OS_WINDOWS], [test "x$backend" = xwindows]) -AM_CONDITIONAL([POLL_POSIX], [test "x$poll" = xposix]) -AM_CONDITIONAL([POLL_WINDOWS], [test "x$poll" = xwindows]) -AM_CONDITIONAL([THREADS_POSIX], [test "x$threads" = xposix]) -AM_CONDITIONAL([THREADS_WINDOWS], [test "x$threads" = xwindows]) +AM_CONDITIONAL([PLATFORM_POSIX], [test "x$platform" = xposix]) +AM_CONDITIONAL([PLATFORM_WINDOWS], [test "x$platform" = xwindows]) AM_CONDITIONAL([USE_UDEV], [test "x$use_udev" = xyes]) dnl The -Wcast-function-type warning causes a flurry of warnings when compiling diff --git a/doc/Makefile.in b/doc/Makefile.in index 26400b5..45c3209 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -5,7 +5,7 @@ LIBUSB_DOC_SRC = $(filter-out $(addprefix $(LIBUSB_SRC_DIR)/,$(EXCLUDED_FILES)), docs: @DOXYGEN_HTMLDIR@ -@DOXYGEN_HTMLDIR@: doxygen.cfg libusb.png $(LIBUSB_DOC_SRC) +@DOXYGEN_HTMLDIR@: doxygen.cfg @top_srcdir@/doc/libusb.png $(LIBUSB_DOC_SRC) doxygen $< sfurl = web.sourceforge.net:/home/project-web/libusb/htdocs diff --git a/doc/doxygen.cfg.in b/doc/doxygen.cfg.in index f4ccf1e..569e465 100644 --- a/doc/doxygen.cfg.in +++ b/doc/doxygen.cfg.in @@ -51,7 +51,7 @@ PROJECT_BRIEF = "A cross-platform user library to access USB devices" # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. -PROJECT_LOGO = libusb.png +PROJECT_LOGO = @top_srcdir@/doc/libusb.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is diff --git a/examples/Makefile.am b/examples/Makefile.am index 2658490..540b027 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -2,17 +2,11 @@ AM_CPPFLAGS = -I$(top_srcdir)/libusb LDADD = ../libusb/libusb-1.0.la LIBS = -noinst_PROGRAMS = fxload hotplugtest listdevs testlibusb xusb +noinst_PROGRAMS = dpfp dpfp_threaded fxload hotplugtest listdevs sam3u_benchmark testlibusb xusb -fxload_SOURCES = ezusb.c ezusb.h fxload.c - -if HAVE_SIGACTION -noinst_PROGRAMS += dpfp -if THREADS_POSIX -noinst_PROGRAMS += dpfp_threaded +dpfp_threaded_CPPFLAGS = $(AM_CPPFLAGS) -DDPFP_THREADED dpfp_threaded_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS) dpfp_threaded_LDADD = $(LDADD) $(THREAD_LIBS) -endif +dpfp_threaded_SOURCES = dpfp.c -noinst_PROGRAMS += sam3u_benchmark -endif +fxload_SOURCES = ezusb.c ezusb.h fxload.c diff --git a/examples/dpfp.c b/examples/dpfp.c index 77f9476..a3a76df 100644 --- a/examples/dpfp.c +++ b/examples/dpfp.c @@ -1,6 +1,8 @@ /* * libusb example program to manipulate U.are.U 4000B fingerprint scanner. * Copyright © 2007 Daniel Drake <dsd@gentoo.org> + * Copyright © 2016 Nathan Hjelm <hjelmn@mac.com> + * Copyright © 2020 Chris Dickens <christopher.a.dickens@gmail.com> * * Basic image capture program only, does not consider the powerup quirks or * the fact that image encryption may be enabled. Not expected to work @@ -21,14 +23,121 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <config.h> + #include <errno.h> #include <signal.h> -#include <string.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include "libusb.h" +#if defined(_MSC_VER) +#define snprintf _snprintf +#endif + +#if defined(DPFP_THREADED) +#if defined(PLATFORM_POSIX) +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <unistd.h> + +#define THREAD_RETURN_VALUE NULL +typedef sem_t * semaphore_t; +typedef pthread_t thread_t; + +static inline semaphore_t semaphore_create(void) +{ + sem_t *semaphore; + char name[50]; + + sprintf(name, "/org.libusb.example.dpfp_threaded:%d", (int)getpid()); + semaphore = sem_open(name, O_CREAT | O_EXCL, 0, 0); + if (semaphore == SEM_FAILED) + return NULL; + /* Remove semaphore so that it does not persist after process exits */ + (void)sem_unlink(name); + return semaphore; +} + +static inline void semaphore_give(semaphore_t semaphore) +{ + (void)sem_post(semaphore); +} + +static inline void semaphore_take(semaphore_t semaphore) +{ + (void)sem_wait(semaphore); +} + +static inline void semaphore_destroy(semaphore_t semaphore) +{ + (void)sem_close(semaphore); +} + +static inline int thread_create(thread_t *thread, + void *(*thread_entry)(void *arg), void *arg) +{ + return pthread_create(thread, NULL, thread_entry, arg) == 0 ? 0 : -1; +} + +static inline void thread_join(thread_t thread) +{ + (void)pthread_join(thread, NULL); +} +#elif defined(PLATFORM_WINDOWS) +#define THREAD_RETURN_VALUE 0 +typedef HANDLE semaphore_t; +typedef HANDLE thread_t; + +#if defined(__CYGWIN__) +typedef DWORD thread_return_t; +#else +#include <process.h> +typedef unsigned thread_return_t; +#endif + +static inline semaphore_t semaphore_create(void) +{ + return CreateSemaphore(NULL, 0, 1, NULL); +} + +static inline void semaphore_give(semaphore_t semaphore) +{ + (void)ReleaseSemaphore(semaphore, 1, NULL); +} + +static inline void semaphore_take(semaphore_t semaphore) +{ + (void)WaitForSingleObject(semaphore, INFINITE); +} + +static inline void semaphore_destroy(semaphore_t semaphore) +{ + (void)CloseHandle(semaphore); +} + +static inline int thread_create(thread_t *thread, + thread_return_t (__stdcall *thread_entry)(void *arg), void *arg) +{ +#if defined(__CYGWIN__) + *thread = CreateThread(NULL, 0, thread_entry, arg, 0, NULL); +#else + *thread = (HANDLE)_beginthreadex(NULL, 0, thread_entry, arg, 0, NULL); +#endif + return *thread != NULL ? 0 : -1; +} + +static inline void thread_join(thread_t thread) +{ + (void)WaitForSingleObject(thread, INFINITE); + (void)CloseHandle(thread); +} +#endif +#endif + #define EP_INTR (1 | LIBUSB_ENDPOINT_IN) #define EP_DATA (2 | LIBUSB_ENDPOINT_IN) #define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN) @@ -57,25 +166,65 @@ enum { }; static int state = 0; -static struct libusb_device_handle *devh = NULL; +static libusb_device_handle *devh = NULL; static unsigned char imgbuf[0x1b340]; static unsigned char irqbuf[INTR_LENGTH]; static struct libusb_transfer *img_transfer = NULL; static struct libusb_transfer *irq_transfer = NULL; static int img_idx = 0; -static int do_exit = 0; +static volatile sig_atomic_t do_exit = 0; + +#if defined(DPFP_THREADED) +static semaphore_t exit_semaphore; +static thread_t poll_thread; +#endif + +static void request_exit(sig_atomic_t code) +{ + do_exit = code; +#if defined(DPFP_THREADED) + semaphore_give(exit_semaphore); +#endif +} + +#if defined(DPFP_THREADED) +#if defined(PLATFORM_POSIX) +static void *poll_thread_main(void *arg) +#elif defined(PLATFORM_WINDOWS) +static thread_return_t __stdcall poll_thread_main(void *arg) +#endif +{ + (void)arg; + + printf("poll thread running\n"); + + while (!do_exit) { + struct timeval tv = { 1, 0 }; + int r; + + r = libusb_handle_events_timeout(NULL, &tv); + if (r < 0) { + request_exit(2); + break; + } + } + + printf("poll thread shutting down\n"); + return THREAD_RETURN_VALUE; +} +#endif static int find_dpfp_device(void) { devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a); - return devh ? 0 : -EIO; + return devh ? 0 : -ENODEV; } static int print_f0_data(void) { unsigned char data[0x10]; + size_t i; int r; - unsigned int i; r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0xf0, 0, data, sizeof(data), 0); @@ -83,14 +232,14 @@ static int print_f0_data(void) fprintf(stderr, "F0 error %d\n", r); return r; } - if ((unsigned int) r < sizeof(data)) { + if (r < (int)sizeof(data)) { fprintf(stderr, "short read (%d)\n", r); return -1; } printf("F0 data:"); for (i = 0; i < sizeof(data); i++) - printf("%02x ", data[i]); + printf(" %02x", data[i]); printf("\n"); return 0; } @@ -104,7 +253,7 @@ static int get_hwstat(unsigned char *status) fprintf(stderr, "read hwstat error %d\n", r); return r; } - if ((unsigned int) r < 1) { + if (r < 1) { fprintf(stderr, "short read (%d)\n", r); return -1; } @@ -123,8 +272,8 @@ static int set_hwstat(unsigned char data) fprintf(stderr, "set hwstat error %d\n", r); return r; } - if ((unsigned int) r < 1) { - fprintf(stderr, "short write (%d)", r); + if (r < 1) { + fprintf(stderr, "short write (%d)\n", r); return -1; } @@ -134,15 +283,15 @@ static int set_hwstat(unsigned char data) static int set_mode(unsigned char data) { int r; - printf("set mode %02x\n", data); + printf("set mode %02x\n", data); r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x4e, 0, &data, 1, 0); if (r < 0) { fprintf(stderr, "set mode error %d\n", r); return r; } - if ((unsigned int) r < 1) { - fprintf(stderr, "short write (%d)", r); + if (r < 1) { + fprintf(stderr, "short write (%d)\n", r); return -1; } @@ -153,18 +302,18 @@ static void LIBUSB_CALL cb_mode_changed(struct libusb_transfer *transfer) { if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { fprintf(stderr, "mode change transfer not completed!\n"); - do_exit = 2; + request_exit(2); } printf("async cb_mode_changed length=%d actual_length=%d\n", transfer->length, transfer->actual_length); if (next_state() < 0) - do_exit = 2; + request_exit(2); } static int set_mode_async(unsigned char data) { - unsigned char *buf = (unsigned char*) malloc(LIBUSB_CONTROL_SETUP_SIZE + 1); + unsigned char *buf = malloc(LIBUSB_CONTROL_SETUP_SIZE + 1); struct libusb_transfer *transfer; if (!buf) @@ -203,7 +352,7 @@ static int do_sync_intr(unsigned char *data) return -1; } - printf("recv interrupt %04x\n", *((uint16_t *) data)); + printf("recv interrupt %04x\n", *((uint16_t *)data)); return 0; } @@ -223,17 +372,17 @@ static int sync_intr(unsigned char type) static int save_to_file(unsigned char *data) { - FILE *fd; + FILE *f; char filename[64]; snprintf(filename, sizeof(filename), "finger%d.pgm", img_idx++); - fd = fopen(filename, "w"); - if (!fd) + f = fopen(filename, "w"); + if (!f) return -1; - fputs("P5 384 289 255 ", fd); - (void) fwrite(data + 64, 1, 384*289, fd); - fclose(fd); + fputs("P5 384 289 255 ", f); + (void)fwrite(data + 64, 1, 384*289, f); + fclose(f); printf("saved image to %s\n", filename); return 0; } @@ -241,6 +390,7 @@ static int save_to_file(unsigned char *data) static int next_state(void) { int r = 0; + printf("old state: %d\n", state); switch (state) { case STATE_AWAIT_IRQ_FINGER_REMOVED: @@ -282,57 +432,60 @@ static void LIBUSB_CALL cb_irq(struct libusb_transfer *transfer) if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { fprintf(stderr, "irq transfer status %d?\n", transfer->status); - do_exit = 2; - libusb_free_transfer(transfer); - irq_transfer = NULL; - return; + goto err_free_transfer; } printf("IRQ callback %02x\n", irqtype); switch (state) { case STATE_AWAIT_IRQ_FINGER_DETECTED: if (irqtype == 0x01) { - if (next_state() < 0) { - do_exit = 2; - return; - } + if (next_state() < 0) + goto err_free_transfer; } else { printf("finger-on-sensor detected in wrong state!\n"); } break; case STATE_AWAIT_IRQ_FINGER_REMOVED: if (irqtype == 0x02) { - if (next_state() < 0) { - do_exit = 2; - return; - } + if (next_state() < 0) + goto err_free_transfer; } else { printf("finger-on-sensor detected in wrong state!\n"); } break; } if (libusb_submit_transfer(irq_transfer) < 0) - do_exit = 2; + goto err_free_transfer; + + return; + +err_free_transfer: + libusb_free_transfer(transfer); + irq_transfer = NULL; + request_exit(2); } static void LIBUSB_CALL cb_img(struct libusb_transfer *transfer) { if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { fprintf(stderr, "img transfer status %d?\n", transfer->status); - do_exit = 2; - libusb_free_transfer(transfer); - img_transfer = NULL; - return; + goto err_free_transfer; } printf("Image callback\n"); save_to_file(imgbuf); - if (next_state() < 0) { - do_exit = 2; - return; - } + if (next_state() < 0) + goto err_free_transfer; + if (libusb_submit_transfer(img_transfer) < 0) - do_exit = 2; + goto err_free_transfer; + + return; + +err_free_transfer: + libusb_free_transfer(transfer); + img_transfer = NULL; + request_exit(2); } static int init_capture(void) @@ -413,17 +566,33 @@ static void sighandler(int signum) { (void)signum; - do_exit = 1; + request_exit(1); } -int main(void) +static void setup_signals(void) { +#if defined(PLATFORM_POSIX) struct sigaction sigact; + + sigact.sa_handler = sighandler; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + (void)sigaction(SIGINT, &sigact, NULL); + (void)sigaction(SIGTERM, &sigact, NULL); + (void)sigaction(SIGQUIT, &sigact, NULL); +#else + (void)signal(SIGINT, sighandler); + (void)signal(SIGTERM, sighandler); +#endif +} + +int main(void) +{ int r; r = libusb_init(NULL); if (r < 0) { - fprintf(stderr, "failed to initialise libusb\n"); + fprintf(stderr, "failed to initialise libusb %d - %s\n", r, libusb_strerror(r)); exit(1); } @@ -435,7 +604,7 @@ int main(void) r = libusb_claim_interface(devh, 0); if (r < 0) { - fprintf(stderr, "usb_claim_interface error %d\n", r); + fprintf(stderr, "claim interface error %d - %s\n", r, libusb_strerror(r)); goto out; } printf("claimed interface\n"); @@ -449,45 +618,66 @@ int main(void) goto out_deinit; /* async from here onwards */ + setup_signals(); r = alloc_transfers(); if (r < 0) goto out_deinit; +#if defined(DPFP_THREADED) + exit_semaphore = semaphore_create(); + if (!exit_semaphore) { + fprintf(stderr, "failed to initialise semaphore\n"); + goto out_deinit; + } + + r = thread_create(&poll_thread, poll_thread_main, NULL); + if (r) { + semaphore_destroy(exit_semaphore); + goto out_deinit; + } + r = init_capture(); if (r < 0) - goto out_deinit; + request_exit(2); - sigact.sa_handler = sighandler; - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = 0; - sigaction(SIGINT, &sigact, NULL); - sigaction(SIGTERM, &sigact, NULL); - sigaction(SIGQUIT, &sigact, NULL); + while (!do_exit) + semaphore_take(exit_semaphore); +#else + r = init_capture(); + if (r < 0) + goto out_deinit; while (!do_exit) { r = libusb_handle_events(NULL); if (r < 0) - goto out_deinit; + request_exit(2); } +#endif printf("shutting down...\n"); - if (irq_transfer) { - r = libusb_cancel_transfer(irq_transfer); - if (r < 0) - goto out_deinit; - } +#if defined(DPFP_THREADED) + thread_join(poll_thread); + semaphore_destroy(exit_semaphore); +#endif if (img_transfer) { r = libusb_cancel_transfer(img_transfer); if (r < 0) - goto out_deinit; + fprintf(stderr, "failed to cancel transfer %d - %s\n", r, libusb_strerror(r)); } - while (irq_transfer || img_transfer) + if (irq_transfer) { + r = libusb_cancel_transfer(irq_transfer); + if (r < 0) + fprintf(stderr, "failed to cancel transfer %d - %s\n", r, libusb_strerror(r)); + } + + while (img_transfer || irq_transfer) { if (libusb_handle_events(NULL) < 0) break; + } if (do_exit == 1) r = 0; @@ -495,8 +685,10 @@ int main(void) r = 1; out_deinit: - libusb_free_transfer(img_transfer); - libusb_free_transfer(irq_transfer); + if (img_transfer) + libusb_free_transfer(img_transfer); + if (irq_transfer) + libusb_free_transfer(irq_transfer); set_mode(0); set_hwstat(0x80); out_release: diff --git a/examples/dpfp_threaded.c b/examples/dpfp_threaded.c deleted file mode 100644 index ee6aad0..0000000 --- a/examples/dpfp_threaded.c +++ /dev/null @@ -1,557 +0,0 @@ -/* - * libusb example program to manipulate U.are.U 4000B fingerprint scanner. - * Copyright © 2007 Daniel Drake <dsd@gentoo.org> - * Copyright © 2016 Nathan Hjelm <hjelmn@mac.com> - * - * Basic image capture program only, does not consider the powerup quirks or - * the fact that image encryption may be enabled. Not expected to work - * flawlessly all of the time. - * - * 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 <errno.h> -#include <pthread.h> -#include <semaphore.h> -#include <signal.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <fcntl.h> - -#include "libusb.h" - -#define EP_INTR (1 | LIBUSB_ENDPOINT_IN) -#define EP_DATA (2 | LIBUSB_ENDPOINT_IN) -#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN) -#define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT) -#define USB_RQ 0x04 -#define INTR_LENGTH 64 -#define SEM_NAME "/org.libusb.example.dpfp_threaded" - -enum { - MODE_INIT = 0x00, - MODE_AWAIT_FINGER_ON = 0x10, - MODE_AWAIT_FINGER_OFF = 0x12, - MODE_CAPTURE = 0x20, - MODE_SHUT_UP = 0x30, - MODE_READY = 0x80, -}; - -static int next_state(void); - -enum { - STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON = 1, - STATE_AWAIT_IRQ_FINGER_DETECTED, - STATE_AWAIT_MODE_CHANGE_CAPTURE, - STATE_AWAIT_IMAGE, - STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF, - STATE_AWAIT_IRQ_FINGER_REMOVED, -}; - -static int state = 0; -static struct libusb_device_handle *devh = NULL; -static unsigned char imgbuf[0x1b340]; -static unsigned char irqbuf[INTR_LENGTH]; -static struct libusb_transfer *img_transfer = NULL; -static struct libusb_transfer *irq_transfer = NULL; -static int img_idx = 0; -static volatile sig_atomic_t do_exit = 0; - -static pthread_t poll_thread; -static sem_t *exit_sem; - -static void request_exit(sig_atomic_t code) -{ - do_exit = code; - sem_post(exit_sem); -} - -static void *poll_thread_main(void *arg) -{ - int r = 0; - printf("poll thread running\n"); - - (void)arg; - - while (!do_exit) { - struct timeval tv = { 1, 0 }; - r = libusb_handle_events_timeout(NULL, &tv); - if (r < 0) { - request_exit(2); - break; - } - } - - printf("poll thread shutting down\n"); - return NULL; -} - -static int find_dpfp_device(void) -{ - devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a); - return devh ? 0 : -EIO; -} - -static int print_f0_data(void) -{ - unsigned char data[0x10]; - int r; - unsigned int i; - - r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0xf0, 0, data, - sizeof(data), 0); - if (r < 0) { - fprintf(stderr, "F0 error %d\n", r); - return r; - } - if ((unsigned int) r < sizeof(data)) { - fprintf(stderr, "short read (%d)\n", r); - return -1; - } - - printf("F0 data:"); - for (i = 0; i < sizeof(data); i++) - printf("%02x ", data[i]); - printf("\n"); - return 0; -} - -static int get_hwstat(unsigned char *status) -{ - int r; - - r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0x07, 0, status, 1, 0); - if (r < 0) { - fprintf(stderr, "read hwstat error %d\n", r); - return r; - } - if ((unsigned int) r < 1) { - fprintf(stderr, "short read (%d)\n", r); - return -1; - } - - printf("hwstat reads %02x\n", *status); - return 0; -} - -static int set_hwstat(unsigned char data) -{ - int r; - - printf("set hwstat to %02x\n", data); - r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x07, 0, &data, 1, 0); - if (r < 0) { - fprintf(stderr, "set hwstat error %d\n", r); - return r; - } - if ((unsigned int) r < 1) { - fprintf(stderr, "short write (%d)", r); - return -1; - } - - return 0; -} - -static int set_mode(unsigned char data) -{ - int r; - printf("set mode %02x\n", data); - - r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x4e, 0, &data, 1, 0); - if (r < 0) { - fprintf(stderr, "set mode error %d\n", r); - return r; - } - if ((unsigned int) r < 1) { - fprintf(stderr, "short write (%d)", r); - return -1; - } - - return 0; -} - -static void LIBUSB_CALL cb_mode_changed(struct libusb_transfer *transfer) -{ - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fprintf(stderr, "mode change transfer not completed!\n"); - request_exit(2); - } - - printf("async cb_mode_changed length=%d actual_length=%d\n", - transfer->length, transfer->actual_length); - if (next_state() < 0) - request_exit(2); -} - -static int set_mode_async(unsigned char data) -{ - unsigned char *buf = (unsigned char*) malloc(LIBUSB_CONTROL_SETUP_SIZE + 1); - struct libusb_transfer *transfer; - - if (!buf) - return -ENOMEM; - - transfer = libusb_alloc_transfer(0); - if (!transfer) { - free(buf); - return -ENOMEM; - } - - printf("async set mode %02x\n", data); - libusb_fill_control_setup(buf, CTRL_OUT, USB_RQ, 0x4e, 0, 1); - buf[LIBUSB_CONTROL_SETUP_SIZE] = data; - libusb_fill_control_transfer(transfer, devh, buf, cb_mode_changed, NULL, - 1000); - - transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK - | LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; - return libusb_submit_transfer(transfer); -} - -static int do_sync_intr(unsigned char *data) -{ - int r; - int transferred; - - r = libusb_interrupt_transfer(devh, EP_INTR, data, INTR_LENGTH, - &transferred, 1000); - if (r < 0) { - fprintf(stderr, "intr error %d\n", r); - return r; - } - if (transferred < INTR_LENGTH) { - fprintf(stderr, "short read (%d)\n", r); - return -1; - } - - printf("recv interrupt %04x\n", *((uint16_t *) data)); - return 0; -} - -static int sync_intr(unsigned char type) -{ - int r; - unsigned char data[INTR_LENGTH]; - - while (1) { - r = do_sync_intr(data); - if (r < 0) - return r; - if (data[0] == type) - return 0; - } -} - -static int save_to_file(unsigned char *data) -{ - FILE *fd; - char filename[64]; - - snprintf(filename, sizeof(filename), "finger%d.pgm", img_idx++); - fd = fopen(filename, "w"); - if (!fd) - return -1; - - fputs("P5 384 289 255 ", fd); - (void) fwrite(data + 64, 1, 384*289, fd); - fclose(fd); - printf("saved image to %s\n", filename); - return 0; -} - -static int next_state(void) -{ - int r = 0; - printf("old state: %d\n", state); - switch (state) { - case STATE_AWAIT_IRQ_FINGER_REMOVED: - state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON; - r = set_mode_async(MODE_AWAIT_FINGER_ON); - break; - case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON: - state = STATE_AWAIT_IRQ_FINGER_DETECTED; - break; - case STATE_AWAIT_IRQ_FINGER_DETECTED: - state = STATE_AWAIT_MODE_CHANGE_CAPTURE; - r = set_mode_async(MODE_CAPTURE); - break; - case STATE_AWAIT_MODE_CHANGE_CAPTURE: - state = STATE_AWAIT_IMAGE; - break; - case STATE_AWAIT_IMAGE: - state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF; - r = set_mode_async(MODE_AWAIT_FINGER_OFF); - break; - case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF: - state = STATE_AWAIT_IRQ_FINGER_REMOVED; - break; - default: - printf("unrecognised state %d\n", state); - } - if (r < 0) { - fprintf(stderr, "error detected changing state\n"); - return r; - } - - printf("new state: %d\n", state); - return 0; -} - -static void LIBUSB_CALL cb_irq(struct libusb_transfer *transfer) -{ - unsigned char irqtype = transfer->buffer[0]; - - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fprintf(stderr, "irq transfer status %d?\n", transfer->status); - irq_transfer = NULL; - request_exit(2); - return; - } - - printf("IRQ callback %02x\n", irqtype); - switch (state) { - case STATE_AWAIT_IRQ_FINGER_DETECTED: - if (irqtype == 0x01) { - if (next_state() < 0) { - request_exit(2); - return; - } - } else { - printf("finger-on-sensor detected in wrong state!\n"); - } - break; - case STATE_AWAIT_IRQ_FINGER_REMOVED: - if (irqtype == 0x02) { - if (next_state() < 0) { - request_exit(2); - return; - } - } else { - printf("finger-on-sensor detected in wrong state!\n"); - } - break; - } - if (libusb_submit_transfer(irq_transfer) < 0) - request_exit(2); -} - -static void LIBUSB_CALL cb_img(struct libusb_transfer *transfer) -{ - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fprintf(stderr, "img transfer status %d?\n", transfer->status); - img_transfer = NULL; - request_exit(2); - return; - } - - printf("Image callback\n"); - save_to_file(imgbuf); - if (next_state() < 0) { - request_exit(2); - return; - } - if (libusb_submit_transfer(img_transfer) < 0) - request_exit(2); -} - -static int init_capture(void) -{ - int r; - - r = libusb_submit_transfer(irq_transfer); - if (r < 0) - return r; - - r = libusb_submit_transfer(img_transfer); - if (r < 0) { - libusb_cancel_transfer(irq_transfer); - while (irq_transfer) - if (libusb_handle_events(NULL) < 0) - break; - return r; - } - - /* start state machine */ - state = STATE_AWAIT_IRQ_FINGER_REMOVED; - return next_state(); -} - -static int do_init(void) -{ - unsigned char status; - int r; - - r = get_hwstat(&status); - if (r < 0) - return r; - - if (!(status & 0x80)) { - r = set_hwstat(status | 0x80); - if (r < 0) - return r; - r = get_hwstat(&status); - if (r < 0) - return r; - } - - status &= ~0x80; - r = set_hwstat(status); - if (r < 0) - return r; - - r = get_hwstat(&status); - if (r < 0) - return r; - - r = sync_intr(0x56); - if (r < 0) - return r; - - return 0; -} - -static int alloc_transfers(void) -{ - img_transfer = libusb_alloc_transfer(0); - if (!img_transfer) - return -ENOMEM; - - irq_transfer = libusb_alloc_transfer(0); - if (!irq_transfer) - return -ENOMEM; - - libusb_fill_bulk_transfer(img_transfer, devh, EP_DATA, imgbuf, - sizeof(imgbuf), cb_img, NULL, 0); - libusb_fill_interrupt_transfer(irq_transfer, devh, EP_INTR, irqbuf, - sizeof(irqbuf), cb_irq, NULL, 0); - - return 0; -} - -static void sighandler(int signum) -{ - (void)signum; - - request_exit(1); -} - -int main(void) -{ - struct sigaction sigact; - int r = 1; - - exit_sem = sem_open (SEM_NAME, O_CREAT, 0); - if (!exit_sem) { - fprintf(stderr, "failed to initialise semaphore error %d", errno); - exit(1); - } - - /* only using this semaphore in this process so go ahead and unlink it now */ - sem_unlink (SEM_NAME); - - r = libusb_init(NULL); - if (r < 0) { - fprintf(stderr, "failed to initialise libusb\n"); - exit(1); - } - - r = find_dpfp_device(); - if (r < 0) { - fprintf(stderr, "Could not find/open device\n"); - goto out; - } - - r = libusb_claim_interface(devh, 0); - if (r < 0) { - fprintf(stderr, "usb_claim_interface error %d %s\n", r, strerror(-r)); - goto out; - } - printf("claimed interface\n"); - - r = print_f0_data(); - if (r < 0) - goto out_release; - - r = do_init(); - if (r < 0) - goto out_deinit; - - /* async from here onwards */ - - sigact.sa_handler = sighandler; - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = 0; - sigaction(SIGINT, &sigact, NULL); - sigaction(SIGTERM, &sigact, NULL); - sigaction(SIGQUIT, &sigact, NULL); - - r = pthread_create(&poll_thread, NULL, poll_thread_main, NULL); - if (r) - goto out_deinit; - - r = alloc_transfers(); - if (r < 0) { - request_exit(1); - pthread_join(poll_thread, NULL); - goto out_deinit; - } - - r = init_capture(); - if (r < 0) { - request_exit(1); - pthread_join(poll_thread, NULL); - goto out_deinit; - } - - while (!do_exit) - sem_wait(exit_sem); - - printf("shutting down...\n"); - pthread_join(poll_thread, NULL); - - r = libusb_cancel_transfer(irq_transfer); - if (r < 0) { - request_exit(1); - goto out_deinit; - } - - r = libusb_cancel_transfer(img_transfer); - if (r < 0) { - request_exit(1); - goto out_deinit; - } - - while (img_transfer || irq_transfer) - if (libusb_handle_events(NULL) < 0) - break; - - if (do_exit == 1) - r = 0; - else - r = 1; - -out_deinit: - libusb_free_transfer(img_transfer); - libusb_free_transfer(irq_transfer); - set_mode(0); - set_hwstat(0x80); -out_release: - libusb_release_interface(devh, 0); -out: - libusb_close(devh); - libusb_exit(NULL); - return r >= 0 ? r : -r; -} diff --git a/examples/ezusb.c b/examples/ezusb.c index 4fe9e65..6abd47d 100644 --- a/examples/ezusb.c +++ b/examples/ezusb.c @@ -20,6 +20,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ + +#include <config.h> + #include <stdio.h> #include <errno.h> #include <stdlib.h> @@ -29,9 +32,6 @@ #include "libusb.h" #include "ezusb.h" -extern void logerror(const char *format, ...) - __attribute__ ((format(printf, 1, 2))); - /* * This file contains functions for uploading firmware into Cypress * EZ-USB microcontrollers. These chips use control endpoint 0 and vendor diff --git a/examples/ezusb.h b/examples/ezusb.h index 12d3d9d..62062c4 100644 --- a/examples/ezusb.h +++ b/examples/ezusb.h @@ -21,12 +21,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#if defined(_MSC_VER) -#define __attribute__(x) -#if defined(_PREFAST_) -#pragma warning(disable:28193) -#endif -#endif +#include <config.h> #include <stdbool.h> @@ -105,6 +100,8 @@ extern int ezusb_load_eeprom(libusb_device_handle *device, /* Verbosity level (default 1). Can be increased or decreased with options v/q */ extern int verbose; +extern void logerror(const char *format, ...) PRINTF_FORMAT(1, 2); + #ifdef __cplusplus } #endif diff --git a/examples/fxload.c b/examples/fxload.c index 114b19b..541c3d3 100644 --- a/examples/fxload.c +++ b/examples/fxload.c @@ -21,6 +21,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ +#include <config.h> + #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -48,9 +50,6 @@ static bool dosyslog = false; #endif void logerror(const char *format, ...) - __attribute__ ((format (__printf__, 1, 2))); - -void logerror(const char *format, ...) { va_list ap; va_start(ap, format); diff --git a/examples/hotplugtest.c b/examples/hotplugtest.c index 4d0db5e..94f7e56 100644 --- a/examples/hotplugtest.c +++ b/examples/hotplugtest.c @@ -95,7 +95,7 @@ int main(int argc, char *argv[]) } if (!libusb_has_capability (LIBUSB_CAP_HAS_HOTPLUG)) { - printf ("Hotplug capabilites are not supported on this platform\n"); + printf ("Hotplug capabilities are not supported on this platform\n"); libusb_exit (NULL); return EXIT_FAILURE; } diff --git a/examples/sam3u_benchmark.c b/examples/sam3u_benchmark.c index b362106..33e8913 100644 --- a/examples/sam3u_benchmark.c +++ b/examples/sam3u_benchmark.c @@ -22,24 +22,54 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> +#include <config.h> + #include <errno.h> #include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#include <time.h> #include "libusb.h" - #define EP_DATA_IN 0x82 #define EP_ISO_IN 0x86 -static int do_exit = 0; +static volatile sig_atomic_t do_exit = 0; static struct libusb_device_handle *devh = NULL; static unsigned long num_bytes = 0, num_xfer = 0; static struct timeval tv_start; +static void get_timestamp(struct timeval *tv) +{ +#if defined(PLATFORM_WINDOWS) + static LARGE_INTEGER frequency; + LARGE_INTEGER counter; + + if (!frequency.QuadPart) + QueryPerformanceFrequency(&frequency); + + QueryPerformanceCounter(&counter); + counter.QuadPart *= 1000000; + counter.QuadPart /= frequency.QuadPart; + + tv->tv_sec = (long)(counter.QuadPart / 1000000ULL); + tv->tv_usec = (long)(counter.QuadPart % 1000000ULL); +#elif defined(HAVE_CLOCK_GETTIME) + struct timespec ts; + + (void)clock_gettime(CLOCK_MONOTONIC, &ts); + tv->tv_sec = ts.tv_sec; + tv->tv_usec = (int)(ts.tv_nsec / 1000L); +#else + gettimeofday(tv, NULL); +#endif +} + static void LIBUSB_CALL cb_xfr(struct libusb_transfer *xfr) { int i; @@ -103,7 +133,7 @@ static int benchmark_in(uint8_t ep) libusb_fill_bulk_transfer(xfr, devh, ep, buf, sizeof(buf), cb_xfr, NULL, 0); - gettimeofday(&tv_start, NULL); + get_timestamp(&tv_start); /* NOTE: To reach maximum possible performance the program must * submit *multiple* transfers here, not just one. @@ -127,34 +157,37 @@ static void measure(void) struct timeval tv_stop; unsigned long diff_msec; - gettimeofday(&tv_stop, NULL); + get_timestamp(&tv_stop); diff_msec = (tv_stop.tv_sec - tv_start.tv_sec) * 1000L; diff_msec += (tv_stop.tv_usec - tv_start.tv_usec) / 1000L; - printf("%lu transfers (total %lu bytes) in %lu miliseconds => %lu bytes/sec\n", + printf("%lu transfers (total %lu bytes) in %lu milliseconds => %lu bytes/sec\n", num_xfer, num_bytes, diff_msec, (num_bytes * 1000L) / diff_msec); } static void sig_hdlr(int signum) { - switch (signum) { - case SIGINT: - measure(); - do_exit = 1; - break; - } + (void)signum; + + measure(); + do_exit = 1; } int main(void) { int rc; + +#if defined(PLATFORM_POSIX) struct sigaction sigact; sigact.sa_handler = sig_hdlr; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; - sigaction(SIGINT, &sigact, NULL); + (void)sigaction(SIGINT, &sigact, NULL); +#else + (void)signal(SIGINT, sig_hdlr); +#endif rc = libusb_init(NULL); if (rc < 0) { @@ -184,7 +217,7 @@ int main(void) /* Measurement has already been done by the signal handler. */ - libusb_release_interface(devh, 0); + libusb_release_interface(devh, 2); out: if (devh) libusb_close(devh); diff --git a/examples/testlibusb.c b/examples/testlibusb.c index 8031e75..ba00f90 100755..100644 --- a/examples/testlibusb.c +++ b/examples/testlibusb.c @@ -160,26 +160,37 @@ static void print_configuration(struct libusb_config_descriptor *config) print_interface(&config->interface[i]); } -static void print_device(libusb_device *dev) +static void print_device(libusb_device *dev, libusb_device_handle *handle) { struct libusb_device_descriptor desc; - libusb_device_handle *handle = NULL; unsigned char string[256]; + const char *speed; int ret; uint8_t i; + switch (libusb_get_device_speed(dev)) { + case LIBUSB_SPEED_LOW: speed = "1.5M"; break; + case LIBUSB_SPEED_FULL: speed = "12M"; break; + case LIBUSB_SPEED_HIGH: speed = "480M"; break; + case LIBUSB_SPEED_SUPER: speed = "5G"; break; + case LIBUSB_SPEED_SUPER_PLUS: speed = "10G"; break; + default: speed = "Unknown"; + } + ret = libusb_get_device_descriptor(dev, &desc); if (ret < 0) { fprintf(stderr, "failed to get device descriptor"); return; } - printf("Dev (bus %u, device %u): %04X - %04X\n", + printf("Dev (bus %u, device %u): %04X - %04X speed: %s\n", libusb_get_bus_number(dev), libusb_get_device_address(dev), - desc.idVendor, desc.idProduct); + desc.idVendor, desc.idProduct, speed); + + if (!handle) + libusb_open(dev, &handle); - ret = libusb_open(dev, &handle); - if (LIBUSB_SUCCESS == ret) { + if (handle) { if (desc.iManufacturer) { ret = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, string, sizeof(string)); if (ret > 0) @@ -222,28 +233,79 @@ static void print_device(libusb_device *dev) libusb_close(handle); } +#ifdef __linux__ +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +static int test_wrapped_device(const char *device_name) +{ + libusb_device_handle *handle; + int r, fd; + + fd = open(device_name, O_RDWR); + if (fd < 0) { + printf("Error could not open %s: %s\n", device_name, strerror(errno)); + return 1; + } + r = libusb_wrap_sys_device(NULL, fd, &handle); + if (r) { + printf("Error wrapping device: %s: %s\n", device_name, libusb_strerror(r)); + close(fd); + return 1; + } + print_device(libusb_get_device(handle), handle); + close(fd); + return 0; +} +#else +static int test_wrapped_device(const char *device_name) +{ + (void)device_name; + printf("Testing wrapped devices is not supported on your platform\n"); + return 1; +} +#endif + int main(int argc, char *argv[]) { + const char *device_name = NULL; libusb_device **devs; ssize_t cnt; int r, i; - if (argc > 1 && !strcmp(argv[1], "-v")) - verbose = 1; + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-v")) { + verbose = 1; + } else if (!strcmp(argv[i], "-d") && (i + 1) < argc) { + i++; + device_name = argv[i]; + } else { + printf("Usage %s [-v] [-d </dev/bus/usb/...>]\n", argv[0]); + printf("Note use -d to test libusb_wrap_sys_device()\n"); + return 1; + } + } r = libusb_init(NULL); if (r < 0) return r; - cnt = libusb_get_device_list(NULL, &devs); - if (cnt < 0) - return (int)cnt; + if (device_name) { + r = test_wrapped_device(device_name); + } else { + cnt = libusb_get_device_list(NULL, &devs); + if (cnt < 0) { + libusb_exit(NULL); + return 1; + } - for (i = 0; devs[i]; i++) - print_device(devs[i]); + for (i = 0; devs[i]; i++) + print_device(devs[i], NULL); - libusb_free_device_list(devs, 1); + libusb_free_device_list(devs, 1); + } libusb_exit(NULL); - return 0; + return r; } diff --git a/libusb/Makefile.am b/libusb/Makefile.am index 6b93343..c78006e 100644 --- a/libusb/Makefile.am +++ b/libusb/Makefile.am @@ -5,22 +5,15 @@ AM_CXXFLAGS += -fvisibility=hidden $(THREAD_CFLAGS) lib_LTLIBRARIES = libusb-1.0.la -POSIX_POLL_SRC = os/poll_posix.h os/poll_posix.c -WINDOWS_POLL_SRC = os/poll_windows.h os/poll_windows.c +POSIX_PLATFORM_SRC = os/events_posix.h os/events_posix.c \ + os/threads_posix.h os/threads_posix.c +WINDOWS_PLATFORM_SRC = os/events_windows.h os/events_windows.c \ + os/threads_windows.h os/threads_windows.c -if POLL_POSIX -POLL_SRC = $(POSIX_POLL_SRC) +if PLATFORM_POSIX +PLATFORM_SRC = $(POSIX_PLATFORM_SRC) else -POLL_SRC = $(WINDOWS_POLL_SRC) -endif - -POSIX_THREADS_SRC = os/threads_posix.h os/threads_posix.c -WINDOWS_THREADS_SRC = os/threads_windows.h os/threads_windows.c - -if THREADS_POSIX -THREADS_SRC = $(POSIX_THREADS_SRC) -else -THREADS_SRC = $(WINDOWS_THREADS_SRC) +PLATFORM_SRC = $(WINDOWS_PLATFORM_SRC) endif OS_DARWIN_SRC = os/darwin_usb.h os/darwin_usb.c @@ -90,6 +83,6 @@ endif libusb_1_0_la_LDFLAGS = $(LT_LDFLAGS) libusb_1_0_la_SOURCES = libusbi.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) + $(PLATFORM_SRC) $(OS_SRC) pkginclude_HEADERS = libusb.h diff --git a/libusb/core.c b/libusb/core.c index 6aa1b0b..07d459c 100644 --- a/libusb/core.c +++ b/libusb/core.c @@ -53,7 +53,7 @@ struct list_head active_contexts_list; * \section intro Introduction * * libusb is an open source library that allows you to communicate with USB - * devices from userspace. For more info, see the + * devices from user space. For more info, see the * <a href="http://libusb.info">libusb homepage</a>. * * This documentation is aimed at application developers wishing to @@ -157,6 +157,36 @@ struct list_head active_contexts_list; /** * \page libusb_caveats Caveats * + * \section threadsafety Thread safety + * + * libusb is designed to be completely thread-safe, but as with any API it + * cannot prevent a user from sabotaging themselves, either intentionally or + * otherwise. + * + * Observe the following general guidelines: + * + * - Calls to functions that release a resource (e.g. libusb_close(), + * libusb_free_config_descriptor()) should not be called concurrently on + * the same resource. This is no different than concurrently calling free() + * on the same allocated pointer. + * - Each individual \ref libusb_transfer should be prepared by a single + * thread. In other words, no two threads should ever be concurrently + * filling out the fields of a \ref libusb_transfer. You can liken this to + * calling sprintf() with the same destination buffer from multiple threads. + * The results will likely not be what you want unless the input parameters + * are all the same, but its best to avoid this situation entirely. + * - Both the \ref libusb_transfer structure and its associated data buffer + * should not be accessed between the time the transfer is submitted and the + * time the completion callback is invoked. You can think of "ownership" of + * these things as being transferred to libusb while the transfer is active. + * - The various "setter" functions (e.g. libusb_set_log_cb(), + * libusb_set_pollfd_notifiers()) should not be called concurrently on the + * resource. Though doing so will not lead to any undefined behavior, it + * will likely produce results that the application does not expect. + * + * Rules for multiple threads and asynchronous I/O are detailed + * \ref libusb_mtasync "here". + * * \section fork Fork considerations * * libusb is <em>not</em> designed to work across fork() calls. Depending on @@ -183,12 +213,12 @@ struct list_head active_contexts_list; * you when this has happened, so if someone else resets your device it will * not be clear to your own program why the device state has changed. * - * Ultimately, this is a limitation of writing drivers in userspace. + * Ultimately, this is a limitation of writing drivers in user space. * Separation from the USB stack in the underlying kernel makes it difficult * for the operating system to deliver such notifications to your program. * The Linux kernel USB stack allows such reset notifications to be delivered * to in-kernel USB drivers, but it is not clear how such notifications could - * be delivered to second-class drivers that live in userspace. + * be delivered to second-class drivers that live in user space. * * \section blockonly Blocking-only functionality * @@ -670,16 +700,11 @@ struct libusb_device *usbi_alloc_device(struct libusb_context *ctx, { size_t priv_size = usbi_backend.device_priv_size; struct libusb_device *dev = calloc(1, PTR_ALIGN(sizeof(*dev)) + priv_size); - int r; if (!dev) return NULL; - r = usbi_mutex_init(&dev->lock); - if (r) { - free(dev); - return NULL; - } + usbi_mutex_init(&dev->lock); dev->ctx = ctx; dev->refcnt = 1; @@ -766,11 +791,12 @@ struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx, struct libusb_device *ret = NULL; usbi_mutex_lock(&ctx->usb_devs_lock); - list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) + for_each_device(ctx, dev) { if (dev->session_data == session_id) { ret = libusb_ref_device(dev); break; } + } usbi_mutex_unlock(&ctx->usb_devs_lock); return ret; @@ -819,7 +845,7 @@ ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx, usbi_backend.hotplug_poll(); usbi_mutex_lock(&ctx->usb_devs_lock); - list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) { + for_each_device(ctx, dev) { discdevs = discovered_devs_append(discdevs, dev); if (!discdevs) { @@ -1187,49 +1213,14 @@ void API_EXPORTED libusb_unref_device(libusb_device *dev) } } -/* - * Signal the event pipe so that the event handling thread will be - * interrupted to process an internal event. - */ -int usbi_signal_event(struct libusb_context *ctx) -{ - unsigned char dummy = 1; - ssize_t r; - - /* write some data on event pipe to interrupt event handlers */ - r = usbi_write(ctx->event_pipe[1], &dummy, sizeof(dummy)); - if (r != sizeof(dummy)) { - usbi_warn(ctx, "internal signalling write failed"); - return LIBUSB_ERROR_IO; - } - - return 0; -} - -/* - * Clear the event pipe so that the event handling will no longer be - * interrupted. - */ -int usbi_clear_event(struct libusb_context *ctx) -{ - unsigned char dummy; - ssize_t r; - - /* read some data on event pipe to clear it */ - r = usbi_read(ctx->event_pipe[0], &dummy, sizeof(dummy)); - if (r != sizeof(dummy)) { - usbi_warn(ctx, "internal signalling read failed"); - return LIBUSB_ERROR_IO; - } - - return 0; -} - /** \ingroup libusb_dev * Wrap a platform-specific system device handle and obtain a libusb device * handle for the underlying device. The handle allows you to use libusb to * perform I/O on the device in question. * + * Must call libusb_set_option(NULL, LIBUSB_OPTION_WEAK_AUTHORITY) + * before libusb_init if don't have authority to access the usb device directly. + * * On Linux, the system device handle must be a valid file descriptor opened * on the device node. * @@ -1260,7 +1251,7 @@ int API_EXPORTED libusb_wrap_sys_device(libusb_context *ctx, intptr_t sys_dev, size_t priv_size = usbi_backend.device_handle_priv_size; int r; - usbi_dbg("wrap_sys_device %p", (void *)sys_dev); + usbi_dbg("wrap_sys_device 0x%" PRIxPTR, (uintptr_t)sys_dev); ctx = usbi_get_context(ctx); @@ -1271,15 +1262,11 @@ int API_EXPORTED libusb_wrap_sys_device(libusb_context *ctx, intptr_t sys_dev, if (!_dev_handle) return LIBUSB_ERROR_NO_MEM; - r = usbi_mutex_init(&_dev_handle->lock); - if (r) { - free(_dev_handle); - return LIBUSB_ERROR_OTHER; - } + usbi_mutex_init(&_dev_handle->lock); r = usbi_backend.wrap_sys_device(ctx, _dev_handle, sys_dev); if (r < 0) { - usbi_dbg("wrap_sys_device %p returns %d", (void *)sys_dev, r); + usbi_dbg("wrap_sys_device 0x%" PRIxPTR " returns %d", (uintptr_t)sys_dev, r); usbi_mutex_destroy(&_dev_handle->lock); free(_dev_handle); return r; @@ -1329,11 +1316,7 @@ int API_EXPORTED libusb_open(libusb_device *dev, if (!_dev_handle) return LIBUSB_ERROR_NO_MEM; - r = usbi_mutex_init(&_dev_handle->lock); - if (r) { - free(_dev_handle); - return LIBUSB_ERROR_OTHER; - } + usbi_mutex_init(&_dev_handle->lock); _dev_handle->dev = libusb_ref_device(dev); @@ -1416,7 +1399,7 @@ static void do_close(struct libusb_context *ctx, usbi_mutex_lock(&ctx->flying_transfers_lock); /* safe iteration because transfers may be being deleted */ - list_for_each_entry_safe(itransfer, tmp, &ctx->flying_transfers, list, struct usbi_transfer) { + for_each_transfer_safe(ctx, itransfer, tmp) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); @@ -1474,8 +1457,8 @@ static void do_close(struct libusb_context *ctx, void API_EXPORTED libusb_close(libusb_device_handle *dev_handle) { struct libusb_context *ctx; + unsigned int event_flags; int handling_events; - int pending_events; if (!dev_handle) return; @@ -1496,10 +1479,11 @@ void API_EXPORTED libusb_close(libusb_device_handle *dev_handle) /* 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); + event_flags = ctx->event_flags; + if (!ctx->device_close++) + ctx->event_flags |= USBI_EVENT_DEVICE_CLOSE; + if (!event_flags) + usbi_signal_event(&ctx->event); usbi_mutex_unlock(&ctx->event_data_lock); /* take event handling lock */ @@ -1513,10 +1497,10 @@ void API_EXPORTED libusb_close(libusb_device_handle *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); + if (!--ctx->device_close) + ctx->event_flags &= ~USBI_EVENT_DEVICE_CLOSE; + if (!ctx->event_flags) + usbi_clear_event(&ctx->event); usbi_mutex_unlock(&ctx->event_data_lock); /* Release event handling lock and wake up event waiters */ @@ -1603,6 +1587,11 @@ int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev_handle, * causing most USB-related device state to be reset (altsetting reset to zero, * endpoint halts cleared, toggles reset). * + * Not all backends support setting the configuration from user space, which + * will be indicated by the return code LIBUSB_ERROR_NOT_SUPPORTED. As this + * suggests that the platform is handling the device configuration itself, + * this error should generally be safe to ignore. + * * You cannot change/reset configuration if your application has claimed * interfaces. It is advised to set the desired configuration before claiming * interfaces. @@ -1632,6 +1621,8 @@ int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev_handle, * \returns 0 on success * \returns LIBUSB_ERROR_NOT_FOUND if the requested configuration does not exist * \returns LIBUSB_ERROR_BUSY if interfaces are currently claimed + * \returns LIBUSB_ERROR_NOT_SUPPORTED if setting or changing the configuration + * is not supported by the backend * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected * \returns another LIBUSB_ERROR code on other failure * \see libusb_set_auto_detach_kernel_driver() @@ -1926,7 +1917,7 @@ int API_EXPORTED libusb_free_streams(libusb_device_handle *dev_handle, * 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 + * Will return NULL on failure. Many systems do not support such zero-copy * 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 @@ -2215,6 +2206,7 @@ int API_EXPORTED libusb_set_option(libusb_context *ctx, /* Handle all backend-specific options here */ case LIBUSB_OPTION_USE_USBDK: + case LIBUSB_OPTION_WEAK_AUTHORITY: if (usbi_backend.set_option) r = usbi_backend.set_option(ctx, option, ap); else @@ -2272,9 +2264,8 @@ int API_EXPORTED libusb_init(libusb_context **context) usbi_mutex_static_lock(&default_context_lock); - if (!timestamp_origin.tv_sec) { - usbi_clock_gettime(USBI_CLOCK_REALTIME, ×tamp_origin); - } + if (!timestamp_origin.tv_sec) + usbi_get_monotonic_time(×tamp_origin); if (!context && usbi_default_context) { usbi_dbg("reusing default context"); @@ -2352,7 +2343,7 @@ err_free_ctx: usbi_mutex_static_unlock(&active_contexts_lock); usbi_mutex_lock(&ctx->usb_devs_lock); - list_for_each_entry_safe(dev, next, &ctx->usb_devs, list, struct libusb_device) { + for_each_device_safe(ctx, dev, next) { list_del(&dev->list); libusb_unref_device(dev); } @@ -2432,7 +2423,7 @@ void API_EXPORTED libusb_exit(libusb_context *ctx) libusb_handle_events_timeout(ctx, &tv); usbi_mutex_lock(&ctx->usb_devs_lock); - list_for_each_entry_safe(dev, next, &ctx->usb_devs, list, struct libusb_device) { + for_each_device_safe(ctx, dev, next) { list_del(&dev->list); libusb_unref_device(dev); } @@ -2490,94 +2481,90 @@ int API_EXPORTED libusb_has_capability(uint32_t capability) #ifdef LIBUSB_PRINTF_WIN32 /* * Prior to VS2015, Microsoft did not provide the snprintf() function and - * provided a vsnprintf() that did not guarantee NULL-terminated output. + * provided a vsnprintf() that did not guarantee NUL-terminated output. * Microsoft did provide a _snprintf() function, but again it did not * guarantee NULL-terminated output. * - * The below implementations guarantee NULL-terminated output and are + * The below implementations guarantee NUL-terminated output and are * C99 compliant. */ int usbi_snprintf(char *str, size_t size, const char *format, ...) { - va_list ap; + va_list args; int ret; - va_start(ap, format); - ret = usbi_vsnprintf(str, size, format, ap); - va_end(ap); + va_start(args, format); + ret = usbi_vsnprintf(str, size, format, args); + va_end(args); return ret; } -int usbi_vsnprintf(char *str, size_t size, const char *format, va_list ap) +int usbi_vsnprintf(char *str, size_t size, const char *format, va_list args) { int ret; - ret = _vsnprintf(str, size, format, ap); + ret = _vsnprintf(str, size, format, args); if (ret < 0 || ret == (int)size) { - /* Output is truncated, ensure buffer is NULL-terminated and + /* Output is truncated, ensure buffer is NUL-terminated and * determine how many characters would have been written. */ str[size - 1] = '\0'; if (ret < 0) - ret = _vsnprintf(NULL, 0, format, ap); + ret = _vsnprintf(NULL, 0, format, args); } return ret; } #endif /* LIBUSB_PRINTF_WIN32 */ -static void usbi_log_str(enum libusb_log_level level, const char *str) +static void log_str(enum libusb_log_level level, const char *str) { #if defined(USE_SYSTEM_LOGGING_FACILITY) -#if defined(_WIN32) -#if !defined(UNICODE) - OutputDebugStringA(str); -#else - WCHAR wbuf[USBI_MAX_LOG_LEN]; - if (MultiByteToWideChar(CP_UTF8, 0, str, -1, wbuf, sizeof(wbuf)) != 0) - OutputDebugStringW(wbuf); -#endif -#elif defined(__ANDROID__) - int priority = ANDROID_LOG_UNKNOWN; +#if defined(__ANDROID__) + int priority; switch (level) { - case LIBUSB_LOG_LEVEL_NONE: return; + case LIBUSB_LOG_LEVEL_NONE: return; /* Impossible, but keeps compiler happy */ case LIBUSB_LOG_LEVEL_ERROR: priority = ANDROID_LOG_ERROR; break; case LIBUSB_LOG_LEVEL_WARNING: priority = ANDROID_LOG_WARN; break; case LIBUSB_LOG_LEVEL_INFO: priority = ANDROID_LOG_INFO; break; case LIBUSB_LOG_LEVEL_DEBUG: priority = ANDROID_LOG_DEBUG; break; + default: priority = ANDROID_LOG_UNKNOWN; } __android_log_write(priority, "libusb", str); +#elif defined(_WIN32) + UNUSED(level); + OutputDebugStringA(str); #elif defined(HAVE_SYSLOG) - int syslog_level = LOG_INFO; + int syslog_level; switch (level) { - case LIBUSB_LOG_LEVEL_NONE: return; + case LIBUSB_LOG_LEVEL_NONE: return; /* Impossible, but keeps compiler happy */ case LIBUSB_LOG_LEVEL_ERROR: syslog_level = LOG_ERR; break; case LIBUSB_LOG_LEVEL_WARNING: syslog_level = LOG_WARNING; break; case LIBUSB_LOG_LEVEL_INFO: syslog_level = LOG_INFO; break; case LIBUSB_LOG_LEVEL_DEBUG: syslog_level = LOG_DEBUG; break; + default: syslog_level = LOG_INFO; } syslog(syslog_level, "%s", str); #else /* All of gcc, Clang, Xcode seem to use #warning */ #warning System logging is not supported on this platform. Logging to stderr will be used instead. + UNUSED(level); fputs(str, stderr); #endif #else /* Global log handler */ - if (log_handler != NULL) + if (log_handler) log_handler(NULL, level, str); else fputs(str, stderr); #endif /* USE_SYSTEM_LOGGING_FACILITY */ - UNUSED(level); } -void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, +static void log_v(struct libusb_context *ctx, enum libusb_log_level level, const char *function, const char *format, va_list args) { const char *prefix; char buf[USBI_MAX_LOG_LEN]; - struct timespec now; int global_debug, header_len, text_len; static int has_debug_header_been_displayed = 0; @@ -2585,7 +2572,7 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, global_debug = 1; UNUSED(ctx); #else - enum libusb_log_level ctx_level = LIBUSB_LOG_LEVEL_NONE; + enum libusb_log_level ctx_level; ctx = usbi_get_context(ctx); if (ctx) @@ -2593,33 +2580,14 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, else ctx_level = get_env_debug_level(); - if (ctx_level == LIBUSB_LOG_LEVEL_NONE) - return; - if (level == LIBUSB_LOG_LEVEL_WARNING && ctx_level < LIBUSB_LOG_LEVEL_WARNING) - return; - if (level == LIBUSB_LOG_LEVEL_INFO && ctx_level < LIBUSB_LOG_LEVEL_INFO) - return; - if (level == LIBUSB_LOG_LEVEL_DEBUG && ctx_level < LIBUSB_LOG_LEVEL_DEBUG) + if (ctx_level < level) return; global_debug = (ctx_level == LIBUSB_LOG_LEVEL_DEBUG); #endif - usbi_clock_gettime(USBI_CLOCK_REALTIME, &now); - if ((global_debug) && (!has_debug_header_been_displayed)) { - has_debug_header_been_displayed = 1; - usbi_log_str(LIBUSB_LOG_LEVEL_DEBUG, "[timestamp] [threadID] facility level [function call] <message>" USBI_LOG_LINE_END); - usbi_log_str(LIBUSB_LOG_LEVEL_DEBUG, "--------------------------------------------------------------------------------" USBI_LOG_LINE_END); - } - if (now.tv_nsec < timestamp_origin.tv_nsec) { - now.tv_sec--; - now.tv_nsec += 1000000000L; - } - now.tv_sec -= timestamp_origin.tv_sec; - now.tv_nsec -= timestamp_origin.tv_nsec; - switch (level) { - case LIBUSB_LOG_LEVEL_NONE: + case LIBUSB_LOG_LEVEL_NONE: /* Impossible, but keeps compiler happy */ return; case LIBUSB_LOG_LEVEL_ERROR: prefix = "error"; @@ -2639,21 +2607,31 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, } if (global_debug) { + struct timespec timestamp; + + if (!has_debug_header_been_displayed) { + has_debug_header_been_displayed = 1; + log_str(LIBUSB_LOG_LEVEL_DEBUG, "[timestamp] [threadID] facility level [function call] <message>" USBI_LOG_LINE_END); + log_str(LIBUSB_LOG_LEVEL_DEBUG, "--------------------------------------------------------------------------------" USBI_LOG_LINE_END); + } + + usbi_get_monotonic_time(×tamp); + TIMESPEC_SUB(×tamp, ×tamp_origin, ×tamp); + header_len = snprintf(buf, sizeof(buf), "[%2ld.%06ld] [%08x] libusb: %s [%s] ", - (long)now.tv_sec, (long)(now.tv_nsec / 1000L), usbi_get_tid(), prefix, function); + (long)timestamp.tv_sec, (long)(timestamp.tv_nsec / 1000L), usbi_get_tid(), prefix, function); } else { header_len = snprintf(buf, sizeof(buf), "libusb: %s [%s] ", prefix, function); } if (header_len < 0 || header_len >= (int)sizeof(buf)) { - /* Somehow snprintf failed to write to the buffer, + /* Somehow snprintf() failed to write to the buffer, * remove the header so something useful is output. */ header_len = 0; } - /* Make sure buffer is NUL terminated */ - buf[header_len] = '\0'; + text_len = vsnprintf(buf + header_len, sizeof(buf) - (size_t)header_len, format, args); if (text_len < 0 || text_len + header_len >= (int)sizeof(buf)) { @@ -2667,9 +2645,9 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, } strcpy(buf + header_len + text_len, USBI_LOG_LINE_END); - usbi_log_str(level, buf); + log_str(level, buf); - /* Per context log handler */ + /* Per-context log handler */ #ifndef ENABLE_DEBUG_LOGGING if (ctx && ctx->log_handler) ctx->log_handler(ctx, level, buf); @@ -2681,9 +2659,9 @@ void usbi_log(struct libusb_context *ctx, enum libusb_log_level level, { va_list args; - va_start (args, format); - usbi_log_v(ctx, level, function, format, args); - va_end (args); + va_start(args, format); + log_v(ctx, level, function, format, args); + va_end(args); } #endif /* ENABLE_LOGGING */ diff --git a/libusb/descriptor.c b/libusb/descriptor.c index 2097b84..ecd9441 100644 --- a/libusb/descriptor.c +++ b/libusb/descriptor.c @@ -53,14 +53,14 @@ static void parse_descriptor(const void *source, const char *descriptor, void *d *dp++ = *sp++; break; case 'w': /* 16-bit word, convert from little endian to CPU */ - dp += ((uintptr_t)dp & 1); /* Align to word boundary */ + dp += ((uintptr_t)dp & 1); /* Align to 16-bit word boundary */ *((uint16_t *)dp) = READ_LE16(sp); sp += 2; dp += 2; break; case 'd': /* 32-bit word, convert from little endian to CPU */ - dp += ((uintptr_t)dp & 1); /* Align to word boundary */ + dp += 4 - ((uintptr_t)dp & 3); /* Align to 32-bit word boundary */ *((uint32_t *)dp) = READ_LE32(sp); sp += 4; @@ -81,11 +81,11 @@ static void clear_endpoint(struct libusb_endpoint_descriptor *endpoint) } static int parse_endpoint(struct libusb_context *ctx, - struct libusb_endpoint_descriptor *endpoint, unsigned char *buffer, int size) + struct libusb_endpoint_descriptor *endpoint, const uint8_t *buffer, int size) { - struct usbi_descriptor_header *header; - unsigned char *extra; - unsigned char *begin; + const struct usbi_descriptor_header *header; + const uint8_t *begin; + void *extra; int parsed = 0; int len; @@ -95,24 +95,24 @@ static int parse_endpoint(struct libusb_context *ctx, return LIBUSB_ERROR_IO; } - header = (struct usbi_descriptor_header *)buffer; + header = (const struct usbi_descriptor_header *)buffer; if (header->bDescriptorType != LIBUSB_DT_ENDPOINT) { - usbi_err(ctx, "unexpected descriptor %x (expected %x)", + usbi_err(ctx, "unexpected descriptor 0x%x (expected 0x%x)", header->bDescriptorType, LIBUSB_DT_ENDPOINT); return parsed; + } else if (header->bLength < LIBUSB_DT_ENDPOINT_SIZE) { + usbi_err(ctx, "invalid endpoint bLength (%u)", header->bLength); + return LIBUSB_ERROR_IO; } else if (header->bLength > size) { - usbi_warn(ctx, "short endpoint descriptor read %d/%d", + usbi_warn(ctx, "short endpoint descriptor read %d/%u", size, header->bLength); return parsed; } + if (header->bLength >= LIBUSB_DT_ENDPOINT_AUDIO_SIZE) parse_descriptor(buffer, "bbbbwbbb", endpoint); - else if (header->bLength >= LIBUSB_DT_ENDPOINT_SIZE) + else parse_descriptor(buffer, "bbbbwb", endpoint); - else { - usbi_err(ctx, "invalid endpoint bLength (%d)", header->bLength); - return LIBUSB_ERROR_IO; - } buffer += header->bLength; size -= header->bLength; @@ -122,25 +122,25 @@ static int parse_endpoint(struct libusb_context *ctx, /* descriptors */ begin = buffer; while (size >= DESC_HEADER_LENGTH) { - header = (struct usbi_descriptor_header *)buffer; + header = (const struct usbi_descriptor_header *)buffer; if (header->bLength < DESC_HEADER_LENGTH) { - usbi_err(ctx, "invalid extra ep desc len (%d)", + usbi_err(ctx, "invalid extra ep desc len (%u)", header->bLength); return LIBUSB_ERROR_IO; } else if (header->bLength > size) { - usbi_warn(ctx, "short extra ep desc read %d/%d", + usbi_warn(ctx, "short extra ep desc read %d/%u", size, header->bLength); return parsed; } /* If we find another "proper" descriptor then we're done */ - if ((header->bDescriptorType == LIBUSB_DT_ENDPOINT) || - (header->bDescriptorType == LIBUSB_DT_INTERFACE) || - (header->bDescriptorType == LIBUSB_DT_CONFIG) || - (header->bDescriptorType == LIBUSB_DT_DEVICE)) + if (header->bDescriptorType == LIBUSB_DT_ENDPOINT || + header->bDescriptorType == LIBUSB_DT_INTERFACE || + header->bDescriptorType == LIBUSB_DT_CONFIG || + header->bDescriptorType == LIBUSB_DT_DEVICE) break; - usbi_dbg("skipping descriptor %x", header->bDescriptorType); + usbi_dbg("skipping descriptor 0x%x", header->bDescriptorType); buffer += header->bLength; size -= header->bLength; parsed += header->bLength; @@ -166,7 +166,6 @@ static int parse_endpoint(struct libusb_context *ctx, static void clear_interface(struct libusb_interface *usb_interface) { int i; - int j; if (usb_interface->altsetting) { for (i = 0; i < usb_interface->num_altsetting; i++) { @@ -176,6 +175,8 @@ static void clear_interface(struct libusb_interface *usb_interface) free((void *)ifp->extra); if (ifp->endpoint) { + uint8_t j; + for (j = 0; j < ifp->bNumEndpoints; j++) clear_endpoint((struct libusb_endpoint_descriptor *) ifp->endpoint + j); @@ -188,22 +189,21 @@ static void clear_interface(struct libusb_interface *usb_interface) } static int parse_interface(libusb_context *ctx, - struct libusb_interface *usb_interface, unsigned char *buffer, int size) + struct libusb_interface *usb_interface, const uint8_t *buffer, int size) { - int i; int len; int r; int parsed = 0; int interface_number = -1; - struct usbi_descriptor_header *header; + const struct usbi_descriptor_header *header; + const struct usbi_interface_descriptor *if_desc; struct libusb_interface_descriptor *ifp; - unsigned char *extra; - unsigned char *begin; + const uint8_t *begin; while (size >= LIBUSB_DT_INTERFACE_SIZE) { struct libusb_interface_descriptor *altsetting; - altsetting = usbi_reallocf((void *)usb_interface->altsetting, + altsetting = realloc((void *)usb_interface->altsetting, sizeof(*altsetting) * (size_t)(usb_interface->num_altsetting + 1)); if (!altsetting) { r = LIBUSB_ERROR_NO_MEM; @@ -214,23 +214,20 @@ static int parse_interface(libusb_context *ctx, ifp = altsetting + usb_interface->num_altsetting; parse_descriptor(buffer, "bbbbbbbbb", ifp); if (ifp->bDescriptorType != LIBUSB_DT_INTERFACE) { - usbi_err(ctx, "unexpected descriptor %x (expected %x)", + usbi_err(ctx, "unexpected descriptor 0x%x (expected 0x%x)", ifp->bDescriptorType, LIBUSB_DT_INTERFACE); return parsed; - } - if (ifp->bLength < LIBUSB_DT_INTERFACE_SIZE) { - usbi_err(ctx, "invalid interface bLength (%d)", + } else if (ifp->bLength < LIBUSB_DT_INTERFACE_SIZE) { + usbi_err(ctx, "invalid interface bLength (%u)", ifp->bLength); r = LIBUSB_ERROR_IO; goto err; - } - if (ifp->bLength > size) { - usbi_warn(ctx, "short intf descriptor read %d/%d", + } else if (ifp->bLength > size) { + usbi_warn(ctx, "short intf descriptor read %d/%u", size, ifp->bLength); return parsed; - } - if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { - usbi_err(ctx, "too many endpoints (%d)", ifp->bNumEndpoints); + } else if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { + usbi_err(ctx, "too many endpoints (%u)", ifp->bNumEndpoints); r = LIBUSB_ERROR_IO; goto err; } @@ -252,25 +249,25 @@ static int parse_interface(libusb_context *ctx, /* Skip over any interface, class or vendor descriptors */ while (size >= DESC_HEADER_LENGTH) { - header = (struct usbi_descriptor_header *)buffer; + header = (const struct usbi_descriptor_header *)buffer; if (header->bLength < DESC_HEADER_LENGTH) { usbi_err(ctx, - "invalid extra intf desc len (%d)", + "invalid extra intf desc len (%u)", header->bLength); r = LIBUSB_ERROR_IO; goto err; } else if (header->bLength > size) { usbi_warn(ctx, - "short extra intf desc read %d/%d", + "short extra intf desc read %d/%u", size, header->bLength); return parsed; } /* If we find another "proper" descriptor then we're done */ - if ((header->bDescriptorType == LIBUSB_DT_INTERFACE) || - (header->bDescriptorType == LIBUSB_DT_ENDPOINT) || - (header->bDescriptorType == LIBUSB_DT_CONFIG) || - (header->bDescriptorType == LIBUSB_DT_DEVICE)) + if (header->bDescriptorType == LIBUSB_DT_INTERFACE || + header->bDescriptorType == LIBUSB_DT_ENDPOINT || + header->bDescriptorType == LIBUSB_DT_CONFIG || + header->bDescriptorType == LIBUSB_DT_DEVICE) break; buffer += header->bLength; @@ -282,7 +279,8 @@ static int parse_interface(libusb_context *ctx, /* drivers to later parse */ len = (int)(buffer - begin); if (len > 0) { - extra = malloc((size_t)len); + void *extra = malloc((size_t)len); + if (!extra) { r = LIBUSB_ERROR_NO_MEM; goto err; @@ -295,6 +293,7 @@ static int parse_interface(libusb_context *ctx, if (ifp->bNumEndpoints > 0) { struct libusb_endpoint_descriptor *endpoint; + uint8_t i; endpoint = calloc(ifp->bNumEndpoints, sizeof(*endpoint)); if (!endpoint) { @@ -308,7 +307,7 @@ static int parse_interface(libusb_context *ctx, if (r < 0) goto err; if (r == 0) { - ifp->bNumEndpoints = (uint8_t)i; + ifp->bNumEndpoints = i; break; } @@ -319,10 +318,10 @@ static int parse_interface(libusb_context *ctx, } /* We check to see if it's an alternate to this one */ - ifp = (struct libusb_interface_descriptor *)buffer; + if_desc = (const struct usbi_interface_descriptor *)buffer; if (size < LIBUSB_DT_INTERFACE_SIZE || - ifp->bDescriptorType != LIBUSB_DT_INTERFACE || - ifp->bInterfaceNumber != interface_number) + if_desc->bDescriptorType != LIBUSB_DT_INTERFACE || + if_desc->bInterfaceNumber != interface_number) return parsed; } @@ -334,7 +333,8 @@ err: static void clear_configuration(struct libusb_config_descriptor *config) { - int i; + uint8_t i; + if (config->interface) { for (i = 0; i < config->bNumInterfaces; i++) clear_interface((struct libusb_interface *) @@ -345,13 +345,12 @@ static void clear_configuration(struct libusb_config_descriptor *config) } static int parse_configuration(struct libusb_context *ctx, - struct libusb_config_descriptor *config, unsigned char *buffer, int size) + struct libusb_config_descriptor *config, const uint8_t *buffer, int size) { - int i; + uint8_t i; int r; - struct usbi_descriptor_header *header; + const struct usbi_descriptor_header *header; struct libusb_interface *usb_interface; - unsigned char *extra; if (size < LIBUSB_DT_CONFIG_SIZE) { usbi_err(ctx, "short config descriptor read %d/%d", @@ -361,21 +360,18 @@ static int parse_configuration(struct libusb_context *ctx, parse_descriptor(buffer, "bbwbbbbb", config); if (config->bDescriptorType != LIBUSB_DT_CONFIG) { - usbi_err(ctx, "unexpected descriptor %x (expected %x)", + usbi_err(ctx, "unexpected descriptor 0x%x (expected 0x%x)", config->bDescriptorType, LIBUSB_DT_CONFIG); return LIBUSB_ERROR_IO; - } - if (config->bLength < LIBUSB_DT_CONFIG_SIZE) { - usbi_err(ctx, "invalid config bLength (%d)", config->bLength); + } else if (config->bLength < LIBUSB_DT_CONFIG_SIZE) { + usbi_err(ctx, "invalid config bLength (%u)", config->bLength); return LIBUSB_ERROR_IO; - } - if (config->bLength > size) { - usbi_err(ctx, "short config descriptor read %d/%d", + } else if (config->bLength > size) { + usbi_err(ctx, "short config descriptor read %d/%u", size, config->bLength); return LIBUSB_ERROR_IO; - } - if (config->bNumInterfaces > USB_MAXINTERFACES) { - usbi_err(ctx, "too many interfaces (%d)", config->bNumInterfaces); + } else if (config->bNumInterfaces > USB_MAXINTERFACES) { + usbi_err(ctx, "too many interfaces (%u)", config->bNumInterfaces); return LIBUSB_ERROR_IO; } @@ -390,32 +386,32 @@ static int parse_configuration(struct libusb_context *ctx, for (i = 0; i < config->bNumInterfaces; i++) { int len; - unsigned char *begin; + const uint8_t *begin; /* Skip over the rest of the Class Specific or Vendor */ /* Specific descriptors */ begin = buffer; while (size >= DESC_HEADER_LENGTH) { - header = (struct usbi_descriptor_header *)buffer; + header = (const struct usbi_descriptor_header *)buffer; if (header->bLength < DESC_HEADER_LENGTH) { usbi_err(ctx, - "invalid extra config desc len (%d)", + "invalid extra config desc len (%u)", header->bLength); r = LIBUSB_ERROR_IO; goto err; } else if (header->bLength > size) { usbi_warn(ctx, - "short extra config desc read %d/%d", + "short extra config desc read %d/%u", size, header->bLength); - config->bNumInterfaces = (uint8_t)i; + config->bNumInterfaces = i; return size; } /* If we find another "proper" descriptor then we're done */ - if ((header->bDescriptorType == LIBUSB_DT_ENDPOINT) || - (header->bDescriptorType == LIBUSB_DT_INTERFACE) || - (header->bDescriptorType == LIBUSB_DT_CONFIG) || - (header->bDescriptorType == LIBUSB_DT_DEVICE)) + if (header->bDescriptorType == LIBUSB_DT_ENDPOINT || + header->bDescriptorType == LIBUSB_DT_INTERFACE || + header->bDescriptorType == LIBUSB_DT_CONFIG || + header->bDescriptorType == LIBUSB_DT_DEVICE) break; usbi_dbg("skipping descriptor 0x%x", header->bDescriptorType); @@ -427,25 +423,24 @@ static int parse_configuration(struct libusb_context *ctx, /* drivers to later parse */ len = (int)(buffer - begin); if (len > 0) { - /* FIXME: We should realloc and append here */ - if (!config->extra_length) { - extra = malloc((size_t)len); - if (!extra) { - r = LIBUSB_ERROR_NO_MEM; - goto err; - } + uint8_t *extra = realloc((void *)config->extra, + (size_t)(config->extra_length + len)); - memcpy(extra, begin, len); - config->extra = extra; - config->extra_length = len; + if (!extra) { + r = LIBUSB_ERROR_NO_MEM; + goto err; } + + memcpy(extra + config->extra_length, begin, len); + config->extra = extra; + config->extra_length += len; } r = parse_interface(ctx, usb_interface + i, buffer, size); if (r < 0) goto err; if (r == 0) { - config->bNumInterfaces = (uint8_t)i; + config->bNumInterfaces = i; break; } @@ -461,7 +456,7 @@ err: } static int raw_desc_to_config(struct libusb_context *ctx, - unsigned char *buf, int size, struct libusb_config_descriptor **config) + const uint8_t *buf, int size, struct libusb_config_descriptor **config) { struct libusb_config_descriptor *_config = calloc(1, sizeof(*_config)); int r; @@ -482,6 +477,45 @@ static int raw_desc_to_config(struct libusb_context *ctx, return LIBUSB_SUCCESS; } +static int get_active_config_descriptor(struct libusb_device *dev, + uint8_t *buffer, size_t size) +{ + int r = usbi_backend.get_active_config_descriptor(dev, buffer, size); + + if (r < 0) + return r; + + if (r < LIBUSB_DT_CONFIG_SIZE) { + usbi_err(DEVICE_CTX(dev), "short config descriptor read %d/%d", + r, LIBUSB_DT_CONFIG_SIZE); + return LIBUSB_ERROR_IO; + } else if (r != (int)size) { + usbi_warn(DEVICE_CTX(dev), "short config descriptor read %d/%d", + r, (int)size); + } + + return r; +} + +static int get_config_descriptor(struct libusb_device *dev, uint8_t config_idx, + uint8_t *buffer, size_t size) +{ + int r = usbi_backend.get_config_descriptor(dev, config_idx, buffer, size); + + if (r < 0) + return r; + if (r < LIBUSB_DT_CONFIG_SIZE) { + usbi_err(DEVICE_CTX(dev), "short config descriptor read %d/%d", + r, LIBUSB_DT_CONFIG_SIZE); + return LIBUSB_ERROR_IO; + } else if (r != (int)size) { + usbi_warn(DEVICE_CTX(dev), "short config descriptor read %d/%d", + r, (int)size); + } + + return r; +} + /** \ingroup libusb_desc * Get the USB device descriptor for a given device. * @@ -521,28 +555,23 @@ int API_EXPORTED libusb_get_device_descriptor(libusb_device *dev, int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev, struct libusb_config_descriptor **config) { - struct libusb_config_descriptor _config; - unsigned char tmp[LIBUSB_DT_CONFIG_SIZE]; - unsigned char *buf = NULL; + union usbi_config_desc_buf _config; + uint16_t config_len; + uint8_t *buf; int r; - r = usbi_backend.get_active_config_descriptor(dev, tmp, sizeof(tmp)); + r = get_active_config_descriptor(dev, _config.buf, sizeof(_config.buf)); if (r < 0) return r; - if (r < LIBUSB_DT_CONFIG_SIZE) { - usbi_err(dev->ctx, "short config descriptor read %d/%d", - r, LIBUSB_DT_CONFIG_SIZE); - return LIBUSB_ERROR_IO; - } - parse_descriptor(tmp, "bbw", &_config); - buf = malloc(_config.wTotalLength); + config_len = libusb_le16_to_cpu(_config.desc.wTotalLength); + buf = malloc(config_len); if (!buf) return LIBUSB_ERROR_NO_MEM; - r = usbi_backend.get_active_config_descriptor(dev, buf, _config.wTotalLength); + r = get_active_config_descriptor(dev, buf, config_len); if (r >= 0) - r = raw_desc_to_config(dev->ctx, buf, r, config); + r = raw_desc_to_config(DEVICE_CTX(dev), buf, r, config); free(buf); return r; @@ -567,32 +596,27 @@ int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev, int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev, uint8_t config_index, struct libusb_config_descriptor **config) { - struct libusb_config_descriptor _config; - unsigned char tmp[LIBUSB_DT_CONFIG_SIZE]; - unsigned char *buf = NULL; + union usbi_config_desc_buf _config; + uint16_t config_len; + uint8_t *buf; int r; - usbi_dbg("index %d", config_index); + usbi_dbg("index %u", config_index); if (config_index >= dev->device_descriptor.bNumConfigurations) return LIBUSB_ERROR_NOT_FOUND; - r = usbi_backend.get_config_descriptor(dev, config_index, tmp, sizeof(tmp)); + r = get_config_descriptor(dev, config_index, _config.buf, sizeof(_config.buf)); if (r < 0) return r; - if (r < LIBUSB_DT_CONFIG_SIZE) { - usbi_err(dev->ctx, "short config descriptor read %d/%d", - r, LIBUSB_DT_CONFIG_SIZE); - return LIBUSB_ERROR_IO; - } - parse_descriptor(tmp, "bbw", &_config); - buf = malloc(_config.wTotalLength); + config_len = libusb_le16_to_cpu(_config.desc.wTotalLength); + buf = malloc(config_len); if (!buf) return LIBUSB_ERROR_NO_MEM; - r = usbi_backend.get_config_descriptor(dev, config_index, buf, _config.wTotalLength); + r = get_config_descriptor(dev, config_index, buf, config_len); if (r >= 0) - r = raw_desc_to_config(dev->ctx, buf, r, config); + r = raw_desc_to_config(DEVICE_CTX(dev), buf, r, config); free(buf); return r; @@ -628,18 +652,19 @@ int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev, bConfigurationValue, &buf); if (r < 0) return r; - return raw_desc_to_config(dev->ctx, buf, r, config); + + return raw_desc_to_config(DEVICE_CTX(dev), buf, r, config); } usbi_dbg("value %u", bConfigurationValue); for (idx = 0; idx < dev->device_descriptor.bNumConfigurations; idx++) { - unsigned char tmp[6]; + union usbi_config_desc_buf _config; - r = usbi_backend.get_config_descriptor(dev, idx, tmp, sizeof(tmp)); + r = get_config_descriptor(dev, idx, _config.buf, sizeof(_config.buf)); if (r < 0) return r; - if (tmp[5] == bConfigurationValue) + if (_config.desc.bConfigurationValue == bConfigurationValue) return libusb_get_config_descriptor(dev, idx, config); } @@ -683,30 +708,34 @@ int API_EXPORTED libusb_get_ss_endpoint_companion_descriptor( struct libusb_ss_endpoint_companion_descriptor **ep_comp) { struct usbi_descriptor_header *header; + const uint8_t *buffer = endpoint->extra; int size = endpoint->extra_length; - const unsigned char *buffer = endpoint->extra; *ep_comp = NULL; while (size >= DESC_HEADER_LENGTH) { header = (struct usbi_descriptor_header *)buffer; - if (header->bLength < 2 || header->bLength > size) { - usbi_err(ctx, "invalid descriptor length %d", - header->bLength); - return LIBUSB_ERROR_IO; - } if (header->bDescriptorType != LIBUSB_DT_SS_ENDPOINT_COMPANION) { + if (header->bLength < DESC_HEADER_LENGTH) { + usbi_err(ctx, "invalid descriptor length %u", + header->bLength); + return LIBUSB_ERROR_IO; + } buffer += header->bLength; size -= header->bLength; continue; - } - if (header->bLength < LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE) { - usbi_err(ctx, "invalid ss-ep-comp-desc length %d", + } else if (header->bLength < LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE) { + usbi_err(ctx, "invalid ss-ep-comp-desc length %u", header->bLength); return LIBUSB_ERROR_IO; + } else if (header->bLength > size) { + usbi_err(ctx, "short ss-ep-comp-desc read %d/%u", + size, header->bLength); + return LIBUSB_ERROR_IO; } + *ep_comp = malloc(sizeof(**ep_comp)); - if (*ep_comp == NULL) + if (!*ep_comp) return LIBUSB_ERROR_NO_MEM; parse_descriptor(buffer, "bbbbw", *ep_comp); return LIBUSB_SUCCESS; @@ -730,11 +759,12 @@ void API_EXPORTED libusb_free_ss_endpoint_companion_descriptor( static int parse_bos(struct libusb_context *ctx, struct libusb_bos_descriptor **bos, - unsigned char *buffer, int size) + const uint8_t *buffer, int size) { - struct libusb_bos_descriptor bos_header, *_bos; - struct libusb_bos_dev_capability_descriptor dev_cap; - int i; + struct libusb_bos_descriptor *_bos; + const struct usbi_bos_descriptor *bos_desc; + const struct usbi_descriptor_header *header; + uint8_t i; if (size < LIBUSB_DT_BOS_SIZE) { usbi_err(ctx, "short bos descriptor read %d/%d", @@ -742,65 +772,61 @@ static int parse_bos(struct libusb_context *ctx, return LIBUSB_ERROR_IO; } - parse_descriptor(buffer, "bbwb", &bos_header); - if (bos_header.bDescriptorType != LIBUSB_DT_BOS) { - usbi_err(ctx, "unexpected descriptor %x (expected %x)", - bos_header.bDescriptorType, LIBUSB_DT_BOS); + bos_desc = (const struct usbi_bos_descriptor *)buffer; + if (bos_desc->bDescriptorType != LIBUSB_DT_BOS) { + usbi_err(ctx, "unexpected descriptor 0x%x (expected 0x%x)", + bos_desc->bDescriptorType, LIBUSB_DT_BOS); return LIBUSB_ERROR_IO; - } - if (bos_header.bLength < LIBUSB_DT_BOS_SIZE) { - usbi_err(ctx, "invalid bos bLength (%d)", bos_header.bLength); + } else if (bos_desc->bLength < LIBUSB_DT_BOS_SIZE) { + usbi_err(ctx, "invalid bos bLength (%u)", bos_desc->bLength); return LIBUSB_ERROR_IO; - } - if (bos_header.bLength > size) { - usbi_err(ctx, "short bos descriptor read %d/%d", - size, bos_header.bLength); + } else if (bos_desc->bLength > size) { + usbi_err(ctx, "short bos descriptor read %d/%u", + size, bos_desc->bLength); return LIBUSB_ERROR_IO; } - _bos = calloc(1, sizeof(*_bos) + bos_header.bNumDeviceCaps * sizeof(void *)); + _bos = calloc(1, sizeof(*_bos) + bos_desc->bNumDeviceCaps * sizeof(void *)); if (!_bos) return LIBUSB_ERROR_NO_MEM; parse_descriptor(buffer, "bbwb", _bos); - buffer += bos_header.bLength; - size -= bos_header.bLength; + buffer += _bos->bLength; + size -= _bos->bLength; /* Get the device capability descriptors */ - for (i = 0; i < bos_header.bNumDeviceCaps; i++) { + for (i = 0; i < _bos->bNumDeviceCaps; i++) { if (size < LIBUSB_DT_DEVICE_CAPABILITY_SIZE) { usbi_warn(ctx, "short dev-cap descriptor read %d/%d", size, LIBUSB_DT_DEVICE_CAPABILITY_SIZE); break; } - parse_descriptor(buffer, "bbb", &dev_cap); - if (dev_cap.bDescriptorType != LIBUSB_DT_DEVICE_CAPABILITY) { - usbi_warn(ctx, "unexpected descriptor %x (expected %x)", - dev_cap.bDescriptorType, LIBUSB_DT_DEVICE_CAPABILITY); + header = (const struct usbi_descriptor_header *)buffer; + if (header->bDescriptorType != LIBUSB_DT_DEVICE_CAPABILITY) { + usbi_warn(ctx, "unexpected descriptor 0x%x (expected 0x%x)", + header->bDescriptorType, LIBUSB_DT_DEVICE_CAPABILITY); break; - } - if (dev_cap.bLength < LIBUSB_DT_DEVICE_CAPABILITY_SIZE) { - usbi_err(ctx, "invalid dev-cap bLength (%d)", - dev_cap.bLength); + } else if (header->bLength < LIBUSB_DT_DEVICE_CAPABILITY_SIZE) { + usbi_err(ctx, "invalid dev-cap bLength (%u)", + header->bLength); libusb_free_bos_descriptor(_bos); return LIBUSB_ERROR_IO; - } - if (dev_cap.bLength > size) { - usbi_warn(ctx, "short dev-cap descriptor read %d/%d", - size, dev_cap.bLength); + } else if (header->bLength > size) { + usbi_warn(ctx, "short dev-cap descriptor read %d/%u", + size, header->bLength); break; } - _bos->dev_capability[i] = malloc(dev_cap.bLength); + _bos->dev_capability[i] = malloc(header->bLength); if (!_bos->dev_capability[i]) { libusb_free_bos_descriptor(_bos); return LIBUSB_ERROR_NO_MEM; } - memcpy(_bos->dev_capability[i], buffer, dev_cap.bLength); - buffer += dev_cap.bLength; - size -= dev_cap.bLength; + memcpy(_bos->dev_capability[i], buffer, header->bLength); + buffer += header->bLength; + size -= header->bLength; } - _bos->bNumDeviceCaps = (uint8_t)i; + _bos->bNumDeviceCaps = i; *bos = _bos; return LIBUSB_SUCCESS; @@ -820,15 +846,14 @@ static int parse_bos(struct libusb_context *ctx, int API_EXPORTED libusb_get_bos_descriptor(libusb_device_handle *dev_handle, struct libusb_bos_descriptor **bos) { - struct libusb_bos_descriptor _bos; - uint8_t bos_header[LIBUSB_DT_BOS_SIZE] = {0}; - unsigned char *bos_data = NULL; + union usbi_bos_desc_buf _bos; + uint16_t bos_len; + uint8_t *bos_data; int r; /* Read the BOS. This generates 2 requests on the bus, * one for the header, and one for the full BOS */ - r = libusb_get_descriptor(dev_handle, LIBUSB_DT_BOS, 0, bos_header, - LIBUSB_DT_BOS_SIZE); + r = libusb_get_descriptor(dev_handle, LIBUSB_DT_BOS, 0, _bos.buf, sizeof(_bos.buf)); if (r < 0) { if (r != LIBUSB_ERROR_PIPE) usbi_err(HANDLE_CTX(dev_handle), "failed to read BOS (%d)", r); @@ -840,19 +865,22 @@ int API_EXPORTED libusb_get_bos_descriptor(libusb_device_handle *dev_handle, return LIBUSB_ERROR_IO; } - parse_descriptor(bos_header, "bbwb", &_bos); - usbi_dbg("found BOS descriptor: size %d bytes, %d capabilities", - _bos.wTotalLength, _bos.bNumDeviceCaps); - bos_data = calloc(1, _bos.wTotalLength); - if (bos_data == NULL) + bos_len = libusb_le16_to_cpu(_bos.desc.wTotalLength); + usbi_dbg("found BOS descriptor: size %u bytes, %u capabilities", + bos_len, _bos.desc.bNumDeviceCaps); + bos_data = calloc(1, bos_len); + if (!bos_data) return LIBUSB_ERROR_NO_MEM; - r = libusb_get_descriptor(dev_handle, LIBUSB_DT_BOS, 0, bos_data, - _bos.wTotalLength); - if (r >= 0) + r = libusb_get_descriptor(dev_handle, LIBUSB_DT_BOS, 0, bos_data, bos_len); + if (r >= 0) { + if (r != (int)bos_len) + usbi_warn(HANDLE_CTX(dev_handle), "short BOS read %d/%u", + r, bos_len); r = parse_bos(HANDLE_CTX(dev_handle), bos, bos_data, r); - else + } else { usbi_err(HANDLE_CTX(dev_handle), "failed to read BOS (%d)", r); + } free(bos_data); return r; @@ -867,7 +895,7 @@ int API_EXPORTED libusb_get_bos_descriptor(libusb_device_handle *dev_handle, */ void API_EXPORTED libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos) { - int i; + uint8_t i; if (!bos) return; @@ -898,13 +926,12 @@ int API_EXPORTED libusb_get_usb_2_0_extension_descriptor( struct libusb_usb_2_0_extension_descriptor *_usb_2_0_extension; if (dev_cap->bDevCapabilityType != LIBUSB_BT_USB_2_0_EXTENSION) { - usbi_err(ctx, "unexpected bDevCapabilityType %x (expected %x)", + usbi_err(ctx, "unexpected bDevCapabilityType 0x%x (expected 0x%x)", dev_cap->bDevCapabilityType, LIBUSB_BT_USB_2_0_EXTENSION); return LIBUSB_ERROR_INVALID_PARAM; - } - if (dev_cap->bLength < LIBUSB_BT_USB_2_0_EXTENSION_SIZE) { - usbi_err(ctx, "short dev-cap descriptor read %d/%d", + } else if (dev_cap->bLength < LIBUSB_BT_USB_2_0_EXTENSION_SIZE) { + usbi_err(ctx, "short dev-cap descriptor read %u/%d", dev_cap->bLength, LIBUSB_BT_USB_2_0_EXTENSION_SIZE); return LIBUSB_ERROR_IO; } @@ -954,13 +981,12 @@ int API_EXPORTED libusb_get_ss_usb_device_capability_descriptor( struct libusb_ss_usb_device_capability_descriptor *_ss_usb_device_cap; if (dev_cap->bDevCapabilityType != LIBUSB_BT_SS_USB_DEVICE_CAPABILITY) { - usbi_err(ctx, "unexpected bDevCapabilityType %x (expected %x)", + usbi_err(ctx, "unexpected bDevCapabilityType 0x%x (expected 0x%x)", dev_cap->bDevCapabilityType, LIBUSB_BT_SS_USB_DEVICE_CAPABILITY); return LIBUSB_ERROR_INVALID_PARAM; - } - if (dev_cap->bLength < LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) { - usbi_err(ctx, "short dev-cap descriptor read %d/%d", + } else if (dev_cap->bLength < LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) { + usbi_err(ctx, "short dev-cap descriptor read %u/%d", dev_cap->bLength, LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE); return LIBUSB_ERROR_IO; } @@ -1010,13 +1036,12 @@ int API_EXPORTED libusb_get_container_id_descriptor(libusb_context *ctx, struct libusb_container_id_descriptor *_container_id; if (dev_cap->bDevCapabilityType != LIBUSB_BT_CONTAINER_ID) { - usbi_err(ctx, "unexpected bDevCapabilityType %x (expected %x)", + usbi_err(ctx, "unexpected bDevCapabilityType 0x%x (expected 0x%x)", dev_cap->bDevCapabilityType, LIBUSB_BT_CONTAINER_ID); return LIBUSB_ERROR_INVALID_PARAM; - } - if (dev_cap->bLength < LIBUSB_BT_CONTAINER_ID_SIZE) { - usbi_err(ctx, "short dev-cap descriptor read %d/%d", + } else if (dev_cap->bLength < LIBUSB_BT_CONTAINER_ID_SIZE) { + usbi_err(ctx, "short dev-cap descriptor read %u/%d", dev_cap->bLength, LIBUSB_BT_CONTAINER_ID_SIZE); return LIBUSB_ERROR_IO; } @@ -1060,9 +1085,9 @@ void API_EXPORTED libusb_free_container_id_descriptor( 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 */ + union usbi_string_desc_buf str; int r, si, di; - uint16_t langid; + uint16_t langid, wdata; /* Asking for the zero'th index is special - it returns a string * descriptor that contains all the language IDs supported by the @@ -1076,35 +1101,37 @@ int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev_ha if (desc_index == 0) return LIBUSB_ERROR_INVALID_PARAM; - r = libusb_get_string_descriptor(dev_handle, 0, 0, tbuf, sizeof(tbuf)); + r = libusb_get_string_descriptor(dev_handle, 0, 0, str.buf, 4); if (r < 0) return r; - - if (r < 4) + else if (r != 4 || str.desc.bLength < 4) return LIBUSB_ERROR_IO; + else if (str.desc.bDescriptorType != LIBUSB_DT_STRING) + return LIBUSB_ERROR_IO; + else if (str.desc.bLength & 1) + usbi_warn(HANDLE_CTX(dev_handle), "suspicious bLength %u for string descriptor", str.desc.bLength); - langid = (uint16_t)(tbuf[2] | (tbuf[3] << 8)); - - r = libusb_get_string_descriptor(dev_handle, desc_index, langid, tbuf, - sizeof(tbuf)); + langid = libusb_le16_to_cpu(str.desc.wData[0]); + r = libusb_get_string_descriptor(dev_handle, desc_index, langid, str.buf, sizeof(str.buf)); if (r < 0) return r; - - if (tbuf[1] != LIBUSB_DT_STRING) + else if (r < DESC_HEADER_LENGTH || str.desc.bLength > r) return LIBUSB_ERROR_IO; - - if (tbuf[0] > r) + else if (str.desc.bDescriptorType != LIBUSB_DT_STRING) return LIBUSB_ERROR_IO; + else if ((str.desc.bLength & 1) || str.desc.bLength != r) + usbi_warn(HANDLE_CTX(dev_handle), "suspicious bLength %u for string descriptor", str.desc.bLength); di = 0; - for (si = 2; si < tbuf[0]; si += 2) { + for (si = 2; si < str.desc.bLength; si += 2) { if (di >= (length - 1)) break; - if ((tbuf[si] & 0x80) || (tbuf[si + 1])) /* non-ASCII */ - data[di++] = '?'; + wdata = libusb_le16_to_cpu(str.desc.wData[di]); + if (wdata < 0x80) + data[di++] = (unsigned char)wdata; else - data[di++] = tbuf[si]; + data[di++] = '?'; /* non-ASCII */ } data[di] = 0; diff --git a/libusb/hotplug.c b/libusb/hotplug.c index e3e83c3..e3e5e76 100644 --- a/libusb/hotplug.c +++ b/libusb/hotplug.c @@ -50,8 +50,8 @@ * expecting additional events. Returning 0 will rearm the callback and 1 will cause * the callback to be deregistered. Note that when callbacks are called from * libusb_hotplug_register_callback() because of the \ref LIBUSB_HOTPLUG_ENUMERATE - * flag, the callback return value is ignored, iow you cannot cause a callback - * to be deregistered by returning 1 when it is called from + * flag, the callback return value is ignored. In other words, you cannot cause a + * callback to be deregistered by returning 1 when it is called from * libusb_hotplug_register_callback(). * * Callbacks for a particular context are automatically deregistered by libusb_exit(). @@ -184,7 +184,7 @@ void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev, usbi_mutex_lock(&ctx->hotplug_cbs_lock); - list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) { + for_each_hotplug_cb_safe(ctx, hotplug_cb, next) { if (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE) { /* process deregistration in usbi_hotplug_deregister() */ continue; @@ -206,8 +206,8 @@ void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev, void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev, libusb_hotplug_event event) { - int pending_events; struct libusb_hotplug_message *message = calloc(1, sizeof(*message)); + unsigned int event_flags; if (!message) { usbi_err(ctx, "error allocating hotplug message"); @@ -220,10 +220,11 @@ void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device /* Take the event data lock and add this message to the list. * Only signal an event if there are no prior pending events. */ usbi_mutex_lock(&ctx->event_data_lock); - pending_events = usbi_pending_events(ctx); + event_flags = ctx->event_flags; + ctx->event_flags |= USBI_EVENT_HOTPLUG_MSG_PENDING; list_add_tail(&message->list, &ctx->hotplug_msgs); - if (!pending_events) - usbi_signal_event(ctx); + if (!event_flags) + usbi_signal_event(&ctx->event); usbi_mutex_unlock(&ctx->event_data_lock); } @@ -331,7 +332,7 @@ void API_EXPORTED libusb_hotplug_deregister_callback(libusb_context *ctx, ctx = usbi_get_context(ctx); usbi_mutex_lock(&ctx->hotplug_cbs_lock); - list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) { + for_each_hotplug_cb(ctx, hotplug_cb) { if (callback_handle == hotplug_cb->handle) { /* Mark this callback for deregistration */ hotplug_cb->flags |= USBI_HOTPLUG_NEEDS_FREE; @@ -341,13 +342,13 @@ void API_EXPORTED libusb_hotplug_deregister_callback(libusb_context *ctx, usbi_mutex_unlock(&ctx->hotplug_cbs_lock); if (deregistered) { - int pending_events; + unsigned int event_flags; usbi_mutex_lock(&ctx->event_data_lock); - pending_events = usbi_pending_events(ctx); + event_flags = ctx->event_flags; ctx->event_flags |= USBI_EVENT_HOTPLUG_CB_DEREGISTERED; - if (!pending_events) - usbi_signal_event(ctx); + if (!event_flags) + usbi_signal_event(&ctx->event); usbi_mutex_unlock(&ctx->event_data_lock); } } @@ -369,7 +370,7 @@ void * LIBUSB_CALL libusb_hotplug_get_user_data(libusb_context *ctx, ctx = usbi_get_context(ctx); usbi_mutex_lock(&ctx->hotplug_cbs_lock); - list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) { + for_each_hotplug_cb(ctx, hotplug_cb) { if (callback_handle == hotplug_cb->handle) { user_data = hotplug_cb->user_data; } @@ -384,7 +385,7 @@ void usbi_hotplug_deregister(struct libusb_context *ctx, int forced) struct libusb_hotplug_callback *hotplug_cb, *next; usbi_mutex_lock(&ctx->hotplug_cbs_lock); - list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) { + for_each_hotplug_cb_safe(ctx, hotplug_cb, next) { if (forced || (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE)) { usbi_dbg("freeing hotplug cb %p with handle %d", hotplug_cb, hotplug_cb->handle); diff --git a/libusb/hotplug.h b/libusb/hotplug.h index 4335fbe..161f7e5 100644 --- a/libusb/hotplug.h +++ b/libusb/hotplug.h @@ -90,6 +90,12 @@ struct libusb_hotplug_message { struct list_head list; }; +#define for_each_hotplug_cb(ctx, c) \ + for_each_helper(c, &(ctx)->hotplug_cbs, struct libusb_hotplug_callback) + +#define for_each_hotplug_cb_safe(ctx, c, n) \ + for_each_safe_helper(c, n, &(ctx)->hotplug_cbs, struct libusb_hotplug_callback) + void usbi_hotplug_deregister(struct libusb_context *ctx, int forced); void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev, libusb_hotplug_event event); diff --git a/libusb/io.c b/libusb/io.c index b969633..0e960dd 100644 --- a/libusb/io.c +++ b/libusb/io.c @@ -24,12 +24,6 @@ #include "libusbi.h" #include "hotplug.h" -#include <errno.h> -#ifdef HAVE_TIMERFD -#include <sys/timerfd.h> -#include <unistd.h> -#endif - /** * \page libusb_io Synchronous and asynchronous device I/O * @@ -79,7 +73,7 @@ * a single function call. When the function call returns, the transfer has * completed and you can parse the results. * - * If you have used the libusb-0.1 before, this I/O style will seem familar to + * If you have used the libusb-0.1 before, this I/O style will seem familiar to * you. libusb-0.1 only offered a synchronous interface. * * In our input device example, to read button presses you might write code @@ -105,7 +99,7 @@ if (r == 0 && actual_length == sizeof(data)) { * sleeping for that long. Execution will be tied up inside the library - * the entire thread will be useless for that duration. * - * Another issue is that by tieing up the thread with that single transaction + * Another issue is that by tying up the thread with that single transaction * there is no possibility of performing I/O with multiple endpoints and/or * multiple devices simultaneously, unless you resort to creating one thread * per transaction. @@ -323,9 +317,40 @@ if (r == 0 && actual_length == sizeof(data)) { * Freeing the transfer after it has been cancelled but before cancellation * has completed will result in undefined behaviour. * + * \attention * When a transfer is cancelled, some of the data may have been transferred. - * libusb will communicate this to you in the transfer callback. Do not assume - * that no data was transferred. + * libusb will communicate this to you in the transfer callback. + * <b>Do not assume that no data was transferred.</b> + * + * \section asyncpartial Partial data transfer resulting from cancellation + * + * As noted above, some of the data may have been transferred at the time a + * transfer is cancelled. It is helpful to see how this is possible if you + * consider a bulk transfer to an endpoint with a packet size of 64 bytes. + * Supposing you submit a 512-byte transfer to this endpoint, the operating + * system will divide this transfer up into 8 separate 64-byte frames that the + * host controller will schedule for the device to transfer data. If this + * transfer is cancelled while the device is transferring data, a subset of + * these frames may be descheduled from the host controller before the device + * has the opportunity to finish transferring data to the host. + * + * What your application should do with a partial data transfer is a policy + * decision; there is no single answer that satisfies the needs of every + * application. The data that was successfully transferred should be + * considered entirely valid, but your application must decide what to do with + * the remaining data that was not transferred. Some possible actions to take + * are: + * - Resubmit another transfer for the remaining data, possibly with a shorter + * timeout + * - Discard the partially transferred data and report an error + * + * \section asynctimeout Timeouts + * + * When a transfer times out, libusb internally notes this and attempts to + * cancel the transfer. As noted in \ref asyncpartial "above", it is possible + * that some of the data may actually have been transferred. Your application + * should <b>always</b> check how much data was actually transferred once the + * transfer completes and act accordingly. * * \section bulk_overflows Overflows on device-to-host bulk/interrupt endpoints * @@ -383,7 +408,7 @@ if (r == 0 && actual_length == sizeof(data)) { * wLength of the setup packet, rather than the size of the data buffer. So, * if your wLength was 4, your transfer's <tt>length</tt> was 12, then you * should expect an <tt>actual_length</tt> of 4 to indicate that the data was - * transferred in entirity. + * transferred in entirety. * * To simplify parsing of setup packets and obtaining the data from the * correct offset, you may wish to use the libusb_control_transfer_get_data() @@ -462,14 +487,21 @@ if (r == 0 && actual_length == sizeof(data)) { * libusb_get_iso_packet_buffer() and libusb_get_iso_packet_buffer_simple() * functions may help you here. * - * <b>Note</b>: Some operating systems (e.g. Linux) may impose limits on the - * length of individual isochronous packets and/or the total length of the - * isochronous transfer. Such limits can be difficult for libusb to detect, - * so the library will simply try and submit the transfer as set up by you. - * If the transfer fails to submit because it is too large, + * \section asynclimits Transfer length limitations + * + * Some operating systems may impose limits on the length of the transfer data + * buffer or, in the case of isochronous transfers, the length of individual + * isochronous packets. Such limits can be difficult for libusb to detect, so + * in most cases the library will simply try and submit the transfer as set up + * by you. If the transfer fails to submit because it is too large, * libusb_submit_transfer() will return * \ref libusb_error::LIBUSB_ERROR_INVALID_PARAM "LIBUSB_ERROR_INVALID_PARAM". * + * The following are known limits for control transfer lengths. Note that this + * length includes the 8-byte setup packet. + * - Linux (4,096 bytes) + * - Windows (4,096 bytes) + * * \section asyncmem Memory caveats * * In most circumstances, it is not safe to use stack memory for transfer @@ -510,7 +542,14 @@ if (r == 0 && actual_length == sizeof(data)) { * application must call into when libusb has work do to. This gives libusb * the opportunity to reap pending transfers, invoke callbacks, etc. * - * There are 2 different approaches to dealing with libusb_handle_events: + * \note + * All event handling is performed by whichever thread calls the + * libusb_handle_events() function. libusb does not invoke any callbacks + * outside of this context. Consequently, any callbacks will be run on the + * thread that calls the libusb_handle_events() function. + * + * When to call the libusb_handle_events() function depends on which model + * your application decides to use. The 2 different approaches: * * -# Repeatedly call libusb_handle_events() in blocking mode from a dedicated * thread. @@ -531,7 +570,7 @@ if (r == 0 && actual_length == sizeof(data)) { * * Lets begin with stating the obvious: If you're going to use a separate * thread for libusb event handling, your callback functions MUST be - * threadsafe. + * thread-safe. * * Other then that doing event handling from a separate thread, is mostly * simple. You can use an event thread function as follows: @@ -771,7 +810,7 @@ while (user has not requested application exit) { * system calls. This is directly exposed at 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. + * asynchronous interface, therefore the same considerations apply. * * The issue is that if two or more threads are concurrently calling poll() * or select() on libusb's file descriptors then only one of those threads @@ -879,6 +918,11 @@ void myfunc() { * do is submit a single transfer and wait for its completion, then using * one of the synchronous I/O functions is much easier. * + * \note + * The `completed` variable must be modified while holding the event lock, + * otherwise a race condition can still exist. It is simplest to do so from + * within the transfer callback as shown above. + * * \section eventlock The events lock * * The problem is when we consider the fact that libusb exposes file @@ -976,7 +1020,7 @@ printf("completed!\n"); * event handling), because the event waiter seems to have taken the event * waiters lock while waiting for an event. However, the system does support * multiple event waiters, because libusb_wait_for_event() actually drops - * the lock while waiting, and reaquires it before continuing. + * the lock while waiting, and reacquires it before continuing. * * We have now implemented code which can dynamically handle situations where * nobody is handling events (so we should do it ourselves), and it can also @@ -1121,44 +1165,40 @@ int usbi_io_init(struct libusb_context *ctx) 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->removed_ipollfds); + list_init(&ctx->event_sources); + list_init(&ctx->removed_event_sources); list_init(&ctx->hotplug_msgs); list_init(&ctx->completed_transfers); - /* FIXME should use an eventfd on kernels that support it */ - r = usbi_pipe(ctx->event_pipe); - if (r < 0) { - r = LIBUSB_ERROR_OTHER; + r = usbi_create_event(&ctx->event); + if (r < 0) goto err; - } - r = usbi_add_pollfd(ctx, ctx->event_pipe[0], POLLIN); + r = usbi_add_event_source(ctx, USBI_EVENT_OS_HANDLE(&ctx->event), USBI_EVENT_POLL_EVENTS); if (r < 0) - goto err_close_pipe; + goto err_destroy_event; -#ifdef HAVE_TIMERFD - ctx->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); - if (ctx->timerfd >= 0) { - usbi_dbg("using timerfd for timeouts"); - r = usbi_add_pollfd(ctx, ctx->timerfd, POLLIN); +#ifdef HAVE_OS_TIMER + r = usbi_create_timer(&ctx->timer); + if (r == 0) { + usbi_dbg("using timer for timeouts"); + r = usbi_add_event_source(ctx, USBI_TIMER_OS_HANDLE(&ctx->timer), USBI_TIMER_POLL_EVENTS); if (r < 0) - goto err_close_timerfd; + goto err_destroy_timer; } else { - usbi_dbg("timerfd not available, errno=%d", errno); + usbi_dbg("timer not available for timeouts"); } #endif return 0; -#ifdef HAVE_TIMERFD -err_close_timerfd: - close(ctx->timerfd); - usbi_remove_pollfd(ctx, ctx->event_pipe[0]); +#ifdef HAVE_OS_TIMER +err_destroy_timer: + usbi_destroy_timer(&ctx->timer); + usbi_remove_event_source(ctx, USBI_EVENT_OS_HANDLE(&ctx->event)); #endif -err_close_pipe: - usbi_close(ctx->event_pipe[0]); - usbi_close(ctx->event_pipe[1]); +err_destroy_event: + usbi_destroy_event(&ctx->event); err: usbi_mutex_destroy(&ctx->flying_transfers_lock); usbi_mutex_destroy(&ctx->events_lock); @@ -1169,62 +1209,54 @@ err: return r; } -static void cleanup_removed_pollfds(struct libusb_context *ctx) +static void cleanup_removed_event_sources(struct libusb_context *ctx) { - struct usbi_pollfd *ipollfd, *tmp; - list_for_each_entry_safe(ipollfd, tmp, &ctx->removed_ipollfds, list, struct usbi_pollfd) { - list_del(&ipollfd->list); - free(ipollfd); + struct usbi_event_source *ievent_source, *tmp; + + for_each_removed_event_source_safe(ctx, ievent_source, tmp) { + list_del(&ievent_source->list); + free(ievent_source); } } void usbi_io_exit(struct libusb_context *ctx) { - usbi_remove_pollfd(ctx, ctx->event_pipe[0]); - usbi_close(ctx->event_pipe[0]); - usbi_close(ctx->event_pipe[1]); -#ifdef HAVE_TIMERFD - if (usbi_using_timerfd(ctx)) { - usbi_remove_pollfd(ctx, ctx->timerfd); - close(ctx->timerfd); +#ifdef HAVE_OS_TIMER + if (usbi_using_timer(ctx)) { + usbi_remove_event_source(ctx, USBI_TIMER_OS_HANDLE(&ctx->timer)); + usbi_destroy_timer(&ctx->timer); } #endif + usbi_remove_event_source(ctx, USBI_EVENT_OS_HANDLE(&ctx->event)); + usbi_destroy_event(&ctx->event); usbi_mutex_destroy(&ctx->flying_transfers_lock); usbi_mutex_destroy(&ctx->events_lock); 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); - free(ctx->pollfds); - cleanup_removed_pollfds(ctx); + cleanup_removed_event_sources(ctx); + free(ctx->event_data); } -static int calculate_timeout(struct usbi_transfer *itransfer) +static void calculate_timeout(struct usbi_transfer *itransfer) { - int r; unsigned int timeout = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer)->timeout; if (!timeout) { TIMESPEC_CLEAR(&itransfer->timeout); - return 0; + return; } - r = usbi_clock_gettime(USBI_CLOCK_MONOTONIC, &itransfer->timeout); - if (r < 0) { - usbi_err(ITRANSFER_CTX(itransfer), - "failed to read monotonic clock, errno=%d", errno); - return LIBUSB_ERROR_OTHER; - } + usbi_get_monotonic_time(&itransfer->timeout); itransfer->timeout.tv_sec += timeout / 1000U; itransfer->timeout.tv_nsec += (timeout % 1000U) * 1000000L; - if (itransfer->timeout.tv_nsec >= 1000000000L) { + if (itransfer->timeout.tv_nsec >= NSEC_PER_SEC) { ++itransfer->timeout.tv_sec; - itransfer->timeout.tv_nsec -= 1000000000L; + itransfer->timeout.tv_nsec -= NSEC_PER_SEC; } - - return 0; } /** \ingroup libusb_asyncio @@ -1321,55 +1353,39 @@ void API_EXPORTED libusb_free_transfer(struct libusb_transfer *transfer) free(ptr); } -#ifdef HAVE_TIMERFD -static int disarm_timerfd(struct libusb_context *ctx) -{ - const struct itimerspec disarm_timer = { { 0, 0 }, { 0, 0 } }; - int r; - - usbi_dbg(" "); - r = timerfd_settime(ctx->timerfd, 0, &disarm_timer, NULL); - if (r < 0) - return LIBUSB_ERROR_OTHER; - else - return 0; -} - -/* iterates through the flying transfers, and rearms the timerfd based on the +/* iterates through the flying transfers, and rearms the timer based on the * next upcoming timeout. * must be called with flying_list locked. * returns 0 on success or a LIBUSB_ERROR code on failure. */ -static int arm_timerfd_for_next_timeout(struct libusb_context *ctx) +#ifdef HAVE_OS_TIMER +static int arm_timer_for_next_timeout(struct libusb_context *ctx) { struct usbi_transfer *itransfer; - list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) { + if (!usbi_using_timer(ctx)) + return 0; + + for_each_transfer(ctx, itransfer) { struct timespec *cur_ts = &itransfer->timeout; /* if we've reached transfers of infinite timeout, then we have no * arming to do */ if (!TIMESPEC_IS_SET(cur_ts)) - goto disarm; + break; /* act on first transfer that has not already been handled */ if (!(itransfer->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT))) { - int r; - const struct itimerspec it = { {0, 0}, - { cur_ts->tv_sec, cur_ts->tv_nsec } }; usbi_dbg("next timeout originally %ums", USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer)->timeout); - r = timerfd_settime(ctx->timerfd, TFD_TIMER_ABSTIME, &it, NULL); - if (r < 0) - return LIBUSB_ERROR_OTHER; - return 0; + return usbi_arm_timer(&ctx->timer, cur_ts); } } -disarm: - return disarm_timerfd(ctx); + usbi_dbg("no timeouts, disarming timer"); + return usbi_disarm_timer(&ctx->timer); } #else -static int arm_timerfd_for_next_timeout(struct libusb_context *ctx) +static inline int arm_timer_for_next_timeout(struct libusb_context *ctx) { UNUSED(ctx); return 0; @@ -1384,12 +1400,10 @@ static int add_to_flying_list(struct usbi_transfer *itransfer) struct usbi_transfer *cur; struct timespec *timeout = &itransfer->timeout; struct libusb_context *ctx = ITRANSFER_CTX(itransfer); - int r; + int r = 0; int first = 1; - r = calculate_timeout(itransfer); - if (r) - return r; + calculate_timeout(itransfer); /* if we have no other flying transfers, start the list with this one */ if (list_empty(&ctx->flying_transfers)) { @@ -1405,7 +1419,7 @@ static int add_to_flying_list(struct usbi_transfer *itransfer) } /* otherwise, find appropriate place in list */ - list_for_each_entry(cur, &ctx->flying_transfers, list, struct usbi_transfer) { + for_each_transfer(ctx, cur) { /* find first timeout that occurs after the transfer in question */ struct timespec *cur_ts = &cur->timeout; @@ -1420,19 +1434,13 @@ static int add_to_flying_list(struct usbi_transfer *itransfer) /* otherwise we need to be inserted at the end */ list_add_tail(&itransfer->list, &ctx->flying_transfers); out: -#ifdef HAVE_TIMERFD - if (first && usbi_using_timerfd(ctx) && TIMESPEC_IS_SET(timeout)) { +#ifdef HAVE_OS_TIMER + if (first && usbi_using_timer(ctx) && TIMESPEC_IS_SET(timeout)) { /* if this transfer has the lowest timeout of all active transfers, - * rearm the timerfd with this transfer's timeout */ - const struct itimerspec it = { {0, 0}, - { timeout->tv_sec, timeout->tv_nsec } }; - usbi_dbg("arm timerfd for timeout in %ums (first in line)", + * rearm the timer with this transfer's timeout */ + usbi_dbg("arm timer for timeout in %ums (first in line)", USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer)->timeout); - r = timerfd_settime(ctx->timerfd, TFD_TIMER_ABSTIME, &it, NULL); - if (r < 0) { - usbi_warn(ctx, "failed to arm first timerfd, errno=%d", errno); - r = LIBUSB_ERROR_OTHER; - } + r = usbi_arm_timer(&ctx->timer, timeout); } #else UNUSED(first); @@ -1451,15 +1459,15 @@ out: static int remove_from_flying_list(struct usbi_transfer *itransfer) { struct libusb_context *ctx = ITRANSFER_CTX(itransfer); - int rearm_timerfd; + int rearm_timer; int r = 0; usbi_mutex_lock(&ctx->flying_transfers_lock); - rearm_timerfd = (TIMESPEC_IS_SET(&itransfer->timeout) && + rearm_timer = (TIMESPEC_IS_SET(&itransfer->timeout) && list_first_entry(&ctx->flying_transfers, struct usbi_transfer, list) == itransfer); list_del(&itransfer->list); - if (usbi_using_timerfd(ctx) && rearm_timerfd) - r = arm_timerfd_for_next_timeout(ctx); + if (rearm_timer) + r = arm_timer_for_next_timeout(ctx); usbi_mutex_unlock(&ctx->flying_transfers_lock); return r; @@ -1476,7 +1484,7 @@ static int remove_from_flying_list(struct usbi_transfer *itransfer) * \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 + * the operating system and/or hardware can support (see \ref asynclimits) * \returns another LIBUSB_ERROR code on other failure */ int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer) @@ -1659,7 +1667,7 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, r = remove_from_flying_list(itransfer); if (r < 0) - usbi_err(ITRANSFER_CTX(itransfer), "failed to set timer for next timeout, errno=%d", errno); + usbi_err(ITRANSFER_CTX(itransfer), "failed to set timer for next timeout"); usbi_mutex_lock(&itransfer->lock); itransfer->state_flags &= ~USBI_TRANSFER_IN_FLIGHT; @@ -1724,13 +1732,14 @@ void usbi_signal_transfer_completion(struct usbi_transfer *itransfer) if (dev_handle) { struct libusb_context *ctx = HANDLE_CTX(dev_handle); - int pending_events; + unsigned int event_flags; usbi_mutex_lock(&ctx->event_data_lock); - pending_events = usbi_pending_events(ctx); + event_flags = ctx->event_flags; + ctx->event_flags |= USBI_EVENT_TRANSFER_COMPLETED; list_add_tail(&itransfer->completed_list, &ctx->completed_transfers); - if (!pending_events) - usbi_signal_event(ctx); + if (!event_flags) + usbi_signal_event(&ctx->event); usbi_mutex_unlock(&ctx->event_data_lock); } } @@ -1772,7 +1781,7 @@ int API_EXPORTED libusb_try_lock_events(libusb_context *ctx) } r = usbi_mutex_trylock(&ctx->events_lock); - if (r) + if (!r) return 1; ctx->event_handler_active = 1; @@ -1907,17 +1916,17 @@ int API_EXPORTED libusb_event_handler_active(libusb_context *ctx) */ void API_EXPORTED libusb_interrupt_event_handler(libusb_context *ctx) { - int pending_events; + unsigned int event_flags; usbi_dbg(" "); ctx = usbi_get_context(ctx); usbi_mutex_lock(&ctx->event_data_lock); - pending_events = usbi_pending_events(ctx); + event_flags = ctx->event_flags; ctx->event_flags |= USBI_EVENT_USER_INTERRUPT; - if (!pending_events) - usbi_signal_event(ctx); + if (!event_flags) + usbi_signal_event(&ctx->event); usbi_mutex_unlock(&ctx->event_data_lock); } @@ -1933,7 +1942,7 @@ void API_EXPORTED libusb_interrupt_event_handler(libusb_context *ctx) * * You only need to use this lock if you are developing an application * which calls poll() or select() on libusb's file descriptors directly, - * <b>and</b> may potentially be handling events from 2 threads simultaenously. + * <b>and</b> may potentially be handling events from 2 threads simultaneously. * If you stick to libusb's event handling loop functions (e.g. * libusb_handle_events()) then you do not need to be concerned with this * locking. @@ -1981,6 +1990,7 @@ 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 + * \returns LIBUSB_ERROR_INVALID_PARAM if timeval is invalid * \ref libusb_mtasync */ int API_EXPORTED libusb_wait_for_event(libusb_context *ctx, struct timeval *tv) @@ -1988,18 +1998,20 @@ int API_EXPORTED libusb_wait_for_event(libusb_context *ctx, struct timeval *tv) int r; ctx = usbi_get_context(ctx); - if (tv == NULL) { + if (!tv) { usbi_cond_wait(&ctx->event_waiters_cond, &ctx->event_waiters_lock); return 0; } + if (!TIMEVAL_IS_VALID(tv)) + return LIBUSB_ERROR_INVALID_PARAM; + r = usbi_cond_timedwait(&ctx->event_waiters_cond, &ctx->event_waiters_lock, tv); - if (r < 0) - return r; - else - return (r == ETIMEDOUT); + return r == LIBUSB_ERROR_TIMEOUT; + + return 0; } static void handle_timeout(struct usbi_transfer *itransfer) @@ -2014,33 +2026,28 @@ static void handle_timeout(struct usbi_transfer *itransfer) itransfer->timeout_flags |= USBI_TRANSFER_TIMED_OUT; else usbi_warn(TRANSFER_CTX(transfer), - "async cancel failed %d errno=%d", r, errno); + "async cancel failed %d", r); } -static int handle_timeouts_locked(struct libusb_context *ctx) +static void handle_timeouts_locked(struct libusb_context *ctx) { - int r; struct timespec systime; struct usbi_transfer *itransfer; if (list_empty(&ctx->flying_transfers)) - return 0; + return; /* get current time */ - r = usbi_clock_gettime(USBI_CLOCK_MONOTONIC, &systime); - if (r < 0) { - usbi_err(ctx, "failed to read monotonic clock, errno=%d", errno); - return LIBUSB_ERROR_OTHER; - } + usbi_get_monotonic_time(&systime); /* iterate through flying transfers list, finding all transfers that * have expired timeouts */ - list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) { + for_each_transfer(ctx, itransfer) { struct timespec *cur_ts = &itransfer->timeout; /* if we've reached transfers of infinite timeout, we're all done */ if (!TIMESPEC_IS_SET(cur_ts)) - return 0; + return; /* ignore timeouts we've already handled */ if (itransfer->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT)) @@ -2048,42 +2055,120 @@ static int handle_timeouts_locked(struct libusb_context *ctx) /* if transfer has non-expired timeout, nothing more to do */ if (TIMESPEC_CMP(cur_ts, &systime, >)) - return 0; + return; /* otherwise, we've got an expired timeout to handle */ handle_timeout(itransfer); } - return 0; } -static int handle_timeouts(struct libusb_context *ctx) +static void handle_timeouts(struct libusb_context *ctx) { - int r; - ctx = usbi_get_context(ctx); usbi_mutex_lock(&ctx->flying_transfers_lock); - r = handle_timeouts_locked(ctx); + handle_timeouts_locked(ctx); usbi_mutex_unlock(&ctx->flying_transfers_lock); +} + +static int handle_event_trigger(struct libusb_context *ctx) +{ + struct list_head hotplug_msgs; + int r = 0; + + usbi_dbg("event triggered"); + + list_init(&hotplug_msgs); + + /* take the the event data lock while processing events */ + usbi_mutex_lock(&ctx->event_data_lock); + + /* check if someone modified the event sources */ + if (ctx->event_flags & USBI_EVENT_EVENT_SOURCES_MODIFIED) + usbi_dbg("someone updated the event sources"); + + if (ctx->event_flags & USBI_EVENT_USER_INTERRUPT) { + usbi_dbg("someone purposefully interrupted"); + ctx->event_flags &= ~USBI_EVENT_USER_INTERRUPT; + } + + /* check if someone is closing a device */ + if (ctx->event_flags & USBI_EVENT_DEVICE_CLOSE) + usbi_dbg("someone is closing a device"); + + /* check for any pending hotplug messages */ + if (ctx->event_flags & USBI_EVENT_HOTPLUG_MSG_PENDING) { + usbi_dbg("hotplug message received"); + ctx->event_flags &= ~USBI_EVENT_HOTPLUG_MSG_PENDING; + assert(!list_empty(&ctx->hotplug_msgs)); + list_cut(&hotplug_msgs, &ctx->hotplug_msgs); + } + + /* complete any pending transfers */ + if (ctx->event_flags & USBI_EVENT_TRANSFER_COMPLETED) { + struct usbi_transfer *itransfer, *tmp; + struct list_head completed_transfers; + + assert(!list_empty(&ctx->completed_transfers)); + list_cut(&completed_transfers, &ctx->completed_transfers); + usbi_mutex_unlock(&ctx->event_data_lock); + + __for_each_completed_transfer_safe(&completed_transfers, itransfer, tmp) { + list_del(&itransfer->completed_list); + r = usbi_backend.handle_transfer_completion(itransfer); + if (r) { + usbi_err(ctx, "backend handle_transfer_completion failed with error %d", r); + break; + } + } + + usbi_mutex_lock(&ctx->event_data_lock); + if (!list_empty(&completed_transfers)) { + /* an error occurred, put the remaining transfers back on the list */ + list_splice_front(&completed_transfers, &ctx->completed_transfers); + } else if (list_empty(&ctx->completed_transfers)) { + ctx->event_flags &= ~USBI_EVENT_TRANSFER_COMPLETED; + } + } + + /* if no further pending events, clear the event */ + if (!ctx->event_flags) + usbi_clear_event(&ctx->event); + + usbi_mutex_unlock(&ctx->event_data_lock); + + /* process the hotplug messages, if any */ + while (!list_empty(&hotplug_msgs)) { + struct libusb_hotplug_message *message = + list_first_entry(&hotplug_msgs, struct libusb_hotplug_message, list); + + usbi_hotplug_match(ctx, message->device, message->event); + + /* the device left, dereference the device */ + if (message->event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) + libusb_unref_device(message->device); + + list_del(&message->list); + free(message); + } + return r; } -#ifdef HAVE_TIMERFD -static int handle_timerfd_trigger(struct libusb_context *ctx) +#ifdef HAVE_OS_TIMER +static int handle_timer_trigger(struct libusb_context *ctx) { int r; usbi_mutex_lock(&ctx->flying_transfers_lock); /* process the timeout that just happened */ - r = handle_timeouts_locked(ctx); - if (r < 0) - goto out; + handle_timeouts_locked(ctx); /* arm for next timeout */ - r = arm_timerfd_for_next_timeout(ctx); + r = arm_timer_for_next_timeout(ctx); -out: usbi_mutex_unlock(&ctx->flying_transfers_lock); + return r; } #endif @@ -2092,81 +2177,38 @@ out: * doing the same thing. */ static int handle_events(struct libusb_context *ctx, struct timeval *tv) { - int r; - struct usbi_pollfd *ipollfd; - usbi_nfds_t nfds = 0; - usbi_nfds_t internal_nfds; - struct pollfd *fds = NULL; - int timeout_ms; + struct usbi_reported_events reported_events; + int r, timeout_ms; /* prevent attempts to recursively handle events (e.g. calling into * libusb_handle_events() from within a hotplug or transfer callback) */ - usbi_mutex_lock(&ctx->event_data_lock); - r = 0; if (usbi_handling_events(ctx)) - r = LIBUSB_ERROR_BUSY; - else - usbi_start_event_handling(ctx); - usbi_mutex_unlock(&ctx->event_data_lock); - - if (r) - return r; - - /* there are certain fds that libusb uses internally, currently: - * - * 1) event pipe - * 2) timerfd - * - * the backend will never need to attempt to handle events on these fds, so - * we determine how many fds are in use internally for this context and when - * handle_events() is called in the backend, the pollfd list and count will - * be adjusted to skip over these internal fds */ - if (usbi_using_timerfd(ctx)) - internal_nfds = 2; - else - internal_nfds = 1; + return LIBUSB_ERROR_BUSY; - /* 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 */ + /* only reallocate the event source data when the list of event sources has + * been modified since the last handle_events(), otherwise reuse them to + * save the additional overhead */ usbi_mutex_lock(&ctx->event_data_lock); - /* clean up removed poll fds */ - cleanup_removed_pollfds(ctx); - if (ctx->event_flags & USBI_EVENT_POLLFDS_MODIFIED) { - int i = 0; - - usbi_dbg("poll fds modified, reallocating"); + if (ctx->event_flags & USBI_EVENT_EVENT_SOURCES_MODIFIED) { + usbi_dbg("event sources modified, reallocating event data"); - free(ctx->pollfds); - ctx->pollfds = NULL; + /* free anything removed since we last ran */ + cleanup_removed_event_sources(ctx); - /* sanity check - it is invalid for a context to have fewer than the - * required internal fds (memory corruption?) */ - assert(ctx->pollfds_cnt >= internal_nfds); - - ctx->pollfds = calloc(ctx->pollfds_cnt, sizeof(*ctx->pollfds)); - if (!ctx->pollfds) { + r = usbi_alloc_event_data(ctx); + if (r) { usbi_mutex_unlock(&ctx->event_data_lock); - r = LIBUSB_ERROR_NO_MEM; - goto done; - } - - list_for_each_entry(ipollfd, &ctx->ipollfds, list, struct usbi_pollfd) { - struct libusb_pollfd *pollfd = &ipollfd->pollfd; - ctx->pollfds[i].fd = pollfd->fd; - ctx->pollfds[i].events = pollfd->events; - i++; + return r; } /* reset the flag now that we have the updated list */ - ctx->event_flags &= ~USBI_EVENT_POLLFDS_MODIFIED; + ctx->event_flags &= ~USBI_EVENT_EVENT_SOURCES_MODIFIED; - /* if no further pending events, clear the event pipe so that we do - * not immediately return from poll */ - if (!usbi_pending_events(ctx)) - usbi_clear_event(ctx); + /* if no further pending events, clear the event so that we do + * not immediately return from the wait function */ + if (!ctx->event_flags) + usbi_clear_event(&ctx->event); } - fds = ctx->pollfds; - nfds = ctx->pollfds_cnt; usbi_mutex_unlock(&ctx->event_data_lock); timeout_ms = (int)(tv->tv_sec * 1000) + (tv->tv_usec / 1000); @@ -2175,141 +2217,42 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv) if (tv->tv_usec % 1000) timeout_ms++; - usbi_dbg("poll() %d fds with timeout in %dms", (int)nfds, timeout_ms); - r = usbi_poll(fds, nfds, timeout_ms); - usbi_dbg("poll() returned %d", r); - 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, errno=%d", errno); - r = LIBUSB_ERROR_IO; - goto done; - } - - /* fds[0] is always the event pipe */ - if (fds[0].revents) { - struct list_head hotplug_msgs; - struct usbi_transfer *itransfer; - int hotplug_cb_deregistered = 0; - int ret = 0; - - list_init(&hotplug_msgs); + reported_events.event_bits = 0; - usbi_dbg("caught a fish on the event pipe"); + usbi_start_event_handling(ctx); - /* take the the event data lock while processing events */ - usbi_mutex_lock(&ctx->event_data_lock); - - /* check if someone added a new poll fd */ - 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; - } - - if (ctx->event_flags & USBI_EVENT_HOTPLUG_CB_DEREGISTERED) { - usbi_dbg("someone unregistered a hotplug cb"); - ctx->event_flags &= ~USBI_EVENT_HOTPLUG_CB_DEREGISTERED; - hotplug_cb_deregistered = 1; - } - - /* check if someone is closing a device */ - if (ctx->device_close) - usbi_dbg("someone is closing a device"); - - /* check for any pending hotplug messages */ - if (!list_empty(&ctx->hotplug_msgs)) { - usbi_dbg("hotplug message received"); - list_cut(&hotplug_msgs, &ctx->hotplug_msgs); - } - - /* complete any pending transfers */ - while (ret == 0 && !list_empty(&ctx->completed_transfers)) { - itransfer = list_first_entry(&ctx->completed_transfers, struct usbi_transfer, completed_list); - list_del(&itransfer->completed_list); - usbi_mutex_unlock(&ctx->event_data_lock); - ret = usbi_backend.handle_transfer_completion(itransfer); - if (ret) - usbi_err(ctx, "backend handle_transfer_completion failed with error %d", ret); - usbi_mutex_lock(&ctx->event_data_lock); - } - - /* if no further pending events, clear the event pipe */ - if (!usbi_pending_events(ctx)) - usbi_clear_event(ctx); - - usbi_mutex_unlock(&ctx->event_data_lock); - - if (hotplug_cb_deregistered) - usbi_hotplug_deregister(ctx, 0); - - /* process the hotplug messages, if any */ - while (!list_empty(&hotplug_msgs)) { - struct libusb_hotplug_message *message = - list_first_entry(&hotplug_msgs, struct libusb_hotplug_message, list); - - usbi_hotplug_match(ctx, message->device, message->event); - - /* the device left, dereference the device */ - if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == message->event) - libusb_unref_device(message->device); - - list_del(&message->list); - free(message); + r = usbi_wait_for_events(ctx, &reported_events, timeout_ms); + if (r != LIBUSB_SUCCESS) { + if (r == LIBUSB_ERROR_TIMEOUT) { + handle_timeouts(ctx); + r = LIBUSB_SUCCESS; } + goto done; + } - if (ret) { + if (reported_events.event_triggered) { + r = handle_event_trigger(ctx); + if (r) { /* return error code */ - r = ret; goto done; } - - if (0 == --r) - goto done; } -#ifdef HAVE_TIMERFD - /* on timerfd configurations, fds[1] is the timerfd */ - if (usbi_using_timerfd(ctx) && fds[1].revents) { - /* timerfd indicates that a timeout has expired */ - int ret; - usbi_dbg("timerfd triggered"); - - ret = handle_timerfd_trigger(ctx); - if (ret < 0) { +#ifdef HAVE_OS_TIMER + if (reported_events.timer_triggered) { + r = handle_timer_trigger(ctx); + if (r) { /* return error code */ - r = ret; goto done; } - - if (0 == --r) - goto done; } #endif - list_for_each_entry(ipollfd, &ctx->removed_ipollfds, list, struct usbi_pollfd) { - usbi_nfds_t n; - - for (n = internal_nfds ; n < nfds ; n++) { - if (ipollfd->pollfd.fd == fds[n].fd) { - /* pollfd was removed between the creation of the fd - * array and here. remove any triggered revent as - * it is no longer relevant */ - usbi_dbg("pollfd %d was removed. ignoring raised events", - fds[n].fd); - fds[n].revents = 0; - break; - } - } - } + if (!reported_events.num_ready) + goto done; - r = usbi_backend.handle_events(ctx, fds + internal_nfds, nfds - internal_nfds, r); + r = usbi_backend.handle_events(ctx, reported_events.event_data, + reported_events.event_data_count, reported_events.num_ready); if (r) usbi_err(ctx, "backend handle_events failed with error %d", r); @@ -2368,7 +2311,9 @@ static int get_next_timeout(libusb_context *ctx, struct timeval *tv, * \param tv the maximum time to block waiting for events, or an all zero * 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 + * \returns 0 on success + * \returns LIBUSB_ERROR_INVALID_PARAM if timeval is invalid + * \returns another LIBUSB_ERROR code on other failure * \ref libusb_mtasync */ int API_EXPORTED libusb_handle_events_timeout_completed(libusb_context *ctx, @@ -2377,11 +2322,15 @@ int API_EXPORTED libusb_handle_events_timeout_completed(libusb_context *ctx, int r; struct timeval poll_timeout; + if (!TIMEVAL_IS_VALID(tv)) + return LIBUSB_ERROR_INVALID_PARAM; + ctx = usbi_get_context(ctx); r = get_next_timeout(ctx, tv, &poll_timeout); if (r) { /* timeout already expired */ - return handle_timeouts(ctx); + handle_timeouts(ctx); + return 0; } retry: @@ -2419,9 +2368,8 @@ already_done: if (r < 0) return r; else if (r == 1) - return handle_timeouts(ctx); - else - return 0; + handle_timeouts(ctx); + return 0; } /** \ingroup libusb_poll @@ -2448,7 +2396,7 @@ int API_EXPORTED libusb_handle_events_timeout(libusb_context *ctx, /** \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 + * hard-coded 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 * for control over the timeout, use libusb_handle_events_timeout_completed() * instead. @@ -2505,7 +2453,9 @@ int API_EXPORTED libusb_handle_events_completed(libusb_context *ctx, * \param ctx the context to operate on, or NULL for the default context * \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 + * \returns 0 on success + * \returns LIBUSB_ERROR_INVALID_PARAM if timeval is invalid + * \returns another LIBUSB_ERROR code on other failure * \ref libusb_mtasync */ int API_EXPORTED libusb_handle_events_locked(libusb_context *ctx, @@ -2514,11 +2464,15 @@ int API_EXPORTED libusb_handle_events_locked(libusb_context *ctx, int r; struct timeval poll_timeout; + if (!TIMEVAL_IS_VALID(tv)) + return LIBUSB_ERROR_INVALID_PARAM; + ctx = usbi_get_context(ctx); r = get_next_timeout(ctx, tv, &poll_timeout); if (r) { /* timeout already expired */ - return handle_timeouts(ctx); + handle_timeouts(ctx); + return 0; } return handle_events(ctx, &poll_timeout); @@ -2554,13 +2508,8 @@ int API_EXPORTED libusb_handle_events_locked(libusb_context *ctx, */ int API_EXPORTED libusb_pollfds_handle_timeouts(libusb_context *ctx) { -#ifdef HAVE_TIMERFD ctx = usbi_get_context(ctx); - return usbi_using_timerfd(ctx); -#else - UNUSED(ctx); - return 0; -#endif + return usbi_using_timer(ctx); } /** \ingroup libusb_poll @@ -2597,10 +2546,9 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx, struct usbi_transfer *itransfer; struct timespec systime; struct timespec next_timeout = { 0, 0 }; - int r; ctx = usbi_get_context(ctx); - if (usbi_using_timerfd(ctx)) + if (usbi_using_timer(ctx)) return 0; usbi_mutex_lock(&ctx->flying_transfers_lock); @@ -2611,11 +2559,11 @@ 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(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) { + for_each_transfer(ctx, itransfer) { if (itransfer->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT)) continue; - /* if we've reached transfers of infinte timeout, we're done looking */ + /* if we've reached transfers of infinite timeout, we're done looking */ if (!TIMESPEC_IS_SET(&itransfer->timeout)) break; @@ -2629,11 +2577,7 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx, return 0; } - r = usbi_clock_gettime(USBI_CLOCK_MONOTONIC, &systime); - if (r < 0) { - usbi_err(ctx, "failed to read monotonic clock, errno=%d", errno); - return 0; - } + usbi_get_monotonic_time(&systime); if (!TIMESPEC_CMP(&systime, &next_timeout, <)) { usbi_dbg("first timeout already expired"); @@ -2672,79 +2616,92 @@ void API_EXPORTED libusb_set_pollfd_notifiers(libusb_context *ctx, libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, void *user_data) { +#if !defined(PLATFORM_WINDOWS) ctx = usbi_get_context(ctx); ctx->fd_added_cb = added_cb; ctx->fd_removed_cb = removed_cb; ctx->fd_cb_user_data = user_data; +#else + usbi_err(ctx, "external polling of libusb's internal event sources " \ + "is not yet supported on Windows"); + UNUSED(added_cb); + UNUSED(removed_cb); + UNUSED(user_data); +#endif } /* * Interrupt the iteration of the event handling thread, so that it picks - * up the fd change. Callers of this function must hold the event_data_lock. + * up the event source change. Callers of this function must hold the event_data_lock. */ -static void usbi_fd_notification(struct libusb_context *ctx) +static void usbi_event_source_notification(struct libusb_context *ctx) { - int pending_events; + unsigned int event_flags; /* 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->event_flags |= USBI_EVENT_POLLFDS_MODIFIED; - if (!pending_events) - usbi_signal_event(ctx); + event_flags = ctx->event_flags; + ctx->event_flags |= USBI_EVENT_EVENT_SOURCES_MODIFIED; + if (!event_flags) + usbi_signal_event(&ctx->event); } -/* Add a file descriptor to the list of file descriptors to be monitored. - * events should be specified as a bitmask of events passed to poll(), e.g. +/* Add an event source to the list of event sources to be monitored. + * poll_events should be specified as a bitmask of events passed to poll(), e.g. * POLLIN and/or POLLOUT. */ -int usbi_add_pollfd(struct libusb_context *ctx, int fd, short events) +int usbi_add_event_source(struct libusb_context *ctx, usbi_os_handle_t os_handle, short poll_events) { - struct usbi_pollfd *ipollfd = malloc(sizeof(*ipollfd)); - if (!ipollfd) + struct usbi_event_source *ievent_source = malloc(sizeof(*ievent_source)); + + if (!ievent_source) return LIBUSB_ERROR_NO_MEM; - usbi_dbg("add fd %d events %d", fd, events); - ipollfd->pollfd.fd = fd; - ipollfd->pollfd.events = events; + usbi_dbg("add " USBI_OS_HANDLE_FORMAT_STRING " events %d", os_handle, poll_events); + ievent_source->data.os_handle = os_handle; + ievent_source->data.poll_events = poll_events; usbi_mutex_lock(&ctx->event_data_lock); - list_add_tail(&ipollfd->list, &ctx->ipollfds); - ctx->pollfds_cnt++; - usbi_fd_notification(ctx); + list_add_tail(&ievent_source->list, &ctx->event_sources); + usbi_event_source_notification(ctx); usbi_mutex_unlock(&ctx->event_data_lock); +#if !defined(PLATFORM_WINDOWS) if (ctx->fd_added_cb) - ctx->fd_added_cb(fd, events, ctx->fd_cb_user_data); + ctx->fd_added_cb(os_handle, poll_events, ctx->fd_cb_user_data); +#endif + return 0; } -/* Remove a file descriptor from the list of file descriptors to be polled. */ -void usbi_remove_pollfd(struct libusb_context *ctx, int fd) +/* Remove an event source from the list of event sources to be monitored. */ +void usbi_remove_event_source(struct libusb_context *ctx, usbi_os_handle_t os_handle) { - struct usbi_pollfd *ipollfd; + struct usbi_event_source *ievent_source; int found = 0; - usbi_dbg("remove fd %d", fd); + usbi_dbg("remove " USBI_OS_HANDLE_FORMAT_STRING, os_handle); usbi_mutex_lock(&ctx->event_data_lock); - list_for_each_entry(ipollfd, &ctx->ipollfds, list, struct usbi_pollfd) - if (ipollfd->pollfd.fd == fd) { + for_each_event_source(ctx, ievent_source) { + if (ievent_source->data.os_handle == os_handle) { found = 1; break; } + } if (!found) { - usbi_dbg("couldn't find fd %d to remove", fd); + usbi_dbg("couldn't find " USBI_OS_HANDLE_FORMAT_STRING " to remove", os_handle); usbi_mutex_unlock(&ctx->event_data_lock); return; } - list_del(&ipollfd->list); - list_add_tail(&ipollfd->list, &ctx->removed_ipollfds); - ctx->pollfds_cnt--; - usbi_fd_notification(ctx); + list_del(&ievent_source->list); + list_add_tail(&ievent_source->list, &ctx->removed_event_sources); + usbi_event_source_notification(ctx); usbi_mutex_unlock(&ctx->event_data_lock); +#if !defined(PLATFORM_WINDOWS) if (ctx->fd_removed_cb) - ctx->fd_removed_cb(fd, ctx->fd_cb_user_data); + ctx->fd_removed_cb(os_handle, ctx->fd_cb_user_data); +#endif } /** \ingroup libusb_poll @@ -2766,29 +2723,36 @@ DEFAULT_VISIBILITY const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds( libusb_context *ctx) { -#ifndef _WIN32 +#if !defined(PLATFORM_WINDOWS) struct libusb_pollfd **ret = NULL; - struct usbi_pollfd *ipollfd; - size_t i = 0; + struct usbi_event_source *ievent_source; + size_t i; + + static_assert(sizeof(struct usbi_event_source_data) == sizeof(struct libusb_pollfd), + "mismatch between usbi_event_source_data and libusb_pollfd sizes"); ctx = usbi_get_context(ctx); usbi_mutex_lock(&ctx->event_data_lock); - ret = calloc(ctx->pollfds_cnt + 1, sizeof(struct libusb_pollfd *)); + i = 0; + for_each_event_source(ctx, ievent_source) + i++; + + ret = calloc(i + 1, sizeof(struct libusb_pollfd *)); if (!ret) goto out; - list_for_each_entry(ipollfd, &ctx->ipollfds, list, struct usbi_pollfd) - ret[i++] = (struct libusb_pollfd *)ipollfd; - ret[ctx->pollfds_cnt] = NULL; + i = 0; + for_each_event_source(ctx, ievent_source) + ret[i++] = (struct libusb_pollfd *)ievent_source; out: usbi_mutex_unlock(&ctx->event_data_lock); return (const struct libusb_pollfd **)ret; #else - usbi_err(ctx, "external polling of libusb's internal descriptors "\ - "is not yet supported on Windows platforms"); + usbi_err(ctx, "external polling of libusb's internal event sources " \ + "is not yet supported on Windows"); return NULL; #endif } @@ -2806,7 +2770,11 @@ out: */ void API_EXPORTED libusb_free_pollfds(const struct libusb_pollfd **pollfds) { +#if !defined(PLATFORM_WINDOWS) free((void *)pollfds); +#else + UNUSED(pollfds); +#endif } /* Backends may call this from handle_events to report disconnection of a @@ -2815,6 +2783,7 @@ void API_EXPORTED libusb_free_pollfds(const struct libusb_pollfd **pollfds) */ void usbi_handle_disconnect(struct libusb_device_handle *dev_handle) { + struct libusb_context *ctx = HANDLE_CTX(dev_handle); struct usbi_transfer *cur; struct usbi_transfer *to_cancel; @@ -2836,8 +2805,8 @@ void usbi_handle_disconnect(struct libusb_device_handle *dev_handle) while (1) { to_cancel = NULL; - 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) + usbi_mutex_lock(&ctx->flying_transfers_lock); + for_each_transfer(ctx, cur) { if (USBI_TRANSFER_TO_LIBUSB_TRANSFER(cur)->dev_handle == dev_handle) { usbi_mutex_lock(&cur->lock); if (cur->state_flags & USBI_TRANSFER_IN_FLIGHT) @@ -2847,7 +2816,8 @@ void usbi_handle_disconnect(struct libusb_device_handle *dev_handle) if (to_cancel) break; } - usbi_mutex_unlock(&HANDLE_CTX(dev_handle)->flying_transfers_lock); + } + usbi_mutex_unlock(&ctx->flying_transfers_lock); if (!to_cancel) break; diff --git a/libusb/libusb-1.0.def b/libusb/libusb-1.0.def index 2e78b0a..700a8bc 100644 --- a/libusb/libusb-1.0.def +++ b/libusb/libusb-1.0.def @@ -178,3 +178,5 @@ EXPORTS libusb_unref_device@4 = libusb_unref_device libusb_wait_for_event libusb_wait_for_event@8 = libusb_wait_for_event + libusb_wrap_sys_device + libusb_wrap_sys_device@12 = libusb_wrap_sys_device diff --git a/libusb/libusb-1.0.rc b/libusb/libusb-1.0.rc index 9cdecd0..bcb10fa 100644 --- a/libusb/libusb-1.0.rc +++ b/libusb/libusb-1.0.rc @@ -1,5 +1,5 @@ /* - * For Windows: input this file to the Resoure Compiler to produce a binary + * For Windows: input this file to the Resource Compiler to produce a binary * .res file. This is then embedded in the resultant library (like any other * compilation object). * The information can then be queried using standard APIs and can also be diff --git a/libusb/libusb.h b/libusb/libusb.h index da6b1e5..1308571 100644 --- a/libusb/libusb.h +++ b/libusb/libusb.h @@ -231,6 +231,9 @@ enum libusb_class_code { /** Wireless class */ LIBUSB_CLASS_WIRELESS = 0xe0, + /** Miscellaneous class */ + LIBUSB_CLASS_MISCELLANEOUS = 0xef, + /** Application class */ LIBUSB_CLASS_APPLICATION = 0xfe, @@ -1254,7 +1257,16 @@ struct libusb_transfer { * fails, or is cancelled. */ libusb_transfer_cb_fn callback; - /** User context data to pass to the callback function. */ + /** User context data. Useful for associating specific data to a transfer + * that can be accessed from within the callback function. + * + * This field may be set manually or is taken as the `user_data` parameter + * of the following functions: + * - libusb_fill_bulk_transfer() + * - libusb_fill_bulk_stream_transfer() + * - libusb_fill_control_transfer() + * - libusb_fill_interrupt_transfer() + * - libusb_fill_iso_transfer() */ void *user_data; /** Data buffer */ @@ -1316,10 +1328,10 @@ enum libusb_log_level { * \see libusb_set_log_cb() */ enum libusb_log_cb_mode { - /** Callback function handling all log mesages. */ + /** Callback function handling all log messages. */ LIBUSB_LOG_CB_GLOBAL = (1 << 0), - /** Callback function handling context related log mesages. */ + /** Callback function handling context related log messages. */ LIBUSB_LOG_CB_CONTEXT = (1 << 1) }; @@ -1912,7 +1924,7 @@ void LIBUSB_CALL libusb_set_pollfd_notifiers(libusb_context *ctx, * Callbacks handles are generated by libusb_hotplug_register_callback() * and can be used to deregister callbacks. Callback handles are unique * per libusb_context and it is safe to call libusb_hotplug_deregister_callback() - * on an already deregisted callback. + * on an already deregistered callback. * * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 * @@ -2078,7 +2090,18 @@ enum libusb_option { * * Only valid on Windows. */ - LIBUSB_OPTION_USE_USBDK = 1 + LIBUSB_OPTION_USE_USBDK = 1, + + /** Set libusb has weak authority. With this option, libusb will skip + * scan devices in libusb_init. + * + * This option should be set before calling libusb_init(), otherwise + * libusb_init will failed. Normally libusb_wrap_sys_device need set + * this option. + * + * Only valid on Linux-based operating system, such as Android. + */ + LIBUSB_OPTION_WEAK_AUTHORITY = 2 }; int LIBUSB_CALL libusb_set_option(libusb_context *ctx, enum libusb_option option, ...); diff --git a/libusb/libusbi.h b/libusb/libusbi.h index 3c5add6..491114b 100644 --- a/libusb/libusbi.h +++ b/libusb/libusbi.h @@ -3,7 +3,7 @@ * Copyright © 2007-2009 Daniel Drake <dsd@gentoo.org> * Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com> * Copyright © 2019 Nathan Hjelm <hjelmn@cs.umm.edu> - * Copyright © 2019 Google LLC. All rights reserved. + * Copyright © 2019-2020 Google LLC. All rights reserved. * Copyright © 2020 Chris Dickens <christopher.a.dickens@gmail.com> * * This library is free software; you can redistribute it and/or @@ -27,6 +27,7 @@ #include <config.h> #include <assert.h> +#include <inttypes.h> #include <stdarg.h> #include <stddef.h> #include <stdlib.h> @@ -43,6 +44,14 @@ #define static_assert(cond, msg) _Static_assert(cond, msg) #endif +#ifdef NDEBUG +#define ASSERT_EQ(expression, value) (void)expression +#define ASSERT_NE(expression, value) (void)expression +#else +#define ASSERT_EQ(expression, value) assert(expression == value) +#define ASSERT_NE(expression, value) assert(expression != value) +#endif + #define container_of(ptr, type, member) \ ((type *)((uintptr_t)(ptr) - (uintptr_t)offsetof(type, member))) @@ -74,17 +83,12 @@ #define PTR_ALIGN(v) \ (((v) + (sizeof(void *) - 1)) & ~(sizeof(void *) - 1)) -/* Internal abstraction for poll */ -#if defined(POLL_POSIX) -#include "os/poll_posix.h" -#elif defined(POLL_WINDOWS) -#include "os/poll_windows.h" -#endif - -/* Internal abstraction for thread synchronization */ -#if defined(THREADS_POSIX) +/* Internal abstractions for event handling and thread synchronization */ +#if defined(PLATFORM_POSIX) +#include "os/events_posix.h" #include "os/threads_posix.h" -#elif defined(THREADS_WINDOWS) +#elif defined(PLATFORM_WINDOWS) +#include "os/events_windows.h" #include "os/threads_windows.h" #endif @@ -97,16 +101,6 @@ */ #define API_EXPORTED LIBUSB_CALL DEFAULT_VISIBILITY -/* Macro to decorate printf-like functions, in order to get - * compiler warnings about format string mistakes. - */ -#ifndef _MSC_VER -#define USBI_PRINTFLIKE(formatarg, firstvararg) \ - __attribute__ ((__format__ (__printf__, formatarg, firstvararg))) -#else -#define USBI_PRINTFLIKE(formatarg, firstvararg) -#endif - #ifdef __cplusplus extern "C" { #endif @@ -139,6 +133,9 @@ struct list_head { #define list_first_entry(ptr, type, member) \ list_entry((ptr)->next, type, member) +#define list_next_entry(ptr, type, member) \ + list_entry((ptr)->member.next, type, member) + /* Get each entry from a list * pos - A structure pointer has a "member" element * head - list head @@ -146,15 +143,24 @@ 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); \ + for (pos = list_first_entry(head, type, member); \ &pos->member != (head); \ - pos = list_entry(pos->member.next, type, member)) + pos = list_next_entry(pos, 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); \ + for (pos = list_first_entry(head, type, member), \ + n = list_next_entry(pos, type, member); \ &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, type, member)) + pos = n, n = list_next_entry(n, type, member)) + +/* Helper macros to iterate over a list. The structure pointed + * to by "pos" must have a list_head member named "list". + */ +#define for_each_helper(pos, head, type) \ + list_for_each_entry(pos, head, list, type) + +#define for_each_safe_helper(pos, n, head, type) \ + list_for_each_entry_safe(pos, n, head, list, type) #define list_empty(entry) ((entry)->next == (entry)) @@ -191,8 +197,10 @@ static inline void list_del(struct list_head *entry) static inline void list_cut(struct list_head *list, struct list_head *head) { - if (list_empty(head)) + if (list_empty(head)) { + list_init(list); return; + } list->next = head->next; list->next->prev = list; @@ -202,6 +210,14 @@ static inline void list_cut(struct list_head *list, struct list_head *head) list_init(head); } +static inline void list_splice_front(struct list_head *list, struct list_head *head) +{ + list->next->prev = head; + list->prev->next = head->next; + head->next->prev = list->prev; + head->next = list->next; +} + static inline void *usbi_reallocf(void *ptr, size_t size) { void *ret = realloc(ptr, size); @@ -211,6 +227,18 @@ static inline void *usbi_reallocf(void *ptr, size_t size) return ret; } +#if !defined(USEC_PER_SEC) +#define USEC_PER_SEC 1000000L +#endif + +#if !defined(NSEC_PER_SEC) +#define NSEC_PER_SEC 1000000000L +#endif + +#define TIMEVAL_IS_VALID(tv) \ + ((tv)->tv_sec >= 0 && \ + (tv)->tv_usec >= 0 && (tv)->tv_usec < USEC_PER_SEC) + #define TIMESPEC_IS_SET(ts) ((ts)->tv_sec || (ts)->tv_nsec) #define TIMESPEC_CLEAR(ts) (ts)->tv_sec = (ts)->tv_nsec = 0 #define TIMESPEC_CMP(a, b, CMP) \ @@ -223,11 +251,11 @@ static inline void *usbi_reallocf(void *ptr, size_t size) (result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \ if ((result)->tv_nsec < 0L) { \ --(result)->tv_sec; \ - (result)->tv_nsec += 1000000000L; \ + (result)->tv_nsec += NSEC_PER_SEC; \ } \ } while (0) -#if defined(_WIN32) +#if defined(PLATFORM_WINDOWS) #define TIMEVAL_TV_SEC_TYPE long #else #define TIMEVAL_TV_SEC_TYPE time_t @@ -249,15 +277,12 @@ static inline void *usbi_reallocf(void *ptr, size_t size) #define snprintf usbi_snprintf #define vsnprintf usbi_vsnprintf int usbi_snprintf(char *dst, size_t size, const char *format, ...); -int usbi_vsnprintf(char *dst, size_t size, const char *format, va_list ap); +int usbi_vsnprintf(char *dst, size_t size, const char *format, va_list args); #define LIBUSB_PRINTF_WIN32 #endif /* defined(_MSC_VER) && (_MSC_VER < 1900) */ void usbi_log(struct libusb_context *ctx, enum libusb_log_level level, - const char *function, const char *format, ...) USBI_PRINTFLIKE(4, 5); - -void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, - const char *function, const char *format, va_list args) USBI_PRINTFLIKE(4, 0); + const char *function, const char *format, ...) PRINTF_FORMAT(4, 5); #define _usbi_log(ctx, level, ...) usbi_log(ctx, level, __func__, __VA_ARGS__) @@ -293,8 +318,14 @@ struct libusb_context { libusb_log_cb log_handler; #endif - /* internal event pipe, used for signalling occurrence of an internal event. */ - int event_pipe[2]; + /* used for signalling occurrence of an internal event. */ + usbi_event_t event; + +#ifdef HAVE_OS_TIMER + /* used for timeout handling, if supported by OS. + * this timer is maintained to trigger on the next pending timeout */ + usbi_timer_t timer; +#endif struct list_head usb_devs; usbi_mutex_t usb_devs_lock; @@ -318,10 +349,12 @@ struct libusb_context { * take this lock first */ usbi_mutex_t flying_transfers_lock; +#if !defined(PLATFORM_WINDOWS) /* user callbacks for pollfd changes */ libusb_pollfd_added_cb fd_added_cb; libusb_pollfd_removed_cb fd_removed_cb; void *fd_cb_user_data; +#endif /* ensures that only one thread is handling events at any one time */ usbi_mutex_t events_lock; @@ -349,14 +382,17 @@ struct libusb_context { * 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. Protected by event_data_lock. */ - struct list_head ipollfds; - /* list of pollfds that have been removed. keeps track of pollfd changes - * between the poll call and */ - struct list_head removed_ipollfds; - struct pollfd *pollfds; - usbi_nfds_t pollfds_cnt; + /* A list of currently active event sources. Protected by event_data_lock. */ + struct list_head event_sources; + + /* A list of event sources that have been removed since the last time + * event sources were waited on. Protected by event_data_lock. */ + struct list_head removed_event_sources; + + /* A pointer and count to platform-specific data used for monitoring event + * sources. Only accessed during event handling. */ + void *event_data; + unsigned int event_data_cnt; /* A list of pending hotplug messages. Protected by event_data_lock. */ struct list_head hotplug_msgs; @@ -364,31 +400,37 @@ struct libusb_context { /* A list of pending completed transfers. Protected by event_data_lock. */ struct list_head completed_transfers; -#ifdef HAVE_TIMERFD - /* used for timeout handling, if supported by OS. - * this timerfd is maintained to trigger on the next pending timeout */ - int timerfd; -#endif - struct list_head list; }; extern struct libusb_context *usbi_default_context; +extern struct list_head active_contexts_list; +extern usbi_mutex_static_t active_contexts_lock; + static inline struct libusb_context *usbi_get_context(struct libusb_context *ctx) { return ctx ? ctx : usbi_default_context; } enum usbi_event_flags { - /* The list of pollfds has been modified */ - USBI_EVENT_POLLFDS_MODIFIED = 1U << 0, + /* The list of event sources has been modified */ + USBI_EVENT_EVENT_SOURCES_MODIFIED = 1U << 0, /* The user has interrupted the event handler */ USBI_EVENT_USER_INTERRUPT = 1U << 1, /* A hotplug callback deregistration is pending */ USBI_EVENT_HOTPLUG_CB_DEREGISTERED = 1U << 2, + + /* One or more hotplug messages are pending */ + USBI_EVENT_HOTPLUG_MSG_PENDING = 1U << 3, + + /* One or more completed transfers are pending */ + USBI_EVENT_TRANSFER_COMPLETED = 1U << 4, + + /* A device is in the process of being closed */ + USBI_EVENT_DEVICE_CLOSE = 1U << 5, }; /* Macros for managing event handling state */ @@ -407,25 +449,6 @@ static inline void usbi_end_event_handling(struct libusb_context *ctx) usbi_tls_key_set(ctx->event_handling_key, NULL); } -/* Update the following function if new event sources are added */ -static inline int usbi_pending_events(struct libusb_context *ctx) -{ - return ctx->event_flags || - ctx->device_close || - !list_empty(&ctx->hotplug_msgs) || - !list_empty(&ctx->completed_transfers); -} - -static inline int usbi_using_timerfd(struct libusb_context *ctx) -{ -#ifdef HAVE_TIMERFD - return ctx->timerfd >= 0; -#else - UNUSED(ctx); - return 0; -#endif -} - struct libusb_device { /* lock protects refcnt, everything else is finalized at initialization * time */ @@ -469,22 +492,26 @@ static inline void usbi_localize_device_descriptor(struct libusb_device_descript } #ifdef HAVE_CLOCK_GETTIME -#define USBI_CLOCK_REALTIME CLOCK_REALTIME -#define USBI_CLOCK_MONOTONIC CLOCK_MONOTONIC -#define usbi_clock_gettime clock_gettime +static inline void usbi_get_monotonic_time(struct timespec *tp) +{ + ASSERT_EQ(clock_gettime(CLOCK_MONOTONIC, tp), 0); +} +static inline void usbi_get_real_time(struct timespec *tp) +{ + ASSERT_EQ(clock_gettime(CLOCK_REALTIME, tp), 0); +} #else /* If the platform doesn't provide the clock_gettime() function, the backend - * must provide its own implementation. Two clocks must be supported by the - * backend: USBI_CLOCK_REALTIME, and USBI_CLOCK_MONOTONIC. + * must provide its own clock implementations. Two clock functions are + * required: * - * Description of clocks: - * USBI_CLOCK_REALTIME: clock returns time since system epoch. - * USBI_CLOCK_MONOTONIC: clock returns time since unspecified start time - * (usually boot). + * usbi_get_monotonic_time(): returns the time since an unspecified starting + * point (usually boot) that is monotonically + * increasing. + * usbi_get_real_time(): returns the time since system epoch. */ -#define USBI_CLOCK_REALTIME 0 -#define USBI_CLOCK_MONOTONIC 1 -int usbi_clock_gettime(int clk_id, struct timespec *tp); +void usbi_get_monotonic_time(struct timespec *tp); +void usbi_get_real_time(struct timespec *tp); #endif /* in-memory transfer layout: @@ -605,7 +632,7 @@ struct usbi_interface_descriptor { struct usbi_string_descriptor { uint8_t bLength; uint8_t bDescriptorType; - uint16_t wData[]; + uint16_t wData[ZERO_SIZED_ARRAY]; } LIBUSB_PACKED; struct usbi_bos_descriptor { @@ -619,6 +646,24 @@ struct usbi_bos_descriptor { #pragma pack(pop) #endif +union usbi_config_desc_buf { + struct usbi_configuration_descriptor desc; + uint8_t buf[LIBUSB_DT_CONFIG_SIZE]; + uint16_t align; /* Force 2-byte alignment */ +}; + +union usbi_string_desc_buf { + struct usbi_string_descriptor desc; + uint8_t buf[255]; /* Some devices choke on size > 255 */ + uint16_t align; /* Force 2-byte alignment */ +}; + +union usbi_bos_desc_buf { + struct usbi_bos_descriptor desc; + uint8_t buf[LIBUSB_DT_BOS_SIZE]; + uint16_t align; /* Force 2-byte alignment */ +}; + /* shared data and functions */ int usbi_io_init(struct libusb_context *ctx); @@ -639,18 +684,60 @@ void usbi_signal_transfer_completion(struct usbi_transfer *itransfer); void usbi_connect_device(struct libusb_device *dev); void usbi_disconnect_device(struct libusb_device *dev); -int usbi_signal_event(struct libusb_context *ctx); -int usbi_clear_event(struct libusb_context *ctx); +struct usbi_event_source { + struct usbi_event_source_data { + usbi_os_handle_t os_handle; + short poll_events; + } data; + struct list_head list; +}; + +int usbi_add_event_source(struct libusb_context *ctx, usbi_os_handle_t os_handle, + short poll_events); +void usbi_remove_event_source(struct libusb_context *ctx, usbi_os_handle_t os_handle); -struct usbi_pollfd { - /* must come first */ - struct libusb_pollfd pollfd; +/* OS event abstraction */ - struct list_head list; +int usbi_create_event(usbi_event_t *event); +void usbi_destroy_event(usbi_event_t *event); +void usbi_signal_event(usbi_event_t *event); +void usbi_clear_event(usbi_event_t *event); + +#ifdef HAVE_OS_TIMER +int usbi_create_timer(usbi_timer_t *timer); +void usbi_destroy_timer(usbi_timer_t *timer); +int usbi_arm_timer(usbi_timer_t *timer, const struct timespec *timeout); +int usbi_disarm_timer(usbi_timer_t *timer); +#endif + +static inline int usbi_using_timer(struct libusb_context *ctx) +{ +#ifdef HAVE_OS_TIMER + return usbi_timer_valid(&ctx->timer); +#else + UNUSED(ctx); + return 0; +#endif +} + +struct usbi_reported_events { + union { + struct { + unsigned int event_triggered:1; +#ifdef HAVE_OS_TIMER + unsigned int timer_triggered:1; +#endif + }; + unsigned int event_bits; + }; + void *event_data; + unsigned int event_data_count; + unsigned int num_ready; }; -int usbi_add_pollfd(struct libusb_context *ctx, int fd, short events); -void usbi_remove_pollfd(struct libusb_context *ctx, int fd); +int usbi_alloc_event_data(struct libusb_context *ctx); +int usbi_wait_for_events(struct libusb_context *ctx, + struct usbi_reported_events *reported_events, int timeout_ms); /* accessor functions for structure private data */ @@ -807,7 +894,7 @@ struct usbi_os_backend { * and other operations so that those operations can happen (hopefully) * without hiccup. This is also a good place to inform libusb that it * should monitor certain file descriptors related to this device - - * see the usbi_add_pollfd() function. + * see the usbi_add_event_source() function. * * Your backend should also initialize the device structure * (dev_handle->dev), which is NULL at the beginning of the call. @@ -836,7 +923,7 @@ struct usbi_os_backend { * and other operations so that those operations can happen (hopefully) * without hiccup. This is also a good place to inform libusb that it * should monitor certain file descriptors related to this device - - * see the usbi_add_pollfd() function. + * see the usbi_add_event_source() function. * * This function should not generate any bus I/O and should not block. * @@ -857,9 +944,9 @@ struct usbi_os_backend { /* Close a device such that the handle cannot be used again. Your backend * should destroy any resources that were allocated in the open path. - * This may also be a good place to call usbi_remove_pollfd() to inform - * libusb of any file descriptors associated with this device that should - * no longer be monitored. + * This may also be a good place to call usbi_remove_event_source() to + * inform libusb of any event sources associated with this device that + * should no longer be monitored. * * This function is called when the user closes a device handle. */ @@ -1034,7 +1121,7 @@ struct usbi_os_backend { * completes, assuming that the device descriptors did not change during * reset and all previous interface state can be restored. * - * If something changes, or you cannot easily locate/verify the resetted + * If something changes, or you cannot easily locate/verify the reset * device, return LIBUSB_ERROR_NOT_FOUND. This prompts the application * to close the old handle and re-enumerate the device. * @@ -1154,21 +1241,22 @@ struct usbi_os_backend { */ void (*clear_transfer_priv)(struct usbi_transfer *itransfer); - /* Handle any pending events on file descriptors. Optional. + /* Handle any pending events on event sources. Optional. * - * Provide this function when file descriptors directly indicate device - * or transfer activity. If your backend does not have such file descriptors, + * Provide this function when event sources directly indicate device + * or transfer activity. If your backend does not have such event sources, * implement the handle_transfer_completion function below. * * This involves monitoring any active transfers and processing their * completion or cancellation. * - * The function is passed an array of pollfd structures (size nfds) - * as a result of the poll() system call. The num_ready parameter - * indicates the number of file descriptors that have reported events - * (i.e. the poll() return value). This should be enough information - * for you to determine which actions need to be taken on the currently - * active transfers. + * The function is passed a pointer that represents platform-specific + * data for monitoring event sources (size count). This data is to be + * (re)allocated as necessary when event sources are modified. + * The num_ready parameter indicates the number of event sources that + * have reported events. This should be enough information for you to + * determine which actions need to be taken on the currently active + * transfers. * * For any cancelled transfers, call usbi_handle_transfer_cancellation(). * For completed transfers, call usbi_handle_transfer_completion(). @@ -1187,13 +1275,13 @@ struct usbi_os_backend { * Return 0 on success, or a LIBUSB_ERROR code on failure. */ int (*handle_events)(struct libusb_context *ctx, - struct pollfd *fds, usbi_nfds_t nfds, int num_ready); + void *event_data, unsigned int count, unsigned int num_ready); /* Handle transfer completion. Optional. * - * Provide this function when there are no file descriptors available - * that directly indicate device or transfer activity. If your backend does - * have such file descriptors, implement the handle_events function above. + * Provide this function when there are no event sources available that + * directly indicate device or transfer activity. If your backend does + * have such event sources, implement the handle_events function above. * * Your backend must tell the library when a transfer has completed by * calling usbi_signal_transfer_completion(). You should store any private @@ -1241,8 +1329,41 @@ struct usbi_os_backend { extern const struct usbi_os_backend usbi_backend; -extern struct list_head active_contexts_list; -extern usbi_mutex_static_t active_contexts_lock; +#define for_each_context(c) \ + for_each_helper(c, &active_contexts_list, struct libusb_context) + +#define for_each_device(ctx, d) \ + for_each_helper(d, &(ctx)->usb_devs, struct libusb_device) + +#define for_each_device_safe(ctx, d, n) \ + for_each_safe_helper(d, n, &(ctx)->usb_devs, struct libusb_device) + +#define for_each_open_device(ctx, h) \ + for_each_helper(h, &(ctx)->open_devs, struct libusb_device_handle) + +#define __for_each_transfer(list, t) \ + for_each_helper(t, (list), struct usbi_transfer) + +#define for_each_transfer(ctx, t) \ + __for_each_transfer(&(ctx)->flying_transfers, t) + +#define __for_each_transfer_safe(list, t, n) \ + for_each_safe_helper(t, n, (list), struct usbi_transfer) + +#define for_each_transfer_safe(ctx, t, n) \ + __for_each_transfer_safe(&(ctx)->flying_transfers, t, n) + +#define __for_each_completed_transfer_safe(list, t, n) \ + list_for_each_entry_safe(t, n, (list), completed_list, struct usbi_transfer) + +#define for_each_event_source(ctx, e) \ + for_each_helper(e, &(ctx)->event_sources, struct usbi_event_source) + +#define for_each_removed_event_source(ctx, e) \ + for_each_helper(e, &(ctx)->removed_event_sources, struct usbi_event_source) + +#define for_each_removed_event_source_safe(ctx, e, n) \ + for_each_safe_helper(e, n, &(ctx)->removed_event_sources, struct usbi_event_source) #ifdef __cplusplus } diff --git a/libusb/os/darwin_iousbhost.m b/libusb/os/darwin_iousbhost.m new file mode 100644 index 0000000..d4e1226 --- /dev/null +++ b/libusb/os/darwin_iousbhost.m @@ -0,0 +1,268 @@ +/* -*- Mode: C; indent-tabs-mode:nil -*- */ +/* + * darwin backend for libusb 1.0 + * Copyright © 2008-2020 Nathan Hjelm <hjelmn@cs.unm.edu> + * Copyright © 2019-2020 Google LLC. All rights reserved. + * + * 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 + */ + +/* new mac api */ +#import <Foundation/Foundation.h> +#import <IOUSBHost/IOUSBHost.h> +#import <IOKit/IOMessage.h> + +#import "darwin_usb.h" + + +NS_ASSUME_NONNULL_BEGIN + +/// Identifies a USB device by its vendor/product pair. +@interface DarwinUsbDeviceIdentifier : NSObject +@property(nonatomic, nonnull, strong) NSNumber *vendorID; +@property(nonatomic, nonnull, strong) NSNumber *productID; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithVendorID:(NSNumber *)vendorID productID:(NSNumber *)productID; +@end + + +/// Acquires exclusive access to the the device specified by the device ID. +@interface DarwinUsbDeviceExclusiveAccessAssertion : NSObject +@property (nonatomic, nonnull, strong) DarwinUsbDeviceIdentifier *deviceID; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithDeviceID:(DarwinUsbDeviceIdentifier *)deviceID; +@end + + +/// Parses the command line to extract all specified USB devices. +@interface DarwinUSBDeviceCommandLineProcessor : NSObject + +/// Fetch the array of devices that were specified at the command line. +/// +/// Multiple devices can be specified at the command line. For each such device, specify the `-device` switch followed by the +/// device's specification prefixed by `usb-host` and including the required vendor and product ids along with any other optional +/// properties. Properties are comma delimitted and specified as key/value pair assignments with the `=` delimitter. For example: +/// `-device usb-host,bus=ehci.0,vendorid=0x0b05,productid=0x17cb` +/// +/// - Returns: The array of scanned USB devices. +- (NSArray<DarwinUsbDeviceIdentifier *> *)fetchDevices; +@end + +NS_ASSUME_NONNULL_END + + +/// Array of assertions for exclusive USB access. +static NSMutableArray<DarwinUsbDeviceExclusiveAccessAssertion *> *usbDeviceExlusiveAccessAssertions; + +/// Acquire exclusive USB access for the desired devices. +void DarwinGetExclusiveAccessForDevices(void) { + // Only need to execute this once. + static BOOL hasRun = NO; + if (hasRun) { return; } + hasRun = YES; + + usbDeviceExlusiveAccessAssertions = [[NSMutableArray alloc] init]; + + // Parse the command line to fetch every device. + DarwinUSBDeviceCommandLineProcessor *processor = [[DarwinUSBDeviceCommandLineProcessor alloc] init]; + NSArray<DarwinUsbDeviceIdentifier *> *deviceIDs = [processor fetchDevices]; + NSLog(@"Command line USB devices: %@", deviceIDs); + + // For device found, acquire an assertion for exclusive access. + for (DarwinUsbDeviceIdentifier *deviceID in deviceIDs) { + DarwinUsbDeviceExclusiveAccessAssertion *assertion = + [[DarwinUsbDeviceExclusiveAccessAssertion alloc] initWithDeviceID:deviceID]; + if (assertion != nil) { + [usbDeviceExlusiveAccessAssertions addObject:assertion]; + } + } +} + + +@implementation DarwinUsbDeviceExclusiveAccessAssertion { + dispatch_queue_t _queue; + io_service_t _service; + IOUSBHostDevice *_device; +} + +- (instancetype)initWithDeviceID:(DarwinUsbDeviceIdentifier *)deviceID { + self = [super init]; + if (self) { + NSLog(@"Acquiring USB Exclusive access for device: <%@>", deviceID); + _queue = dispatch_queue_create("usb-exclusive-access", DISPATCH_QUEUE_SERIAL); + + _deviceID = deviceID; + + CFMutableDictionaryRef query = [IOUSBHostDevice + createMatchingDictionaryWithVendorID:deviceID.vendorID + productID:deviceID.productID + bcdDevice:nil + deviceClass:nil + deviceSubclass:nil + deviceProtocol:nil + speed:nil + productIDArray:nil]; + + _service = IOServiceGetMatchingService(kIOMasterPortDefault, query); + + if (_service == 0) { + NSLog(@"No service match found for product/vendor query."); + return nil; + } + + kern_return_t authorized = IOServiceAuthorize(_service, 0); + if (authorized != kIOReturnSuccess) { + NSLog(@"Service authorization failed with error with return code: %d", authorized); + } + + NSError* error = nil; + + _device = [[IOUSBHostDevice alloc] initWithIOService:_service + options:IOUSBHostObjectInitOptionsDeviceCapture + queue:_queue + error:&error + interestHandler:nil + ]; + + if (error != nil) { + NSLog(@"Error creating device: %@", [error localizedDescription]); + } + } + + return self; +} + +- (void)dealloc { + NSLog(@"dealloc DarwinUsbDeviceExclusiveAccessAssertion..."); + NSError *error = nil; + BOOL success = [_device resetWithError:&error]; + NSLog(@"Reset device: %@ with result: %u", _deviceID, success); + IOObjectRelease(_service); +} + +@end + + +/// As the command line is parsed, the mode tracks the state. +typedef enum DarwinCommandLineUsbDeviceParseMode { + DarwinCommandLineUsbDeviceParseModeScanning, // Scanning for the next device. + DarwinCommandLineUsbDeviceParseModeProcessingDevice // Processing the current device. +} DarwinCommandLineUsbDeviceParseMode; + + +@implementation DarwinUSBDeviceCommandLineProcessor { + DarwinCommandLineUsbDeviceParseMode mode; +} + +- (NSArray<DarwinUsbDeviceIdentifier *> *)fetchDevices { + mode = DarwinCommandLineUsbDeviceParseModeScanning; + NSMutableArray<DarwinUsbDeviceIdentifier *> *deviceIdentifiers = [[NSMutableArray alloc] init]; + + NSArray<NSString *> *arguments = [[NSProcessInfo processInfo] arguments]; + for (NSString *argument in arguments) { + switch(mode) { + case DarwinCommandLineUsbDeviceParseModeProcessingDevice: + { + DarwinUsbDeviceIdentifier *deviceIdentifier = [self processDeviceArgument:argument]; + if (deviceIdentifier != nil) { + [deviceIdentifiers addObject:deviceIdentifier]; + } + } + break; + case DarwinCommandLineUsbDeviceParseModeScanning: + [self processSearchingArgument:argument]; + break; + } + } + + return [deviceIdentifiers copy]; +} + +- (void)processSearchingArgument:(NSString *)argument { + if ([argument isEqualToString:@"-device"]) { + mode = DarwinCommandLineUsbDeviceParseModeProcessingDevice; + } +} + +- (DarwinUsbDeviceIdentifier *)processDeviceArgument:(NSString *)deviceArgument { + // Continue searching for more devices after processing this argument. + mode = DarwinCommandLineUsbDeviceParseModeScanning; + + NSString * _Nonnull const vendorIDKey = @"vendorid"; + NSString * _Nonnull const productIDKey = @"productid"; + NSString *vendorIDText = nil; + NSString *productIDText = nil; + if ([deviceArgument hasPrefix:@"usb-host"]) { + NSArray<NSString *> *deviceComponents = [deviceArgument componentsSeparatedByString:@","]; + NSMutableDictionary<NSString *, NSString *> *assignments = [[NSMutableDictionary alloc] init]; + for (NSString *deviceComponent in deviceComponents) { + NSArray<NSString *> *pair = [deviceComponent componentsSeparatedByString:@"="]; + if ([pair count] == 2) { + NSString *key = pair[0]; + NSString *value = pair[1]; + assignments[key] = value; + } + } + vendorIDText = assignments[vendorIDKey]; + productIDText = assignments[productIDKey]; + + BOOL success = NO; + unsigned int vendorID = 0; + NSScanner *vendorScanner = [[NSScanner alloc] initWithString:vendorIDText]; + success = [vendorScanner scanHexInt:&vendorID]; + if (!success) return nil; + + unsigned int productID = 0; + NSScanner *productScanner = [[NSScanner alloc] initWithString:productIDText]; + success = [productScanner scanHexInt:&productID]; + if (!success) return nil; + + if (vendorIDText != nil && productIDText != nil) { + NSLog(@"vendorID: %@ (%u), productID: %@ (%u)", vendorIDText, vendorID, productIDText, productID); + } + + DarwinUsbDeviceIdentifier *device = [[DarwinUsbDeviceIdentifier alloc] initWithVendorID:[NSNumber numberWithUnsignedInt:vendorID] productID:[NSNumber numberWithUnsignedInt:productID]]; + + return device; + } + + return nil; +} + +- (void)parseDevice:(NSString *)device { + +} + +@end + + +@implementation DarwinUsbDeviceIdentifier + +- (instancetype)initWithVendorID:(NSNumber *)vendorID productID:(NSNumber *)productID { + self = [super init]; + if (self) { + self.vendorID = vendorID; + self.productID = productID; + } + return self; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"vendorID: 0x%x, productID: 0x%x", [_vendorID unsignedIntValue], [_productID unsignedIntValue]]; +} + +@end diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c index a64d67d..402e8c4 100644 --- a/libusb/os/darwin_usb.c +++ b/libusb/os/darwin_usb.c @@ -23,7 +23,6 @@ #include <assert.h> #include <time.h> #include <ctype.h> -#include <errno.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> @@ -337,7 +336,7 @@ static void darwin_devices_attached (void *ptr, io_iterator_t add_devices) { } /* add this device to each active context's device list */ - list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) { + for_each_context(ctx) { process_new_device (ctx, cached_device, old_session_id); } @@ -381,7 +380,7 @@ static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) { if (old_device->in_reenumerate) { /* device is re-enumerating. do not dereference the device at this time. libusb_reset_device() * will deref if needed. */ - usbi_dbg ("detected device detatched due to re-enumeration"); + usbi_dbg ("detected device detached due to re-enumeration"); /* the device object is no longer usable so go ahead and release it */ if (old_device->device) { @@ -403,7 +402,7 @@ static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) { continue; } - list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) { + for_each_context(ctx) { usbi_dbg ("notifying context %p of device disconnect", ctx); dev = usbi_get_device_by_session_id(ctx, (unsigned long) session); @@ -582,6 +581,8 @@ static int darwin_init(struct libusb_context *ctx) { do { if (first_init) { + DarwinGetExclusiveAccessForDevices(); + assert (NULL == darwin_cached_devices.next); list_init (&darwin_cached_devices); @@ -1201,6 +1202,8 @@ static int darwin_open (struct libusb_device_handle *dev_handle) { struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); IOReturn kresult; + usbi_dbg("<darwin_open> vendor: 0x%x, product: 0x%x", dpriv->dev_descriptor.idVendor, dpriv->dev_descriptor.idProduct); + if (0 == dpriv->open_count) { /* try to open the device */ kresult = (*(dpriv->device))->USBDeviceOpenSeize (dpriv->device); @@ -2148,31 +2151,34 @@ static enum libusb_transfer_status darwin_transfer_status (struct usbi_transfer static int darwin_handle_transfer_completion (struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct darwin_transfer_priv *tpriv = usbi_get_transfer_priv(itransfer); - bool isIsoc = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type; - bool isBulk = LIBUSB_TRANSFER_TYPE_BULK == transfer->type; - bool isControl = LIBUSB_TRANSFER_TYPE_CONTROL == transfer->type; - bool isInterrupt = LIBUSB_TRANSFER_TYPE_INTERRUPT == transfer->type; - int i; + const unsigned char max_transfer_type = LIBUSB_TRANSFER_TYPE_BULK_STREAM; + const char *transfer_types[max_transfer_type + 1] = {"control", "isoc", "bulk", "interrupt", "bulk-stream"}; + bool is_isoc = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type; - if (!isIsoc && !isBulk && !isControl && !isInterrupt) { + if (transfer->type > max_transfer_type) { usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); return LIBUSB_ERROR_INVALID_PARAM; } - usbi_dbg ("handling %s completion with kernel status %d", - isControl ? "control" : isBulk ? "bulk" : isIsoc ? "isoc" : "interrupt", tpriv->result); + if (NULL == tpriv) { + usbi_err (TRANSFER_CTX(transfer), "malformed request is missing transfer priv"); + return LIBUSB_ERROR_INVALID_PARAM; + } + + usbi_dbg ("handling transfer completion type %s with kernel status %d", transfer_types[transfer->type], tpriv->result); if (kIOReturnSuccess == tpriv->result || kIOReturnUnderrun == tpriv->result) { - if (isIsoc && tpriv->isoc_framelist) { + if (is_isoc && tpriv->isoc_framelist) { /* copy isochronous results back */ - for (i = 0; i < transfer->num_iso_packets ; i++) { + for (int i = 0; i < transfer->num_iso_packets ; i++) { struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i]; lib_desc->status = darwin_transfer_status (itransfer, tpriv->isoc_framelist[i].frStatus); lib_desc->actual_length = tpriv->isoc_framelist[i].frActCount; } - } else if (!isIsoc) + } else if (!is_isoc) { itransfer->transferred += tpriv->size; + } } /* it is ok to handle cancelled transfers without calling usbi_handle_transfer_cancellation (we catch timeout transfers) */ @@ -2180,30 +2186,24 @@ static int darwin_handle_transfer_completion (struct usbi_transfer *itransfer) { } #if !defined(HAVE_CLOCK_GETTIME) -int usbi_clock_gettime(int clk_id, struct timespec *tp) { +void usbi_get_monotonic_time(struct timespec *tp) { mach_timespec_t sys_time; - clock_serv_t clock_ref; - - switch (clk_id) { - case USBI_CLOCK_REALTIME: - /* CLOCK_REALTIME represents time since the epoch */ - clock_ref = clock_realtime; - break; - case USBI_CLOCK_MONOTONIC: - /* use system boot time as reference for the monotonic clock */ - clock_ref = clock_monotonic; - break; - default: - errno = EINVAL; - return -1; - } - clock_get_time (clock_ref, &sys_time); + /* use system boot time as reference for the monotonic clock */ + clock_get_time (clock_monotonic, &sys_time); tp->tv_sec = sys_time.tv_sec; tp->tv_nsec = sys_time.tv_nsec; +} - return 0; +void usbi_get_real_time(struct timespec *tp) { + mach_timespec_t sys_time; + + /* CLOCK_REALTIME represents time since the epoch */ + clock_get_time (clock_realtime, &sys_time); + + tp->tv_sec = sys_time.tv_sec; + tp->tv_nsec = sys_time.tv_nsec; } #endif @@ -2215,7 +2215,7 @@ static int darwin_alloc_streams (struct libusb_device_handle *dev_handle, uint32 uint8_t pipeRef; int rc, i; - /* find the mimimum number of supported streams on the endpoint list */ + /* find the minimum number of supported streams on the endpoint list */ for (i = 0 ; i < num_endpoints ; ++i) { if (0 != (rc = ep_to_pipeRef (dev_handle, endpoints[i], &pipeRef, NULL, &cInterface))) { return rc; diff --git a/libusb/os/darwin_usb.h b/libusb/os/darwin_usb.h index b799bfd..20a1a34 100644 --- a/libusb/os/darwin_usb.h +++ b/libusb/os/darwin_usb.h @@ -200,4 +200,19 @@ struct darwin_transfer_priv { UInt32 size; }; + +/// Attempt to acquire exclusive USB access for the desired devices. +/// +/// This function must be called within a process with root priviledge. +/// +/// Assertions for exclusive access are maintained internally. This method only needs to be called one time. Subsequent calls will +/// have no effect. So, the USB devices must be attached at the time the emulator is launched. +/// +/// Currently the devices are specified at the command line. Multiple devices can be specified at the command line. For each such +/// device, specify the `-device` switch followed by the device's specification prefixed by `usb-host` and including the required vendor +/// and product ids along with any other optional properties. Properties are comma delimitted and specified as key/value pair +/// assignments with the `=` delimitter. For example: +/// `-device usb-host,bus=ehci.0,vendorid=0x0b05,productid=0x17cb` +void DarwinGetExclusiveAccessForDevices(void); + #endif diff --git a/libusb/os/events_posix.c b/libusb/os/events_posix.c new file mode 100644 index 0000000..b74189b --- /dev/null +++ b/libusb/os/events_posix.c @@ -0,0 +1,300 @@ +/* + * libusb event abstraction on POSIX platforms + * + * Copyright © 2020 Chris Dickens <christopher.a.dickens@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libusbi.h" + +#include <errno.h> +#include <fcntl.h> +#ifdef HAVE_EVENTFD +#include <sys/eventfd.h> +#endif +#ifdef HAVE_TIMERFD +#include <sys/timerfd.h> +#endif +#include <unistd.h> + +#ifdef HAVE_EVENTFD +#define EVENT_READ_FD(e) ((e)->eventfd) +#define EVENT_WRITE_FD(e) ((e)->eventfd) +#else +#define EVENT_READ_FD(e) ((e)->pipefd[0]) +#define EVENT_WRITE_FD(e) ((e)->pipefd[1]) +#endif + +#ifdef HAVE_NFDS_T +typedef nfds_t usbi_nfds_t; +#else +typedef unsigned int usbi_nfds_t; +#endif + +int usbi_create_event(usbi_event_t *event) +{ +#ifdef HAVE_EVENTFD + event->eventfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); + if (event->eventfd == -1) { + usbi_err(NULL, "failed to create eventfd, errno=%d", errno); + return LIBUSB_ERROR_OTHER; + } + + return 0; +#else +#if defined(HAVE_PIPE2) + int ret = pipe2(event->pipefd, O_CLOEXEC); +#else + int ret = pipe(event->pipefd); +#endif + + if (ret != 0) { + usbi_err(NULL, "failed to create pipe, errno=%d", errno); + return LIBUSB_ERROR_OTHER; + } + +#if !defined(HAVE_PIPE2) && defined(FD_CLOEXEC) + ret = fcntl(event->pipefd[0], F_GETFD); + if (ret == -1) { + usbi_err(NULL, "failed to get pipe fd flags, errno=%d", errno); + goto err_close_pipe; + } + ret = fcntl(event->pipefd[0], F_SETFD, ret | FD_CLOEXEC); + if (ret == -1) { + usbi_err(NULL, "failed to set pipe fd flags, errno=%d", errno); + goto err_close_pipe; + } + + ret = fcntl(event->pipefd[1], F_GETFD); + if (ret == -1) { + usbi_err(NULL, "failed to get pipe fd flags, errno=%d", errno); + goto err_close_pipe; + } + ret = fcntl(event->pipefd[1], F_SETFD, ret | FD_CLOEXEC); + if (ret == -1) { + usbi_err(NULL, "failed to set pipe fd flags, errno=%d", errno); + goto err_close_pipe; + } +#endif + + ret = fcntl(event->pipefd[1], F_GETFL); + if (ret == -1) { + usbi_err(NULL, "failed to get pipe fd status flags, errno=%d", errno); + goto err_close_pipe; + } + ret = fcntl(event->pipefd[1], F_SETFL, ret | O_NONBLOCK); + if (ret == -1) { + usbi_err(NULL, "failed to set pipe fd status flags, errno=%d", errno); + goto err_close_pipe; + } + + return 0; + +err_close_pipe: + close(event->pipefd[1]); + close(event->pipefd[0]); + return LIBUSB_ERROR_OTHER; +#endif +} + +void usbi_destroy_event(usbi_event_t *event) +{ +#ifdef HAVE_EVENTFD + if (close(event->eventfd) == -1) + usbi_warn(NULL, "failed to close eventfd, errno=%d", errno); +#else + if (close(event->pipefd[1]) == -1) + usbi_warn(NULL, "failed to close pipe write end, errno=%d", errno); + if (close(event->pipefd[0]) == -1) + usbi_warn(NULL, "failed to close pipe read end, errno=%d", errno); +#endif +} + +void usbi_signal_event(usbi_event_t *event) +{ + uint64_t dummy = 1; + ssize_t r; + + r = write(EVENT_WRITE_FD(event), &dummy, sizeof(dummy)); + if (r != sizeof(dummy)) + usbi_warn(NULL, "event write failed"); +} + +void usbi_clear_event(usbi_event_t *event) +{ + uint64_t dummy; + ssize_t r; + + r = read(EVENT_READ_FD(event), &dummy, sizeof(dummy)); + if (r != sizeof(dummy)) + usbi_warn(NULL, "event read failed"); +} + +#ifdef HAVE_TIMERFD +int usbi_create_timer(usbi_timer_t *timer) +{ + timer->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); + if (timer->timerfd == -1) { + usbi_warn(NULL, "failed to create timerfd, errno=%d", errno); + return LIBUSB_ERROR_OTHER; + } + + return 0; +} + +void usbi_destroy_timer(usbi_timer_t *timer) +{ + if (close(timer->timerfd) == -1) + usbi_warn(NULL, "failed to close timerfd, errno=%d", errno); +} + +int usbi_arm_timer(usbi_timer_t *timer, const struct timespec *timeout) +{ + const struct itimerspec it = { { 0, 0 }, { timeout->tv_sec, timeout->tv_nsec } }; + + if (timerfd_settime(timer->timerfd, TFD_TIMER_ABSTIME, &it, NULL) == -1) { + usbi_warn(NULL, "failed to arm timerfd, errno=%d", errno); + return LIBUSB_ERROR_OTHER; + } + + return 0; +} + +int usbi_disarm_timer(usbi_timer_t *timer) +{ + const struct itimerspec it = { { 0, 0 }, { 0, 0 } }; + + if (timerfd_settime(timer->timerfd, 0, &it, NULL) == -1) { + usbi_warn(NULL, "failed to disarm timerfd, errno=%d", errno); + return LIBUSB_ERROR_OTHER; + } + + return 0; +} +#endif + +int usbi_alloc_event_data(struct libusb_context *ctx) +{ + struct usbi_event_source *ievent_source; + struct pollfd *fds; + size_t i = 0; + + if (ctx->event_data) { + free(ctx->event_data); + ctx->event_data = NULL; + } + + ctx->event_data_cnt = 0; + for_each_event_source(ctx, ievent_source) + ctx->event_data_cnt++; + + fds = calloc(ctx->event_data_cnt, sizeof(*fds)); + if (!fds) + return LIBUSB_ERROR_NO_MEM; + + for_each_event_source(ctx, ievent_source) { + fds[i].fd = ievent_source->data.os_handle; + fds[i].events = ievent_source->data.poll_events; + i++; + } + + ctx->event_data = fds; + return 0; +} + +int usbi_wait_for_events(struct libusb_context *ctx, + struct usbi_reported_events *reported_events, int timeout_ms) +{ + struct pollfd *fds = ctx->event_data; + usbi_nfds_t nfds = (usbi_nfds_t)ctx->event_data_cnt; + int internal_fds, num_ready; + + usbi_dbg("poll() %u fds with timeout in %dms", (unsigned int)nfds, timeout_ms); + num_ready = poll(fds, nfds, timeout_ms); + usbi_dbg("poll() returned %d", num_ready); + if (num_ready == 0) { + if (usbi_using_timer(ctx)) + goto done; + return LIBUSB_ERROR_TIMEOUT; + } else if (num_ready == -1) { + if (errno == EINTR) + return LIBUSB_ERROR_INTERRUPTED; + usbi_err(ctx, "poll() failed, errno=%d", errno); + return LIBUSB_ERROR_IO; + } + + /* fds[0] is always the internal signalling event */ + if (fds[0].revents) { + reported_events->event_triggered = 1; + num_ready--; + } else { + reported_events->event_triggered = 0; + } + +#ifdef HAVE_OS_TIMER + /* on timer configurations, fds[1] is the timer */ + if (usbi_using_timer(ctx) && fds[1].revents) { + reported_events->timer_triggered = 1; + num_ready--; + } else { + reported_events->timer_triggered = 0; + } +#endif + + if (!num_ready) + goto done; + + /* the backend will never need to attempt to handle events on the + * library's internal file descriptors, so we determine how many are + * in use internally for this context and skip these when passing any + * remaining pollfds to the backend. */ + internal_fds = usbi_using_timer(ctx) ? 2 : 1; + fds += internal_fds; + nfds -= internal_fds; + + usbi_mutex_lock(&ctx->event_data_lock); + if (ctx->event_flags & USBI_EVENT_EVENT_SOURCES_MODIFIED) { + struct usbi_event_source *ievent_source; + + for_each_removed_event_source(ctx, ievent_source) { + usbi_nfds_t n; + + for (n = 0; n < nfds; n++) { + if (ievent_source->data.os_handle != fds[n].fd) + continue; + if (!fds[n].revents) + continue; + /* pollfd was removed between the creation of the fds array and + * here. remove triggered revent as it is no longer relevant. */ + usbi_dbg("fd %d was removed, ignoring raised events", fds[n].fd); + fds[n].revents = 0; + num_ready--; + break; + } + } + } + usbi_mutex_unlock(&ctx->event_data_lock); + + if (num_ready) { + assert(num_ready > 0); + reported_events->event_data = fds; + reported_events->event_data_count = (unsigned int)nfds; + } + +done: + reported_events->num_ready = num_ready; + return LIBUSB_SUCCESS; +} diff --git a/libusb/os/events_posix.h b/libusb/os/events_posix.h new file mode 100644 index 0000000..d81b5c4 --- /dev/null +++ b/libusb/os/events_posix.h @@ -0,0 +1,59 @@ +/* + * libusb event abstraction on POSIX platforms + * + * Copyright © 2020 Chris Dickens <christopher.a.dickens@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LIBUSB_EVENTS_POSIX_H +#define LIBUSB_EVENTS_POSIX_H + +#include <poll.h> + +typedef int usbi_os_handle_t; +#define USBI_OS_HANDLE_FORMAT_STRING "fd %d" + +#ifdef HAVE_EVENTFD +typedef struct usbi_event { + int eventfd; +} usbi_event_t; +#define USBI_EVENT_OS_HANDLE(e) ((e)->eventfd) +#define USBI_EVENT_POLL_EVENTS POLLIN +#define USBI_INVALID_EVENT { -1 } +#else +typedef struct usbi_event { + int pipefd[2]; +} usbi_event_t; +#define USBI_EVENT_OS_HANDLE(e) ((e)->pipefd[0]) +#define USBI_EVENT_POLL_EVENTS POLLIN +#define USBI_INVALID_EVENT { { -1, -1 } } +#endif + +#ifdef HAVE_TIMERFD +#define HAVE_OS_TIMER 1 +typedef struct usbi_timer { + int timerfd; +} usbi_timer_t; +#define USBI_TIMER_OS_HANDLE(t) ((t)->timerfd) +#define USBI_TIMER_POLL_EVENTS POLLIN + +static inline int usbi_timer_valid(usbi_timer_t *timer) +{ + return timer->timerfd >= 0; +} +#endif + +#endif diff --git a/libusb/os/events_windows.c b/libusb/os/events_windows.c new file mode 100644 index 0000000..81d8b87 --- /dev/null +++ b/libusb/os/events_windows.c @@ -0,0 +1,214 @@ +/* + * libusb event abstraction on Microsoft Windows + * + * Copyright © 2020 Chris Dickens <christopher.a.dickens@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include "libusbi.h" +#include "windows_common.h" + +int usbi_create_event(usbi_event_t *event) +{ + event->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (event->hEvent == NULL) { + usbi_err(NULL, "CreateEvent failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_OTHER; + } + + return 0; +} + +void usbi_destroy_event(usbi_event_t *event) +{ + if (!CloseHandle(event->hEvent)) + usbi_warn(NULL, "CloseHandle failed: %s", windows_error_str(0)); +} + +void usbi_signal_event(usbi_event_t *event) +{ + if (!SetEvent(event->hEvent)) + usbi_warn(NULL, "SetEvent failed: %s", windows_error_str(0)); +} + +void usbi_clear_event(usbi_event_t *event) +{ + if (!ResetEvent(event->hEvent)) + usbi_warn(NULL, "ResetEvent failed: %s", windows_error_str(0)); +} + +#ifdef HAVE_OS_TIMER +int usbi_create_timer(usbi_timer_t *timer) +{ + timer->hTimer = CreateWaitableTimer(NULL, TRUE, NULL); + if (timer->hTimer == NULL) { + usbi_warn(NULL, "CreateWaitableTimer failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_OTHER; + } + + return 0; +} + +void usbi_destroy_timer(usbi_timer_t *timer) +{ + if (!CloseHandle(timer->hTimer)) + usbi_warn(NULL, "CloseHandle failed: %s", windows_error_str(0)); +} + +int usbi_arm_timer(usbi_timer_t *timer, const struct timespec *timeout) +{ + struct timespec systime, remaining; + FILETIME filetime; + LARGE_INTEGER dueTime; + + /* Transfer timeouts are based on the monotonic clock and the waitable + * timers on the system clock. This requires a conversion between the + * two, so we calculate the remaining time relative to the monotonic + * clock and calculate an absolute system time for the timer expiration. + * Note that if the timeout has already passed, the remaining time will + * be negative and thus an absolute system time in the past will be set. + * This works just as intended because the timer becomes signalled + * immediately. */ + usbi_get_monotonic_time(&systime); + + TIMESPEC_SUB(timeout, &systime, &remaining); + + GetSystemTimeAsFileTime(&filetime); + dueTime.LowPart = filetime.dwLowDateTime; + dueTime.HighPart = filetime.dwHighDateTime; + dueTime.QuadPart += (remaining.tv_sec * 10000000LL) + (remaining.tv_nsec / 100LL); + + if (!SetWaitableTimer(timer->hTimer, &dueTime, 0, NULL, NULL, FALSE)) { + usbi_warn(NULL, "SetWaitableTimer failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_OTHER; + } + + return 0; +} + +int usbi_disarm_timer(usbi_timer_t *timer) +{ + LARGE_INTEGER dueTime; + + /* A manual-reset waitable timer will stay in the signalled state until + * another call to SetWaitableTimer() is made. It is possible that the + * timer has already expired by the time we come in to disarm it, so to + * be entirely sure the timer is disarmed and not in the signalled state, + * we will set it with an impossibly large expiration and immediately + * cancel. */ + dueTime.QuadPart = LLONG_MAX; + if (!SetWaitableTimer(timer->hTimer, &dueTime, 0, NULL, NULL, FALSE)) { + usbi_warn(NULL, "SetWaitableTimer failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_OTHER; + } + + if (!CancelWaitableTimer(timer->hTimer)) { + usbi_warn(NULL, "SetWaitableTimer failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_OTHER; + } + + return 0; +} +#endif + +int usbi_alloc_event_data(struct libusb_context *ctx) +{ + struct usbi_event_source *ievent_source; + HANDLE *handles; + size_t i = 0; + + /* Event sources are only added during usbi_io_init(). We should not + * be running this function again if the event data has already been + * allocated. */ + if (ctx->event_data) { + usbi_warn(ctx, "program assertion failed - event data already allocated"); + return LIBUSB_ERROR_OTHER; + } + + ctx->event_data_cnt = 0; + for_each_event_source(ctx, ievent_source) + ctx->event_data_cnt++; + + /* We only expect up to two HANDLEs to wait on, one for the internal + * signalling event and the other for the timer. */ + if (ctx->event_data_cnt != 1 && ctx->event_data_cnt != 2) { + usbi_err(ctx, "program assertion failed - expected exactly 1 or 2 HANDLEs"); + return LIBUSB_ERROR_OTHER; + } + + handles = calloc(ctx->event_data_cnt, sizeof(HANDLE)); + if (!handles) + return LIBUSB_ERROR_NO_MEM; + + for_each_event_source(ctx, ievent_source) { + handles[i] = ievent_source->data.os_handle; + i++; + } + + ctx->event_data = handles; + return 0; +} + +int usbi_wait_for_events(struct libusb_context *ctx, + struct usbi_reported_events *reported_events, int timeout_ms) +{ + HANDLE *handles = ctx->event_data; + DWORD num_handles = (DWORD)ctx->event_data_cnt; + DWORD result; + + usbi_dbg("WaitForMultipleObjects() for %lu HANDLEs with timeout in %dms", ULONG_CAST(num_handles), timeout_ms); + result = WaitForMultipleObjects(num_handles, handles, FALSE, (DWORD)timeout_ms); + usbi_dbg("WaitForMultipleObjects() returned %lu", ULONG_CAST(result)); + if (result == WAIT_TIMEOUT) { + if (usbi_using_timer(ctx)) + goto done; + return LIBUSB_ERROR_TIMEOUT; + } else if (result == WAIT_FAILED) { + usbi_err(ctx, "WaitForMultipleObjects() failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_IO; + } + + result -= WAIT_OBJECT_0; + + /* handles[0] is always the internal signalling event */ + if (result == 0) + reported_events->event_triggered = 1; + else + reported_events->event_triggered = 0; + +#ifdef HAVE_OS_TIMER + /* on timer configurations, handles[1] is the timer */ + if (usbi_using_timer(ctx)) { + /* The WaitForMultipleObjects() function reports the index of + * the first object that became signalled. If the internal + * signalling event was reported, we need to also check and + * report whether the timer is in the signalled state. */ + if (result == 1 || WaitForSingleObject(handles[1], 0) == WAIT_OBJECT_0) + reported_events->timer_triggered = 1; + else + reported_events->timer_triggered = 0; + } else { + reported_events->timer_triggered = 0; + } +#endif + +done: + /* no events are ever reported to the backend */ + reported_events->num_ready = 0; + return LIBUSB_SUCCESS; +} diff --git a/libusb/os/events_windows.h b/libusb/os/events_windows.h new file mode 100644 index 0000000..0c5e0b0 --- /dev/null +++ b/libusb/os/events_windows.h @@ -0,0 +1,46 @@ +/* + * libusb event abstraction on Microsoft Windows + * + * Copyright © 2020 Chris Dickens <christopher.a.dickens@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LIBUSB_EVENTS_WINDOWS_H +#define LIBUSB_EVENTS_WINDOWS_H + +typedef HANDLE usbi_os_handle_t; +#define USBI_OS_HANDLE_FORMAT_STRING "HANDLE %p" + +typedef struct usbi_event { + HANDLE hEvent; +} usbi_event_t; +#define USBI_EVENT_OS_HANDLE(e) ((e)->hEvent) +#define USBI_EVENT_POLL_EVENTS 0 +#define USBI_INVALID_EVENT { INVALID_HANDLE_VALUE } + +#define HAVE_OS_TIMER 1 +typedef struct usbi_timer { + HANDLE hTimer; +} usbi_timer_t; +#define USBI_TIMER_OS_HANDLE(t) ((t)->hTimer) +#define USBI_TIMER_POLL_EVENTS 0 + +static inline int usbi_timer_valid(usbi_timer_t *timer) +{ + return timer->hTimer != NULL; +} + +#endif diff --git a/libusb/os/haiku_pollfs.cpp b/libusb/os/haiku_pollfs.cpp index c60b3b5..cb4fda8 100644 --- a/libusb/os/haiku_pollfs.cpp +++ b/libusb/os/haiku_pollfs.cpp @@ -97,7 +97,7 @@ WatchedEntry::WatchedEntry(BMessenger *messenger, entry_ref *ref) 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) { + for_each_context(ctx) { 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); @@ -172,7 +172,7 @@ WatchedEntry::~WatchedEntry() 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) { + for_each_context(ctx) { dev = usbi_get_device_by_session_id(ctx, session_id); if (dev != NULL) { usbi_disconnect_device(dev); diff --git a/libusb/os/linux_netlink.c b/libusb/os/linux_netlink.c index 9917df2..77c83c5 100644 --- a/libusb/os/linux_netlink.c +++ b/libusb/os/linux_netlink.c @@ -48,7 +48,7 @@ #endif static int linux_netlink_socket = -1; -static int netlink_control_pipe[2] = { -1, -1 }; +static usbi_event_t netlink_control_event = USBI_INVALID_EVENT; static pthread_t libusb_linux_event_thread; static void *linux_netlink_event_thread_main(void *arg); @@ -125,25 +125,23 @@ int linux_netlink_start_event_monitor(void) goto err_close_socket; } - ret = usbi_pipe(netlink_control_pipe); + ret = usbi_create_event(&netlink_control_event); if (ret) { - usbi_err(NULL, "failed to create netlink control pipe"); + usbi_err(NULL, "failed to create netlink control event"); goto err_close_socket; } ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL); if (ret != 0) { usbi_err(NULL, "failed to create netlink event thread (%d)", ret); - goto err_close_pipe; + goto err_destroy_event; } 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_destroy_event: + usbi_destroy_event(&netlink_control_event); + netlink_control_event = (usbi_event_t)USBI_INVALID_EVENT; err_close_socket: close(linux_netlink_socket); linux_netlink_socket = -1; @@ -153,28 +151,23 @@ err: int linux_netlink_stop_event_monitor(void) { - char dummy = 1; - ssize_t r; + int ret; assert(linux_netlink_socket != -1); - /* Write some dummy data to the control pipe and - * wait for the thread to exit */ - r = write(netlink_control_pipe[1], &dummy, sizeof(dummy)); - if (r <= 0) - usbi_warn(NULL, "netlink control pipe signal failed"); + /* Signal the control event and wait for the thread to exit */ + usbi_signal_event(&netlink_control_event); + + ret = pthread_join(libusb_linux_event_thread, NULL); + if (ret) + usbi_warn(NULL, "failed to join netlink event thread (%d)", ret); - pthread_join(libusb_linux_event_thread, NULL); + usbi_destroy_event(&netlink_control_event); + netlink_control_event = (usbi_event_t)USBI_INVALID_EVENT; close(linux_netlink_socket); linux_netlink_socket = -1; - /* close and reset control pipe */ - close(netlink_control_pipe[0]); - close(netlink_control_pipe[1]); - netlink_control_pipe[0] = -1; - netlink_control_pipe[1] = -1; - return LIBUSB_SUCCESS; } @@ -353,15 +346,13 @@ static int linux_netlink_read_message(void) static void *linux_netlink_event_thread_main(void *arg) { - char dummy; - int r; - ssize_t nb; struct pollfd fds[] = { - { .fd = netlink_control_pipe[0], - .events = POLLIN }, + { .fd = USBI_EVENT_OS_HANDLE(&netlink_control_event), + .events = USBI_EVENT_POLL_EVENTS }, { .fd = linux_netlink_socket, .events = POLLIN }, }; + int r; UNUSED(arg); @@ -373,19 +364,20 @@ static void *linux_netlink_event_thread_main(void *arg) usbi_dbg("netlink event thread entering"); - while ((r = poll(fds, 2, -1)) >= 0 || errno == EINTR) { - if (r < 0) { - /* temporary failure */ - continue; + while (1) { + r = poll(fds, 2, -1); + if (r == -1) { + /* check for temporary failure */ + if (errno == EINTR) + continue; + usbi_err(NULL, "poll() failed, errno=%d", errno); + break; } - if (fds[0].revents & POLLIN) { - /* activity on control pipe, read the byte and exit */ - nb = read(netlink_control_pipe[0], &dummy, sizeof(dummy)); - if (nb <= 0) - usbi_warn(NULL, "netlink control pipe read failed"); + if (fds[0].revents) { + /* activity on control event, exit */ break; } - if (fds[1].revents & POLLIN) { + if (fds[1].revents) { usbi_mutex_static_lock(&linux_hotplug_lock); linux_netlink_read_message(); usbi_mutex_static_unlock(&linux_hotplug_lock); diff --git a/libusb/os/linux_udev.c b/libusb/os/linux_udev.c index e8fb198..beb2f05 100644 --- a/libusb/os/linux_udev.c +++ b/libusb/os/linux_udev.c @@ -34,7 +34,7 @@ /* udev context */ static struct udev *udev_ctx = NULL; static int udev_monitor_fd = -1; -static int udev_control_pipe[2] = {-1, -1}; +static usbi_event_t udev_control_event = USBI_INVALID_EVENT; static struct udev_monitor *udev_monitor = NULL; static pthread_t linux_event_thread; @@ -100,23 +100,23 @@ int linux_udev_start_event_monitor(void) } } - r = usbi_pipe(udev_control_pipe); + r = usbi_create_event(&udev_control_event); if (r) { - usbi_err(NULL, "could not create udev control pipe"); + usbi_err(NULL, "failed to create udev control event"); goto err_free_monitor; } r = pthread_create(&linux_event_thread, NULL, linux_udev_event_thread_main, NULL); if (r) { - usbi_err(NULL, "creating hotplug event thread (%d)", r); - goto err_close_pipe; + usbi_err(NULL, "failed to create hotplug event thread (%d)", r); + goto err_destroy_event; } return LIBUSB_SUCCESS; -err_close_pipe: - close(udev_control_pipe[0]); - close(udev_control_pipe[1]); +err_destroy_event: + usbi_destroy_event(&udev_control_event); + udev_control_event = (usbi_event_t)USBI_INVALID_EVENT; err_free_monitor: udev_monitor_unref(udev_monitor); udev_monitor = NULL; @@ -130,20 +130,21 @@ err: int linux_udev_stop_event_monitor(void) { - char dummy = 1; - ssize_t r; + int r; assert(udev_ctx != NULL); assert(udev_monitor != NULL); assert(udev_monitor_fd != -1); - /* Write some dummy data to the control pipe and - * wait for the thread to exit */ - r = write(udev_control_pipe[1], &dummy, sizeof(dummy)); - if (r <= 0) { - usbi_warn(NULL, "udev control pipe signal failed"); - } - pthread_join(linux_event_thread, NULL); + /* Signal the control event and wait for the thread to exit */ + usbi_signal_event(&udev_control_event); + + r = pthread_join(linux_event_thread, NULL); + if (r) + usbi_warn(NULL, "failed to join hotplug event thread (%d)", r); + + usbi_destroy_event(&udev_control_event); + udev_control_event = (usbi_event_t)USBI_INVALID_EVENT; /* Release the udev monitor */ udev_monitor_unref(udev_monitor); @@ -154,27 +155,19 @@ int linux_udev_stop_event_monitor(void) udev_unref(udev_ctx); udev_ctx = NULL; - /* close and reset control pipe */ - close(udev_control_pipe[0]); - close(udev_control_pipe[1]); - udev_control_pipe[0] = -1; - udev_control_pipe[1] = -1; - return LIBUSB_SUCCESS; } static void *linux_udev_event_thread_main(void *arg) { - char dummy; - int r; - ssize_t nb; - struct udev_device *udev_dev; struct pollfd fds[] = { - {.fd = udev_control_pipe[0], - .events = POLLIN}, - {.fd = udev_monitor_fd, - .events = POLLIN}, + { .fd = USBI_EVENT_OS_HANDLE(&udev_control_event), + .events = USBI_EVENT_POLL_EVENTS }, + { .fd = udev_monitor_fd, + .events = POLLIN }, }; + struct udev_device *udev_dev; + int r; UNUSED(arg); @@ -186,20 +179,20 @@ static void *linux_udev_event_thread_main(void *arg) usbi_dbg("udev event thread entering"); - while ((r = poll(fds, 2, -1)) >= 0 || errno == EINTR) { - if (r < 0) { - /* temporary failure */ - continue; + while (1) { + r = poll(fds, 2, -1); + if (r == -1) { + /* check for temporary failure */ + if (errno == EINTR) + continue; + usbi_err(NULL, "poll() failed, errno=%d", errno); + break; } - if (fds[0].revents & POLLIN) { - /* activity on control pipe, read the byte and exit */ - nb = read(udev_control_pipe[0], &dummy, sizeof(dummy)); - if (nb <= 0) { - usbi_warn(NULL, "udev control pipe read failed"); - } + if (fds[0].revents) { + /* activity on control event, exit */ break; } - if (fds[1].revents & POLLIN) { + if (fds[1].revents) { usbi_mutex_static_lock(&linux_hotplug_lock); udev_dev = udev_monitor_receive_device(udev_monitor); if (udev_dev) diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c index 082d726..fb2ed53 100644 --- a/libusb/os/linux_usbfs.c +++ b/libusb/os/linux_usbfs.c @@ -36,6 +36,7 @@ #include <sys/mman.h> #include <sys/utsname.h> #include <sys/vfs.h> +#include <unistd.h> /* sysfs vs usbfs: * opening a usbfs node causes the device to be resumed, so we attempt to @@ -94,6 +95,11 @@ static int sysfs_available = -1; /* how many times have we initted (and not exited) ? */ static int init_count = 0; +#ifdef __ANDROID__ +/* have no authority to operate usb device directly */ +static int weak_authority = 0; +#endif + /* Serialize hotplug start/stop */ static usbi_mutex_static_t linux_hotplug_startstop_lock = USBI_MUTEX_INITIALIZER; /* Serialize scan-devices, event-thread, and poll */ @@ -380,6 +386,12 @@ static int op_init(struct libusb_context *ctx) } } +#ifdef __ANDROID__ + if (weak_authority) { + return LIBUSB_SUCCESS; + } +#endif + usbi_mutex_static_lock(&linux_hotplug_startstop_lock); r = LIBUSB_SUCCESS; if (init_count == 0) { @@ -412,6 +424,24 @@ static void op_exit(struct libusb_context *ctx) usbi_mutex_static_unlock(&linux_hotplug_startstop_lock); } +static int op_set_option(struct libusb_context *ctx, enum libusb_option option, va_list ap) +{ + UNUSED(ctx); + UNUSED(ap); + +#ifdef __ANDROID__ + if (option == LIBUSB_OPTION_WEAK_AUTHORITY) { + usbi_dbg("set libusb has weak authority"); + weak_authority = 1; + return LIBUSB_SUCCESS; + } +#else + UNUSED(option); +#endif + + return LIBUSB_ERROR_NOT_SUPPORTED; +} + static int linux_scan_devices(struct libusb_context *ctx) { int ret; @@ -647,7 +677,7 @@ static int parse_config_descriptors(struct libusb_device *dev) uint8_t *buffer; size_t remaining; - device_desc = (struct usbi_device_descriptor *)priv->descriptors; + device_desc = priv->descriptors; num_configs = device_desc->bNumConfigurations; if (num_configs == 0) @@ -657,7 +687,7 @@ static int parse_config_descriptors(struct libusb_device *dev) if (!priv->config_descriptors) return LIBUSB_ERROR_NO_MEM; - buffer = priv->descriptors + LIBUSB_DT_DEVICE_SIZE; + buffer = (uint8_t *)priv->descriptors + LIBUSB_DT_DEVICE_SIZE; remaining = priv->descriptors_len - LIBUSB_DT_DEVICE_SIZE; for (idx = 0; idx < num_configs; idx++) { @@ -834,6 +864,26 @@ static int usbfs_get_active_config(struct libusb_device *dev, int fd) return LIBUSB_SUCCESS; } +static enum libusb_speed usbfs_get_speed(struct libusb_context *ctx, int fd) +{ + int r; + + r = ioctl(fd, IOCTL_USBFS_GET_SPEED, NULL); + switch (r) { + case USBFS_SPEED_UNKNOWN: return LIBUSB_SPEED_UNKNOWN; + case USBFS_SPEED_LOW: return LIBUSB_SPEED_LOW; + case USBFS_SPEED_FULL: return LIBUSB_SPEED_FULL; + case USBFS_SPEED_HIGH: return LIBUSB_SPEED_HIGH; + case USBFS_SPEED_WIRELESS: return LIBUSB_SPEED_HIGH; + case USBFS_SPEED_SUPER: return LIBUSB_SPEED_SUPER; + case USBFS_SPEED_SUPER_PLUS: return LIBUSB_SPEED_SUPER_PLUS; + default: + usbi_warn(ctx, "Error getting device speed: %d", r); + } + + return LIBUSB_SPEED_UNKNOWN; +} + static int initialize_device(struct libusb_device *dev, uint8_t busnum, uint8_t devaddr, const char *sysfs_dir, int wrapped_fd) { @@ -864,6 +914,8 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, usbi_warn(ctx, "unknown device speed: %d Mbps", speed); } } + } else if (wrapped_fd >= 0) { + dev->speed = usbfs_get_speed(ctx, wrapped_fd); } /* cache descriptors in memory */ @@ -884,19 +936,21 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, alloc_len = 0; do { - alloc_len += 256; + const size_t desc_read_length = 256; + uint8_t *read_ptr; + + alloc_len += desc_read_length; priv->descriptors = usbi_reallocf(priv->descriptors, alloc_len); if (!priv->descriptors) { if (fd != wrapped_fd) close(fd); return LIBUSB_ERROR_NO_MEM; } + read_ptr = (uint8_t *)priv->descriptors + priv->descriptors_len; /* usbfs has holes in the file */ if (!sysfs_dir) - memset(priv->descriptors + priv->descriptors_len, - 0, alloc_len - priv->descriptors_len); - nb = read(fd, priv->descriptors + priv->descriptors_len, - alloc_len - priv->descriptors_len); + memset(read_ptr, 0, desc_read_length); + nb = read(fd, read_ptr, desc_read_length); if (nb < 0) { usbi_err(ctx, "read descriptor failed, errno=%d", errno); if (fd != wrapped_fd) @@ -991,7 +1045,7 @@ static int linux_get_parent_info(struct libusb_device *dev, const char *sysfs_di retry: /* find the parent in the context */ usbi_mutex_lock(&ctx->usb_devs_lock); - list_for_each_entry(it, &ctx->usb_devs, list, struct libusb_device) { + for_each_device(ctx, it) { struct linux_device_priv *priv = usbi_get_device_priv(it); if (priv->sysfs_dir) { @@ -1070,7 +1124,7 @@ void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_na struct libusb_context *ctx; usbi_mutex_static_lock(&active_contexts_lock); - list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) { + for_each_context(ctx) { linux_enumerate_device(ctx, busnum, devaddr, sys_name); } usbi_mutex_static_unlock(&active_contexts_lock); @@ -1083,7 +1137,7 @@ void linux_device_disconnected(uint8_t busnum, uint8_t devaddr) unsigned long session_id = busnum << 8 | devaddr; usbi_mutex_static_lock(&active_contexts_lock); - list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) { + for_each_context(ctx) { dev = usbi_get_device_by_session_id(ctx, session_id); if (dev) { usbi_disconnect_device(dev); @@ -1266,7 +1320,7 @@ static int initialize_handle(struct libusb_device_handle *handle, int fd) hpriv->caps = USBFS_CAP_BULK_CONTINUATION; } - return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT); + return usbi_add_event_source(HANDLE_CTX(handle), hpriv->fd, POLLOUT); } static int op_wrap_sys_device(struct libusb_context *ctx, @@ -1352,7 +1406,7 @@ static void op_close(struct libusb_device_handle *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); + usbi_remove_event_source(HANDLE_CTX(dev_handle), hpriv->fd); if (!hpriv->fd_keep) close(hpriv->fd); } @@ -1845,7 +1899,7 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer) * a time, but there is a big performance gain doing it this way. * * Newer versions lift the 16k limit (USBFS_CAP_NO_PACKET_SIZE_LIM), - * using arbritary large transfers can still be a bad idea though, as + * using arbitrary large transfers can still be a bad idea though, as * the kernel needs to allocate physical contiguous memory for this, * which may fail for large buffers. * @@ -2614,22 +2668,24 @@ static int reap_for_handle(struct libusb_device_handle *handle) } static int op_handle_events(struct libusb_context *ctx, - struct pollfd *fds, usbi_nfds_t nfds, int num_ready) + void *event_data, unsigned int count, unsigned int num_ready) { - usbi_nfds_t n; + struct pollfd *fds = event_data; + unsigned int n; int r; usbi_mutex_lock(&ctx->open_devs_lock); - for (n = 0; n < nfds && num_ready > 0; n++) { + for (n = 0; n < count && num_ready > 0; n++) { struct pollfd *pollfd = &fds[n]; struct libusb_device_handle *handle; struct linux_device_handle_priv *hpriv = NULL; + int reap_count; if (!pollfd->revents) continue; num_ready--; - list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) { + for_each_open_device(ctx, handle) { hpriv = usbi_get_device_handle_priv(handle); if (hpriv->fd == pollfd->fd) break; @@ -2645,7 +2701,7 @@ static int op_handle_events(struct libusb_context *ctx, /* 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_remove_event_source(HANDLE_CTX(handle), hpriv->fd); hpriv->fd_removed = 1; /* device will still be marked as attached if hotplug monitor thread @@ -2666,9 +2722,11 @@ static int op_handle_events(struct libusb_context *ctx, continue; } + reap_count = 0; do { r = reap_for_handle(handle); - } while (r == 0); + } while (r == 0 && ++reap_count <= 25); + if (r == 1 || r == LIBUSB_ERROR_NO_DEVICE) continue; else if (r < 0) @@ -2686,6 +2744,7 @@ const struct usbi_os_backend usbi_backend = { .caps = USBI_CAP_HAS_HID_ACCESS|USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER, .init = op_init, .exit = op_exit, + .set_option = op_set_option, .hotplug_poll = op_hotplug_poll, .get_active_config_descriptor = op_get_active_config_descriptor, .get_config_descriptor = op_get_config_descriptor, diff --git a/libusb/os/linux_usbfs.h b/libusb/os/linux_usbfs.h index 060aa35..1238ffa 100644 --- a/libusb/os/linux_usbfs.h +++ b/libusb/os/linux_usbfs.h @@ -127,6 +127,14 @@ struct usbfs_streams { unsigned char eps[0]; }; +#define USBFS_SPEED_UNKNOWN 0 +#define USBFS_SPEED_LOW 1 +#define USBFS_SPEED_FULL 2 +#define USBFS_SPEED_HIGH 3 +#define USBFS_SPEED_WIRELESS 4 +#define USBFS_SPEED_SUPER 5 +#define USBFS_SPEED_SUPER_PLUS 6 + #define IOCTL_USBFS_CONTROL _IOWR('U', 0, struct usbfs_ctrltransfer) #define IOCTL_USBFS_SETINTERFACE _IOR('U', 4, struct usbfs_setinterface) #define IOCTL_USBFS_SETCONFIGURATION _IOR('U', 5, unsigned int) @@ -146,6 +154,8 @@ struct usbfs_streams { #define IOCTL_USBFS_DISCONNECT_CLAIM _IOR('U', 27, struct usbfs_disconnect_claim) #define IOCTL_USBFS_ALLOC_STREAMS _IOR('U', 28, struct usbfs_streams) #define IOCTL_USBFS_FREE_STREAMS _IOR('U', 29, struct usbfs_streams) +#define IOCTL_USBFS_DROP_PRIVILEGES _IOW('U', 30, __u32) +#define IOCTL_USBFS_GET_SPEED _IO('U', 31) extern usbi_mutex_static_t linux_hotplug_lock; diff --git a/libusb/os/openbsd_usb.c b/libusb/os/openbsd_usb.c index f5b0470..e05610e 100644 --- a/libusb/os/openbsd_usb.c +++ b/libusb/os/openbsd_usb.c @@ -173,6 +173,7 @@ obsd_get_device_list(struct libusb_context * ctx, dev->bus_number = di.udi_bus; dev->device_address = di.udi_addr; dev->speed = di.udi_speed; + dev->port_number = di.udi_port; dpriv = usbi_get_device_priv(dev); dpriv->fd = -1; @@ -225,15 +226,17 @@ obsd_open(struct libusb_device_handle *handle) char devnode[16]; if (dpriv->devname) { + int fd; /* * Only open ugen(4) attached devices read-write, all * read-only operations are done through the bus node. */ snprintf(devnode, sizeof(devnode), DEVPATH "%s.00", dpriv->devname); - dpriv->fd = open(devnode, O_RDWR); - if (dpriv->fd < 0) + fd = open(devnode, O_RDWR); + if (fd < 0) return _errno_to_libusb(errno); + dpriv->fd = fd; usbi_dbg("open %s: fd %d", devnode, dpriv->fd); } diff --git a/libusb/os/poll_posix.c b/libusb/os/poll_posix.c deleted file mode 100644 index 93e9bee..0000000 --- a/libusb/os/poll_posix.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * poll_posix: poll compatibility wrapper for POSIX systems - * Copyright © 2013 RealVNC Ltd. - * - * 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 "libusbi.h" - -#include <errno.h> -#include <fcntl.h> -#include <unistd.h> - -int usbi_pipe(int pipefd[2]) -{ -#if defined(HAVE_PIPE2) - int ret = pipe2(pipefd, O_CLOEXEC); -#else - int ret = pipe(pipefd); -#endif - - if (ret != 0) { - usbi_err(NULL, "failed to create pipe, errno=%d", errno); - return ret; - } - -#if !defined(HAVE_PIPE2) && defined(FD_CLOEXEC) - ret = fcntl(pipefd[0], F_GETFD); - if (ret == -1) { - usbi_err(NULL, "failed to get pipe fd flags, errno=%d", errno); - goto err_close_pipe; - } - ret = fcntl(pipefd[0], F_SETFD, ret | FD_CLOEXEC); - if (ret == -1) { - usbi_err(NULL, "failed to set pipe fd flags, errno=%d", errno); - goto err_close_pipe; - } - - ret = fcntl(pipefd[1], F_GETFD); - if (ret == -1) { - usbi_err(NULL, "failed to get pipe fd flags, errno=%d", errno); - goto err_close_pipe; - } - ret = fcntl(pipefd[1], F_SETFD, ret | FD_CLOEXEC); - if (ret == -1) { - usbi_err(NULL, "failed to set pipe fd flags, errno=%d", errno); - goto err_close_pipe; - } -#endif - - ret = fcntl(pipefd[1], F_GETFL); - if (ret == -1) { - usbi_err(NULL, "failed to get pipe fd status flags, errno=%d", errno); - goto err_close_pipe; - } - ret = fcntl(pipefd[1], F_SETFL, ret | O_NONBLOCK); - if (ret == -1) { - usbi_err(NULL, "failed to set pipe fd status flags, errno=%d", errno); - goto err_close_pipe; - } - - return 0; - -err_close_pipe: - close(pipefd[0]); - close(pipefd[1]); - return ret; -} diff --git a/libusb/os/poll_posix.h b/libusb/os/poll_posix.h deleted file mode 100644 index 48c4904..0000000 --- a/libusb/os/poll_posix.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef LIBUSB_POLL_POSIX_H -#define LIBUSB_POLL_POSIX_H - -#include <poll.h> -#include <unistd.h> - -#ifdef HAVE_NFDS_T -typedef nfds_t usbi_nfds_t; -#else -typedef unsigned int usbi_nfds_t; -#endif - -#define usbi_write write -#define usbi_read read -#define usbi_close close -#define usbi_poll poll - -int usbi_pipe(int pipefd[2]); - -#endif /* LIBUSB_POLL_POSIX_H */ diff --git a/libusb/os/poll_windows.c b/libusb/os/poll_windows.c deleted file mode 100644 index bf9f7b7..0000000 --- a/libusb/os/poll_windows.c +++ /dev/null @@ -1,556 +0,0 @@ -/* - * poll_windows: poll compatibility wrapper for Windows - * Copyright © 2017 Chris Dickens <christopher.a.dickens@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -/* - * poll() and pipe() Windows compatibility layer for libusb 1.0 - * - * The way this layer works is by using OVERLAPPED with async I/O transfers, as - * OVERLAPPED have an associated event which is flagged for I/O completion. - * - * For USB pollable async I/O, you would typically: - * - obtain a Windows HANDLE to a file or device that has been opened in - * OVERLAPPED mode - * - call usbi_create_fd with this handle to obtain a custom fd. - * - leave the core functions call the poll routine and flag POLLIN/POLLOUT - * - * The pipe pollable synchronous I/O works using the overlapped event associated - * with a fake pipe. The read/write functions are only meant to be used in that - * context. - */ - -#include "libusbi.h" -#include "windows_common.h" - -#include <errno.h> -#include <intrin.h> -#include <malloc.h> -#include <stdbool.h> -#include <stdlib.h> - -// public fd data -const struct winfd INVALID_WINFD = { -1, NULL }; - -// private data -struct file_descriptor { - enum fd_type { FD_TYPE_PIPE, FD_TYPE_TRANSFER } type; - LONG refcount; - OVERLAPPED overlapped; -}; - -static usbi_mutex_static_t fd_table_lock = USBI_MUTEX_INITIALIZER; - -#define BITS_PER_BYTE 8 -#define BITMAP_BITS_PER_WORD (sizeof(unsigned long) * BITS_PER_BYTE) -#define FD_TABLE_INCR_SIZE 64 - -static struct file_descriptor **fd_table; -static unsigned long *fd_table_bitmap; -static unsigned int fd_table_size; -static unsigned int fd_count; - -#define return_with_errno(err) \ - do { \ - errno = (err); \ - return -1; \ - } while (0) - -static struct file_descriptor *alloc_fd(enum fd_type type, LONG refcount) -{ - struct file_descriptor *fd = calloc(1, sizeof(*fd)); - - if (fd == NULL) - return NULL; - fd->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (fd->overlapped.hEvent == NULL) { - free(fd); - return NULL; - } - fd->type = type; - fd->refcount = refcount; - return fd; -} - -static struct file_descriptor *get_fd(unsigned int _fd, bool ref) -{ - struct file_descriptor *fd = NULL; - - if (_fd < fd_table_size) - fd = fd_table[_fd]; - if (fd != NULL && ref) - InterlockedIncrement(&fd->refcount); - - return fd; -} - -static void put_fd(struct file_descriptor *fd) -{ - if (InterlockedDecrement(&fd->refcount) == 0L) { - CloseHandle(fd->overlapped.hEvent); - free(fd); - } -} - -static int install_fd(struct file_descriptor *fd) -{ - unsigned int n; - - if (fd_count == fd_table_size) { - struct file_descriptor **new_table; - unsigned long *new_bitmap; - - // Need to expand the fd table and bitmap - new_table = realloc(fd_table, (fd_table_size + FD_TABLE_INCR_SIZE) * sizeof(*new_table)); - if (new_table == NULL) - return -ENOMEM; - memset(new_table + fd_table_size, 0, FD_TABLE_INCR_SIZE * sizeof(*new_table)); - fd_table = new_table; - - new_bitmap = realloc(fd_table_bitmap, (fd_table_size + FD_TABLE_INCR_SIZE) / BITS_PER_BYTE); - if (new_bitmap == NULL) - return -ENOMEM; - memset(new_bitmap + (fd_table_size / BITMAP_BITS_PER_WORD), 0, FD_TABLE_INCR_SIZE / BITS_PER_BYTE); - fd_table_bitmap = new_bitmap; - - fd_table_size += FD_TABLE_INCR_SIZE; - assert(fd_table_size < (unsigned int)INT_MAX); - } - - for (n = 0; n < fd_table_size; n += BITMAP_BITS_PER_WORD) { - unsigned int idx = n / BITMAP_BITS_PER_WORD; - ULONG mask, pos = 0U; - unsigned char nonzero; - - mask = ~fd_table_bitmap[idx]; - if (mask == 0U) - continue; - - nonzero = _BitScanForward(&pos, mask); - assert(nonzero); - fd_table_bitmap[idx] |= 1U << pos; - n += pos; - break; - } - - assert(n < fd_table_size); - assert(fd_table[n] == NULL); - fd_table[n] = fd; - fd_count++; - - return n; -} - -static void remove_fd(unsigned int pos) -{ - assert(fd_table[pos] != NULL); - fd_table[pos] = NULL; - fd_table_bitmap[pos / BITMAP_BITS_PER_WORD] &= ~(1U << (pos % BITMAP_BITS_PER_WORD)); - fd_count--; - if (fd_count == 0) { - free(fd_table); - free(fd_table_bitmap); - fd_table = NULL; - fd_table_bitmap = NULL; - fd_table_size = 0; - } -} - -/* - * Create both an fd and an OVERLAPPED, so that it can be used with our - * polling function - * The handle MUST support overlapped transfers (usually requires CreateFile - * with FILE_FLAG_OVERLAPPED) - * Return a pollable file descriptor struct, or INVALID_WINFD on error - * - * Note that the fd returned by this function is a per-transfer fd, rather - * than a per-session fd and cannot be used for anything else but our - * custom functions. - * if you plan to do R/W on the same handle, you MUST create 2 fds: one for - * read and one for write. Using a single R/W fd is unsupported and will - * produce unexpected results - */ -struct winfd usbi_create_fd(void) -{ - struct file_descriptor *fd; - struct winfd wfd; - - fd = alloc_fd(FD_TYPE_TRANSFER, 1); - if (fd == NULL) - return INVALID_WINFD; - - usbi_mutex_static_lock(&fd_table_lock); - wfd.fd = install_fd(fd); - usbi_mutex_static_unlock(&fd_table_lock); - - if (wfd.fd < 0) { - put_fd(fd); - return INVALID_WINFD; - } - - wfd.overlapped = &fd->overlapped; - - return wfd; -} - -struct wait_thread_data { - HANDLE thread; - HANDLE handles[MAXIMUM_WAIT_OBJECTS]; - DWORD num_handles; - DWORD error; -}; - -static DWORD WINAPI WaitThread(LPVOID lpParam) -{ - struct wait_thread_data *thread_data = lpParam; - HANDLE notify_event = thread_data->handles[0]; - DWORD status; - - status = WaitForMultipleObjects(thread_data->num_handles, thread_data->handles, FALSE, INFINITE); - if (status < (WAIT_OBJECT_0 + thread_data->num_handles)) { - if (status > WAIT_OBJECT_0) { - // This will wake up all the other waiting threads - SetEvent(notify_event); - } - thread_data->error = 0; - } else { - assert(status == WAIT_FAILED); - thread_data->error = (status == WAIT_FAILED) ? GetLastError() : ERROR_CAN_NOT_COMPLETE; - } - - return 0; -} - -static DWORD poll_wait(const HANDLE *wait_handles, DWORD num_wait_handles, DWORD timeout) -{ - struct wait_thread_data *thread_data; - HANDLE notify_event; - HANDLE *handles; - int n, num_threads; - DWORD error, status; - - if (num_wait_handles <= MAXIMUM_WAIT_OBJECTS) - return WaitForMultipleObjects(num_wait_handles, wait_handles, FALSE, timeout); - - // To wait on more than MAXIMUM_WAIT_OBJECTS, each thread (including the - // current thread) will wait on an event and (MAXIMUM_WAIT_OBJECTS - 1) - // HANDLEs. The event is shared amongst all threads so that any thread - // that returns from a WaitForMultipleObjects() call will set the event - // and wake up all the other threads. - notify_event = CreateEvent(NULL, FALSE, FALSE, NULL); - if (notify_event == NULL) - return WAIT_FAILED; - - num_threads = 1 + (num_wait_handles - MAXIMUM_WAIT_OBJECTS - 1) / (MAXIMUM_WAIT_OBJECTS - 1); - thread_data = malloc(num_threads * sizeof(*thread_data)); - if (thread_data == NULL) { - CloseHandle(notify_event); - SetLastError(ERROR_OUTOFMEMORY); - return WAIT_FAILED; - } - - handles = _alloca(MAXIMUM_WAIT_OBJECTS * sizeof(HANDLE)); - handles[0] = notify_event; - memcpy(handles + 1, wait_handles, (MAXIMUM_WAIT_OBJECTS - 1) * sizeof(HANDLE)); - wait_handles += MAXIMUM_WAIT_OBJECTS - 1; - num_wait_handles -= MAXIMUM_WAIT_OBJECTS - 1; - - for (n = 0; n < num_threads; n++) { - DWORD copy_size = MIN(num_wait_handles, MAXIMUM_WAIT_OBJECTS - 1); - - thread_data[n].handles[0] = notify_event; - memcpy(thread_data[n].handles + 1, wait_handles, copy_size * sizeof(HANDLE)); - thread_data[n].num_handles = copy_size + 1; - - // Create the thread that will wait on these HANDLEs - thread_data[n].thread = CreateThread(NULL, 0, WaitThread, &thread_data[n], 0, NULL); - if (thread_data[n].thread == NULL) { - thread_data[n].error = GetLastError(); - SetEvent(notify_event); - num_threads = n + 1; - break; - } - - wait_handles += copy_size; - num_wait_handles -= copy_size; - } - - status = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, handles, FALSE, timeout); - if (status < (WAIT_OBJECT_0 + MAXIMUM_WAIT_OBJECTS)) { - if (status > WAIT_OBJECT_0) { - // Wake up all the waiting threads - SetEvent(notify_event); - status = WAIT_OBJECT_0; - } - error = 0; - } else if (status == WAIT_TIMEOUT) { - // Wake up all the waiting threads - SetEvent(notify_event); - error = 0; - } else { - assert(status == WAIT_FAILED); - error = (status == WAIT_FAILED) ? GetLastError() : ERROR_CAN_NOT_COMPLETE; - } - - for (n = 0; n < num_threads; n++) { - if (thread_data[n].thread != NULL) { - if (WaitForSingleObject(thread_data[n].thread, INFINITE) != WAIT_OBJECT_0) - usbi_err(NULL, "WaitForSingleObject() failed: %lu", ULONG_CAST(GetLastError())); - CloseHandle(thread_data[n].thread); - } - if (thread_data[n].error) { - usbi_err(NULL, "wait thread %d had error %lu\n", n, ULONG_CAST(thread_data[n].error)); - error = thread_data[n].error; - status = WAIT_FAILED; - } - } - - free(thread_data); - - CloseHandle(notify_event); - - if (status == WAIT_FAILED) - SetLastError(error); - - return status; -} - -/* - * POSIX poll equivalent, using Windows OVERLAPPED - * Currently, this function only accepts one of POLLIN or POLLOUT per fd - * (but you can create multiple fds from the same handle for read and write) - */ -int usbi_poll(struct pollfd *fds, usbi_nfds_t nfds, int timeout) -{ - struct file_descriptor **fds_array; - HANDLE *handles_array; - struct file_descriptor *fd; - usbi_nfds_t n; - int nready; - - if (nfds <= MAXIMUM_WAIT_OBJECTS) { - fds_array = _alloca(nfds * sizeof(*fds_array)); - handles_array = _alloca(nfds * sizeof(*handles_array)); - } else { - fds_array = malloc(nfds * sizeof(*fds_array)); - if (fds_array == NULL) - return_with_errno(ENOMEM); - handles_array = malloc(nfds * sizeof(*handles_array)); - if (handles_array == NULL) { - free(fds_array); - return_with_errno(ENOMEM); - } - } - - usbi_mutex_static_lock(&fd_table_lock); - for (n = 0; n < nfds; n++) { - struct pollfd *pfd = &fds[n]; - - // Keep it simple - only allow either POLLIN *or* POLLOUT - assert((pfd->events == POLLIN) || (pfd->events == POLLOUT)); - if ((pfd->events != POLLIN) && (pfd->events != POLLOUT)) { - fds_array[n] = NULL; - continue; - } - - // All file descriptors must be valid - fd = get_fd(pfd->fd, true); - assert(fd != NULL); - if (fd == NULL) { - fds_array[n] = NULL; - continue; - } - - // We hold a reference to fd for the duration of usbi_poll() - fds_array[n] = fd; - handles_array[n] = fd->overlapped.hEvent; - } - usbi_mutex_static_unlock(&fd_table_lock); - - nready = 0; - while (nready == 0) { - DWORD ret; - - // Check all fds for events - for (n = 0; n < nfds; n++) { - fd = fds_array[n]; - if (fd == NULL) { - fds[n].revents = POLLNVAL; - nready++; - } else if (HasOverlappedIoCompleted(&fd->overlapped)) { - fds[n].revents = fds[n].events; - nready++; - } else { - fds[n].revents = 0; - } - } - - if ((nready != 0) || (timeout == 0)) - break; - - // Wait for any of the events to trigger - ret = poll_wait(handles_array, nfds, (timeout < 0) ? INFINITE : (DWORD)timeout); - if (ret == WAIT_TIMEOUT) { - assert(timeout > 0); - timeout = 0; - } else if (ret == WAIT_FAILED) { - usbi_err(NULL, "WaitForMultipleObjects failed: %lu", ULONG_CAST(GetLastError())); - errno = EIO; - nready = -1; - } - } - - for (n = 0; n < nfds; n++) { - if (fds_array[n] != NULL) - put_fd(fds_array[n]); - } - - if (nfds > MAXIMUM_WAIT_OBJECTS) { - free(handles_array); - free(fds_array); - } - - return nready; -} - -/* - * close a fake file descriptor - */ -int usbi_close(int _fd) -{ - struct file_descriptor *fd; - - usbi_mutex_static_lock(&fd_table_lock); - fd = get_fd(_fd, false); - if (fd != NULL) - remove_fd(_fd); - usbi_mutex_static_unlock(&fd_table_lock); - - if (fd == NULL) - return_with_errno(EBADF); - - put_fd(fd); - - return 0; -} - -/* -* Create a fake pipe. -* As libusb only uses pipes for signaling, all we need from a pipe is an -* event. To that extent, we create a single wfd and overlapped as a means -* to access that event. -*/ -int usbi_pipe(int filedes[2]) -{ - struct file_descriptor *fd; - int r_fd, w_fd; - int error = 0; - - fd = alloc_fd(FD_TYPE_PIPE, 2); - if (fd == NULL) - return_with_errno(ENOMEM); - - fd->overlapped.Internal = STATUS_PENDING; - - usbi_mutex_static_lock(&fd_table_lock); - r_fd = install_fd(fd); - if (r_fd >= 0) { - w_fd = install_fd(fd); - if (w_fd < 0) { - remove_fd(r_fd); - error = w_fd; - } - } else { - error = r_fd; - w_fd = -1; // Keep compiler happy - } - usbi_mutex_static_unlock(&fd_table_lock); - - if (error) { - CloseHandle(fd->overlapped.hEvent); - free(fd); - return_with_errno(error); - } - - filedes[0] = r_fd; - filedes[1] = w_fd; - - return 0; -} - -/* - * synchronous write for fake "pipe" signaling - */ -ssize_t usbi_write(int _fd, const void *buf, size_t count) -{ - struct file_descriptor *fd; - - UNUSED(buf); - - if (count != sizeof(unsigned char)) { - usbi_err(NULL, "this function should only used for signaling"); - return_with_errno(EINVAL); - } - - usbi_mutex_static_lock(&fd_table_lock); - fd = get_fd(_fd, false); - if (fd && fd->type == FD_TYPE_PIPE) { - assert(fd->overlapped.Internal == STATUS_PENDING); - fd->overlapped.Internal = STATUS_WAIT_0; - SetEvent(fd->overlapped.hEvent); - } else { - fd = NULL; - } - usbi_mutex_static_unlock(&fd_table_lock); - - if (fd == NULL) - return_with_errno(EBADF); - - return sizeof(unsigned char); -} - -/* - * synchronous read for fake "pipe" signaling - */ -ssize_t usbi_read(int _fd, void *buf, size_t count) -{ - struct file_descriptor *fd; - - UNUSED(buf); - - if (count != sizeof(unsigned char)) { - usbi_err(NULL, "this function should only used for signaling"); - return_with_errno(EINVAL); - } - - usbi_mutex_static_lock(&fd_table_lock); - fd = get_fd(_fd, false); - if (fd && fd->type == FD_TYPE_PIPE) { - assert(fd->overlapped.Internal == STATUS_WAIT_0); - fd->overlapped.Internal = STATUS_PENDING; - ResetEvent(fd->overlapped.hEvent); - } else { - fd = NULL; - } - usbi_mutex_static_unlock(&fd_table_lock); - - if (fd == NULL) - return_with_errno(EBADF); - - return sizeof(unsigned char); -} diff --git a/libusb/os/poll_windows.h b/libusb/os/poll_windows.h deleted file mode 100644 index df1781b..0000000 --- a/libusb/os/poll_windows.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Windows compat: POSIX compatibility wrapper - * Copyright © 2012-2013 RealVNC Ltd. - * Copyright © 2009-2010 Pete Batard <pete@akeo.ie> - * Copyright © 2016-2018 Chris Dickens <christopher.a.dickens@gmail.com> - * With contributions from Michael Plante, Orin Eman et al. - * Parts of poll implementation from libusb-win32, by Stephan Meyer et al. - * - * 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_POLL_WINDOWS_H -#define LIBUSB_POLL_WINDOWS_H - -#define DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2) - -#define POLLIN 0x0001 /* There is data to read */ -#define POLLPRI 0x0002 /* There is urgent data to read */ -#define POLLOUT 0x0004 /* Writing now will not block */ -#define POLLERR 0x0008 /* Error condition */ -#define POLLHUP 0x0010 /* Hung up */ -#define POLLNVAL 0x0020 /* Invalid request: fd not open */ - -typedef unsigned int usbi_nfds_t; - -struct pollfd { - int fd; /* file descriptor */ - short events; /* requested events */ - short revents; /* returned events */ -}; - -struct winfd { - int fd; // what's exposed to libusb core - OVERLAPPED *overlapped; // what will report our I/O status -}; - -extern const struct winfd INVALID_WINFD; - -struct winfd usbi_create_fd(void); - -int usbi_pipe(int pipefd[2]); -int usbi_poll(struct pollfd *fds, usbi_nfds_t nfds, int timeout); -ssize_t usbi_write(int fd, const void *buf, size_t count); -ssize_t usbi_read(int fd, void *buf, size_t count); -int usbi_close(int fd); - -#endif diff --git a/libusb/os/sunos_usb.c b/libusb/os/sunos_usb.c index 3e2fb4f..46866fb 100644 --- a/libusb/os/sunos_usb.c +++ b/libusb/os/sunos_usb.c @@ -37,7 +37,6 @@ #include <sys/usb/clients/ugen/usb_ugen.h> #include <sys/usb/usba.h> #include <sys/pci.h> -#include <inttypes.h> #include "libusbi.h" #include "sunos_usb.h" @@ -248,8 +247,10 @@ sunos_new_string_list(void) if (list == NULL) return (NULL); list->string = calloc(DEFAULT_LISTSIZE, sizeof(char *)); - if (list->string == NULL) + if (list->string == NULL) { + free(list); return (NULL); + } list->nargs = 0; list->listsize = DEFAULT_LISTSIZE; @@ -618,7 +619,7 @@ sunos_add_devices(di_devlink_t link, void *arg) if (sunos_fill_in_dev_info(dn, dev) != LIBUSB_SUCCESS) { libusb_unref_device(dev); - usbi_dbg("get infomation fail"); + usbi_dbg("get information fail"); continue; } if (usbi_sanitize_device(dev) < 0) { diff --git a/libusb/os/threads_posix.c b/libusb/os/threads_posix.c index 71a404f..0e0e221 100644 --- a/libusb/os/threads_posix.c +++ b/libusb/os/threads_posix.c @@ -21,6 +21,7 @@ #include "libusbi.h" +#include <errno.h> #if defined(__ANDROID__) # include <unistd.h> #elif defined(__HAIKU__) @@ -38,36 +39,55 @@ # include <sys/lwp.h> #endif +void usbi_cond_init(pthread_cond_t *cond) +{ +#ifdef HAVE_PTHREAD_CONDATTR_SETCLOCK + pthread_condattr_t condattr; + + PTHREAD_CHECK(pthread_condattr_init(&condattr)); + PTHREAD_CHECK(pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC)); + PTHREAD_CHECK(pthread_cond_init(cond, &condattr)); + PTHREAD_CHECK(pthread_condattr_destroy(&condattr)); +#else + PTHREAD_CHECK(pthread_cond_init(cond, NULL)); +#endif +} + int usbi_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timeval *tv) { struct timespec timeout; int r; - r = usbi_clock_gettime(USBI_CLOCK_REALTIME, &timeout); - if (r < 0) - return r; +#ifdef HAVE_PTHREAD_CONDATTR_SETCLOCK + usbi_get_monotonic_time(&timeout); +#else + usbi_get_real_time(&timeout); +#endif timeout.tv_sec += tv->tv_sec; - timeout.tv_nsec += tv->tv_usec * 1000; - while (timeout.tv_nsec >= 1000000000L) { - timeout.tv_nsec -= 1000000000L; + timeout.tv_nsec += tv->tv_usec * 1000L; + if (timeout.tv_nsec >= NSEC_PER_SEC) { + timeout.tv_nsec -= NSEC_PER_SEC; timeout.tv_sec++; } - return pthread_cond_timedwait(cond, mutex, &timeout); + r = pthread_cond_timedwait(cond, mutex, &timeout); + if (r == 0) + return 0; + else if (r == ETIMEDOUT) + return LIBUSB_ERROR_TIMEOUT; + else + return LIBUSB_ERROR_OTHER; } -int usbi_get_tid(void) +unsigned int usbi_get_tid(void) { -#ifndef _WIN32 - static _Thread_local int tid; - - if (tid) - return tid; -#else + static _Thread_local unsigned int tl_tid; int tid; -#endif + + if (tl_tid) + return tl_tid; #if defined(__ANDROID__) tid = gettid(); @@ -94,8 +114,6 @@ int usbi_get_tid(void) tid = syscall(SYS_getthrid); #elif defined(__sun__) tid = _lwp_self(); -#elif defined(_WIN32) - tid = (int)GetCurrentThreadId(); #else tid = -1; #endif @@ -107,5 +125,5 @@ int usbi_get_tid(void) tid = (int)(intptr_t)pthread_self(); } - return tid; + return tl_tid = (unsigned int)tid; } diff --git a/libusb/os/threads_posix.h b/libusb/os/threads_posix.h index eadb978..9322834 100644 --- a/libusb/os/threads_posix.h +++ b/libusb/os/threads_posix.h @@ -23,63 +23,62 @@ #include <pthread.h> +#define PTHREAD_CHECK(expression) ASSERT_EQ(expression, 0) + #define USBI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER typedef pthread_mutex_t usbi_mutex_static_t; static inline void usbi_mutex_static_lock(usbi_mutex_static_t *mutex) { - (void)pthread_mutex_lock(mutex); + PTHREAD_CHECK(pthread_mutex_lock(mutex)); } static inline void usbi_mutex_static_unlock(usbi_mutex_static_t *mutex) { - (void)pthread_mutex_unlock(mutex); + PTHREAD_CHECK(pthread_mutex_unlock(mutex)); } typedef pthread_mutex_t usbi_mutex_t; -static inline int usbi_mutex_init(usbi_mutex_t *mutex) +static inline void usbi_mutex_init(usbi_mutex_t *mutex) { - return pthread_mutex_init(mutex, NULL); + PTHREAD_CHECK(pthread_mutex_init(mutex, NULL)); } static inline void usbi_mutex_lock(usbi_mutex_t *mutex) { - (void)pthread_mutex_lock(mutex); + PTHREAD_CHECK(pthread_mutex_lock(mutex)); } static inline void usbi_mutex_unlock(usbi_mutex_t *mutex) { - (void)pthread_mutex_unlock(mutex); + PTHREAD_CHECK(pthread_mutex_unlock(mutex)); } static inline int usbi_mutex_trylock(usbi_mutex_t *mutex) { - return pthread_mutex_trylock(mutex); + return pthread_mutex_trylock(mutex) == 0; } static inline void usbi_mutex_destroy(usbi_mutex_t *mutex) { - (void)pthread_mutex_destroy(mutex); + PTHREAD_CHECK(pthread_mutex_destroy(mutex)); } typedef pthread_cond_t usbi_cond_t; -static inline void usbi_cond_init(pthread_cond_t *cond) -{ - (void)pthread_cond_init(cond, NULL); -} +void usbi_cond_init(pthread_cond_t *cond); static inline void usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex) { - (void)pthread_cond_wait(cond, mutex); + PTHREAD_CHECK(pthread_cond_wait(cond, mutex)); } int usbi_cond_timedwait(usbi_cond_t *cond, usbi_mutex_t *mutex, const struct timeval *tv); static inline void usbi_cond_broadcast(usbi_cond_t *cond) { - (void)pthread_cond_broadcast(cond); + PTHREAD_CHECK(pthread_cond_broadcast(cond)); } static inline void usbi_cond_destroy(usbi_cond_t *cond) { - (void)pthread_cond_destroy(cond); + PTHREAD_CHECK(pthread_cond_destroy(cond)); } typedef pthread_key_t usbi_tls_key_t; static inline void usbi_tls_key_create(usbi_tls_key_t *key) { - (void)pthread_key_create(key, NULL); + PTHREAD_CHECK(pthread_key_create(key, NULL)); } static inline void *usbi_tls_key_get(usbi_tls_key_t key) { @@ -87,13 +86,13 @@ static inline void *usbi_tls_key_get(usbi_tls_key_t key) } static inline void usbi_tls_key_set(usbi_tls_key_t key, void *ptr) { - (void)pthread_setspecific(key, ptr); + PTHREAD_CHECK(pthread_setspecific(key, ptr)); } static inline void usbi_tls_key_delete(usbi_tls_key_t key) { - (void)pthread_key_delete(key); + PTHREAD_CHECK(pthread_key_delete(key)); } -int usbi_get_tid(void); +unsigned int usbi_get_tid(void); #endif /* LIBUSB_THREADS_POSIX_H */ diff --git a/libusb/os/threads_windows.c b/libusb/os/threads_windows.c index cf72694..4a57f42 100644 --- a/libusb/os/threads_windows.c +++ b/libusb/os/threads_windows.c @@ -34,7 +34,7 @@ int usbi_cond_timedwait(usbi_cond_t *cond, if (SleepConditionVariableCS(cond, mutex, millis)) return 0; else if (GetLastError() == ERROR_TIMEOUT) - return ETIMEDOUT; + return LIBUSB_ERROR_TIMEOUT; else - return EINVAL; + return LIBUSB_ERROR_OTHER; } diff --git a/libusb/os/threads_windows.h b/libusb/os/threads_windows.h index 618c2f3..dfef158 100644 --- a/libusb/os/threads_windows.h +++ b/libusb/os/threads_windows.h @@ -21,7 +21,7 @@ #ifndef LIBUSB_THREADS_WINDOWS_H #define LIBUSB_THREADS_WINDOWS_H -#include <errno.h> +#define WINAPI_CHECK(expression) ASSERT_NE(expression, 0) #define USBI_MUTEX_INITIALIZER 0L typedef LONG usbi_mutex_static_t; @@ -36,10 +36,9 @@ static inline void usbi_mutex_static_unlock(usbi_mutex_static_t *mutex) } typedef CRITICAL_SECTION usbi_mutex_t; -static inline int usbi_mutex_init(usbi_mutex_t *mutex) +static inline void usbi_mutex_init(usbi_mutex_t *mutex) { InitializeCriticalSection(mutex); - return 0; } static inline void usbi_mutex_lock(usbi_mutex_t *mutex) { @@ -51,14 +50,13 @@ static inline void usbi_mutex_unlock(usbi_mutex_t *mutex) } static inline int usbi_mutex_trylock(usbi_mutex_t *mutex) { - return !TryEnterCriticalSection(mutex); + return TryEnterCriticalSection(mutex) != 0; } static inline void usbi_mutex_destroy(usbi_mutex_t *mutex) { DeleteCriticalSection(mutex); } -// We *were* getting timespec from pthread.h: #if !defined(HAVE_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED) #define HAVE_STRUCT_TIMESPEC 1 #define _TIMESPEC_DEFINED 1 @@ -68,11 +66,6 @@ struct timespec { }; #endif /* HAVE_STRUCT_TIMESPEC || _TIMESPEC_DEFINED */ -// We *were* getting ETIMEDOUT from pthread.h: -#ifndef ETIMEDOUT -#define ETIMEDOUT 10060 /* This is the value in winsock.h. */ -#endif - typedef CONDITION_VARIABLE usbi_cond_t; static inline void usbi_cond_init(usbi_cond_t *cond) { @@ -80,7 +73,7 @@ static inline void usbi_cond_init(usbi_cond_t *cond) } static inline void usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex) { - (void)SleepConditionVariableCS(cond, mutex, INFINITE); + WINAPI_CHECK(SleepConditionVariableCS(cond, mutex, INFINITE)); } int usbi_cond_timedwait(usbi_cond_t *cond, usbi_mutex_t *mutex, const struct timeval *tv); @@ -97,6 +90,7 @@ typedef DWORD usbi_tls_key_t; static inline void usbi_tls_key_create(usbi_tls_key_t *key) { *key = TlsAlloc(); + assert(*key != TLS_OUT_OF_INDEXES); } static inline void *usbi_tls_key_get(usbi_tls_key_t key) { @@ -104,16 +98,16 @@ static inline void *usbi_tls_key_get(usbi_tls_key_t key) } static inline void usbi_tls_key_set(usbi_tls_key_t key, void *ptr) { - (void)TlsSetValue(key, ptr); + WINAPI_CHECK(TlsSetValue(key, ptr)); } static inline void usbi_tls_key_delete(usbi_tls_key_t key) { - (void)TlsFree(key); + WINAPI_CHECK(TlsFree(key)); } -static inline int usbi_get_tid(void) +static inline unsigned int usbi_get_tid(void) { - return (int)GetCurrentThreadId(); + return (unsigned int)GetCurrentThreadId(); } #endif /* LIBUSB_THREADS_WINDOWS_H */ diff --git a/libusb/os/windows_common.c b/libusb/os/windows_common.c index ccf20b2..119ed49 100644 --- a/libusb/os/windows_common.c +++ b/libusb/os/windows_common.c @@ -24,8 +24,6 @@ #include <config.h> -#include <errno.h> -#include <inttypes.h> #include <process.h> #include <stdio.h> @@ -39,16 +37,10 @@ // Public enum windows_version windows_version = WINDOWS_UNDEFINED; - // Global variables for init/exit +// Global variables for init/exit static unsigned int init_count; static bool usbdk_available; -#if !defined(HAVE_CLOCK_GETTIME) -// Global variables for clock_gettime mechanism -static uint64_t hires_ticks_to_ps; -static uint64_t hires_frequency; -#endif - /* * Converts a windows error to human readable string * uses retval as errorcode, or, if 0, use GetLastError() @@ -103,6 +95,35 @@ const char *windows_error_str(DWORD error_code) } #endif +/* + * Dynamically loads a DLL from the Windows system directory. Unlike the + * LoadLibraryA() function, this function will not search through any + * directories to try and find the library. + */ +HMODULE load_system_library(struct libusb_context *ctx, const char *name) +{ + char library_path[MAX_PATH]; + char *filename_start; + UINT length; + + length = GetSystemDirectoryA(library_path, sizeof(library_path)); + if ((length == 0) || (length >= (UINT)sizeof(library_path))) { + usbi_err(ctx, "program assertion failed - could not get system directory"); + return NULL; + } + + filename_start = library_path + length; + // Append '\' + name + ".dll" + NUL + length += 1 + (UINT)strlen(name) + 4 + 1; + if (length >= (UINT)sizeof(library_path)) { + usbi_err(ctx, "program assertion failed - library path buffer overflow"); + return NULL; + } + + sprintf(filename_start, "\\%s.dll", name); + return LoadLibraryA(library_path); +} + /* 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) */ @@ -125,7 +146,7 @@ static unsigned long htab_filled; static bool htab_create(struct libusb_context *ctx) { if (htab_table != NULL) { - usbi_err(ctx, "program assertion falied - hash table already allocated"); + usbi_err(ctx, "program assertion failed - hash table already allocated"); return true; } @@ -269,30 +290,19 @@ enum libusb_transfer_status usbd_status_to_libusb_transfer_status(USBD_STATUS st } /* -* Make a transfer complete synchronously -*/ -void windows_force_sync_completion(OVERLAPPED *overlapped, ULONG size) + * Make a transfer complete synchronously + */ +void windows_force_sync_completion(struct usbi_transfer *itransfer, ULONG size) { + struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer); + OVERLAPPED *overlapped = &transfer_priv->overlapped; + + usbi_dbg("transfer %p, length %lu", USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer), ULONG_CAST(size)); + overlapped->Internal = (ULONG_PTR)STATUS_SUCCESS; overlapped->InternalHigh = (ULONG_PTR)size; - SetEvent(overlapped->hEvent); -} -static void windows_init_clock(void) -{ -#if !defined(HAVE_CLOCK_GETTIME) - LARGE_INTEGER li_frequency; - - // Microsoft says that the QueryPerformanceFrequency() and - // QueryPerformanceCounter() functions always succeed on XP and later - QueryPerformanceFrequency(&li_frequency); - - // 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 frequency: %"PRIu64" Hz", hires_frequency); -#endif + usbi_signal_transfer_completion(itransfer); } /* Windows version detection */ @@ -310,27 +320,26 @@ static BOOL is_x64(void) return ret; } -static void get_windows_version(void) +static enum windows_version get_windows_version(void) { + enum windows_version winver; OSVERSIONINFOEXA vi, vi2; - const char *arch, *w = NULL; unsigned major, minor, version; ULONGLONG major_equal, minor_equal; + const char *w, *arch; bool ws; - windows_version = WINDOWS_UNDEFINED; - 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; + return WINDOWS_UNDEFINED; } if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT) - return; + return WINDOWS_UNDEFINED; 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 @@ -366,27 +375,25 @@ static void get_windows_version(void) } if ((vi.dwMajorVersion > 0xf) || (vi.dwMinorVersion > 0xf)) - return; + return WINDOWS_UNDEFINED; ws = (vi.wProductType <= VER_NT_WORKSTATION); version = vi.dwMajorVersion << 4 | vi.dwMinorVersion; switch (version) { - case 0x50: windows_version = WINDOWS_2000; w = "2000"; break; - case 0x51: windows_version = WINDOWS_XP; w = "XP"; break; - case 0x52: windows_version = WINDOWS_2003; w = "2003"; break; - case 0x60: windows_version = WINDOWS_VISTA; w = (ws ? "Vista" : "2008"); break; - case 0x61: windows_version = WINDOWS_7; w = (ws ? "7" : "2008_R2"); break; - case 0x62: windows_version = WINDOWS_8; w = (ws ? "8" : "2012"); break; - case 0x63: windows_version = WINDOWS_8_1; w = (ws ? "8.1" : "2012_R2"); break; + case 0x50: winver = WINDOWS_2000; w = "2000"; break; + case 0x51: winver = WINDOWS_XP; w = "XP"; break; + case 0x52: winver = WINDOWS_2003; w = "2003"; break; + case 0x60: winver = WINDOWS_VISTA; w = (ws ? "Vista" : "2008"); break; + case 0x61: winver = WINDOWS_7; w = (ws ? "7" : "2008_R2"); break; + case 0x62: winver = WINDOWS_8; w = (ws ? "8" : "2012"); break; + case 0x63: winver = WINDOWS_8_1; w = (ws ? "8.1" : "2012_R2"); break; case 0x64: // Early Windows 10 Insider Previews and Windows Server 2017 Technical Preview 1 used version 6.4 - case 0xA0: windows_version = WINDOWS_10; w = (ws ? "10" : "2016"); break; + case 0xA0: winver = WINDOWS_10; w = (ws ? "10" : "2016"); break; default: - if (version < 0x50) { - return; - } else { - windows_version = WINDOWS_11_OR_LATER; - w = "11 or later"; - } + if (version < 0x50) + return WINDOWS_UNDEFINED; + winver = WINDOWS_11_OR_LATER; + w = "11 or later"; } arch = is_x64() ? "64-bit" : "32-bit"; @@ -397,62 +404,47 @@ static void get_windows_version(void) usbi_dbg("Windows %s SP%u %s", w, vi.wServicePackMajor, arch); else usbi_dbg("Windows %s %s", w, arch); + + return winver; } -static void windows_transfer_callback(const struct windows_backend *backend, - struct usbi_transfer *itransfer, DWORD error, DWORD bytes_transferred) +static unsigned __stdcall windows_iocp_thread(void *arg) { - struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer); - enum libusb_transfer_status status, istatus; + struct libusb_context *ctx = arg; + struct windows_context_priv *priv = usbi_get_context_priv(ctx); + HANDLE iocp = priv->completion_port; + DWORD num_bytes; + ULONG_PTR completion_key; + OVERLAPPED *overlapped; + struct windows_transfer_priv *transfer_priv; + struct usbi_transfer *itransfer; - usbi_dbg("handling I/O completion with errcode %lu, length %lu", - ULONG_CAST(error), ULONG_CAST(bytes_transferred)); + usbi_dbg("I/O completion thread started"); - switch (error) { - case NO_ERROR: - status = backend->copy_transfer_data(itransfer, bytes_transferred); - 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 = backend->copy_transfer_data(itransfer, bytes_transferred); - if (istatus != LIBUSB_TRANSFER_COMPLETED) - usbi_dbg("failed to copy partial data in aborted operation: %d", (int)istatus); + while (true) { + overlapped = NULL; + if (!GetQueuedCompletionStatus(iocp, &num_bytes, &completion_key, &overlapped, INFINITE) && (overlapped == NULL)) { + usbi_err(ctx, "GetQueuedCompletionStatus failed: %s", windows_error_str(0)); + break; + } - usbi_dbg("detected operation aborted"); - status = LIBUSB_TRANSFER_CANCELLED; - break; - case ERROR_FILE_NOT_FOUND: - case ERROR_DEVICE_NOT_CONNECTED: - case ERROR_NO_SUCH_DEVICE: - usbi_dbg("detected device removed"); - status = LIBUSB_TRANSFER_NO_DEVICE; - break; - default: - usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error %lu: %s", - ULONG_CAST(error), windows_error_str(error)); - status = LIBUSB_TRANSFER_ERROR; - break; - } + if (overlapped == NULL) { + // Signal to quit + if (completion_key != (ULONG_PTR)ctx) + usbi_err(ctx, "program assertion failed - overlapped is NULL"); + break; + } - // Cancel polling - usbi_close(transfer_priv->pollable_fd.fd); - transfer_priv->pollable_fd = INVALID_WINFD; - transfer_priv->handle = NULL; + transfer_priv = container_of(overlapped, struct windows_transfer_priv, overlapped); + itransfer = (struct usbi_transfer *)((unsigned char *)transfer_priv + PTR_ALIGN(sizeof(*transfer_priv))); + usbi_dbg("transfer %p completed, length %lu", + USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer), ULONG_CAST(num_bytes)); + usbi_signal_transfer_completion(itransfer); + } - // Backend-specific cleanup - backend->clear_transfer_priv(itransfer); + usbi_dbg("I/O completion thread exiting"); - if (status == LIBUSB_TRANSFER_CANCELLED) - usbi_handle_transfer_cancellation(itransfer); - else - usbi_handle_transfer_completion(itransfer, status); + return 0; } static int windows_init(struct libusb_context *ctx) @@ -460,8 +452,8 @@ static int windows_init(struct libusb_context *ctx) struct windows_context_priv *priv = usbi_get_context_priv(ctx); char mutex_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0' HANDLE mutex; - int r = LIBUSB_ERROR_OTHER; bool winusb_backend_init = false; + int r; sprintf(mutex_name, "libusb_init%08lX", ULONG_CAST(GetCurrentProcessId() & 0xFFFFFFFFU)); mutex = CreateMutexA(NULL, FALSE, mutex_name); @@ -471,7 +463,7 @@ static int windows_init(struct libusb_context *ctx) } // A successful wait gives this thread ownership of the mutex - // => any concurent wait stalls until the mutex is released + // => any concurrent wait stalls until the mutex is released if (WaitForSingleObject(mutex, INFINITE) != WAIT_OBJECT_0) { usbi_err(ctx, "failure to access mutex: %s", windows_error_str(0)); CloseHandle(mutex); @@ -481,18 +473,21 @@ static int windows_init(struct libusb_context *ctx) // 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 (++init_count == 1) { // First init? - get_windows_version(); - + windows_version = get_windows_version(); if (windows_version == WINDOWS_UNDEFINED) { usbi_err(ctx, "failed to detect Windows version"); r = LIBUSB_ERROR_NOT_SUPPORTED; goto init_exit; + } else if (windows_version < WINDOWS_VISTA) { + usbi_err(ctx, "Windows version is too old"); + r = LIBUSB_ERROR_NOT_SUPPORTED; + goto init_exit; } - windows_init_clock(); - - if (!htab_create(ctx)) + if (!htab_create(ctx)) { + r = LIBUSB_ERROR_NO_MEM; goto init_exit; + } r = winusb_backend.init(ctx); if (r != LIBUSB_SUCCESS) @@ -506,17 +501,37 @@ static int windows_init(struct libusb_context *ctx) } else { usbi_info(ctx, "UsbDk backend is not available"); // Do not report this as an error - r = LIBUSB_SUCCESS; } } // By default, new contexts will use the WinUSB backend priv->backend = &winusb_backend; + r = LIBUSB_ERROR_NO_MEM; + + // Use an I/O completion port to manage all transfers for this context + priv->completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); + if (priv->completion_port == NULL) { + usbi_err(ctx, "failed to create I/O completion port: %s", windows_error_str(0)); + goto init_exit; + } + + // And a dedicated thread to wait for I/O completions + priv->completion_port_thread = (HANDLE)_beginthreadex(NULL, 0, windows_iocp_thread, ctx, 0, NULL); + if (priv->completion_port_thread == NULL) { + usbi_err(ctx, "failed to create I/O completion port thread"); + CloseHandle(priv->completion_port); + goto init_exit; + } + r = LIBUSB_SUCCESS; init_exit: // Holds semaphore here if ((init_count == 1) && (r != LIBUSB_SUCCESS)) { // First init failed? + if (usbdk_available) { + usbdk_backend.exit(ctx); + usbdk_available = false; + } if (winusb_backend_init) winusb_backend.exit(ctx); htab_destroy(); @@ -530,6 +545,7 @@ init_exit: // Holds semaphore here static void windows_exit(struct libusb_context *ctx) { + struct windows_context_priv *priv = usbi_get_context_priv(ctx); char mutex_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0' HANDLE mutex; @@ -539,13 +555,23 @@ static void windows_exit(struct libusb_context *ctx) return; // A successful wait gives this thread ownership of the mutex - // => any concurent wait stalls until the mutex is released + // => any concurrent wait stalls until the mutex is released if (WaitForSingleObject(mutex, INFINITE) != WAIT_OBJECT_0) { usbi_err(ctx, "failed to access mutex: %s", windows_error_str(0)); CloseHandle(mutex); return; } + // A NULL completion status will indicate to the thread that it is time to exit + if (!PostQueuedCompletionStatus(priv->completion_port, 0, (ULONG_PTR)ctx, NULL)) + usbi_err(ctx, "failed to post I/O completion: %s", windows_error_str(0)); + + if (WaitForSingleObject(priv->completion_port_thread, INFINITE) == WAIT_FAILED) + usbi_err(ctx, "failed to wait for I/O completion port thread: %s", windows_error_str(0)); + + CloseHandle(priv->completion_port_thread); + CloseHandle(priv->completion_port); + // Only works if exits and inits are balanced exactly if (--init_count == 0) { // Last exit if (usbdk_available) { @@ -566,19 +592,17 @@ static int windows_set_option(struct libusb_context *ctx, enum libusb_option opt UNUSED(ap); - switch ((int)option) { - case LIBUSB_OPTION_USE_USBDK: - if (usbdk_available) { - usbi_dbg("switching context %p to use UsbDk backend", ctx); - priv->backend = &usbdk_backend; - } else { + if (option == LIBUSB_OPTION_USE_USBDK) { + if (!usbdk_available) { usbi_err(ctx, "UsbDk backend not available"); return LIBUSB_ERROR_NOT_FOUND; } + usbi_dbg("switching context %p to use UsbDk backend", ctx); + priv->backend = &usbdk_backend; return LIBUSB_SUCCESS; - default: - return LIBUSB_ERROR_NOT_SUPPORTED; } + + return LIBUSB_ERROR_NOT_SUPPORTED; } static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **discdevs) @@ -677,17 +701,13 @@ static int windows_submit_transfer(struct usbi_transfer *itransfer) struct libusb_context *ctx = TRANSFER_CTX(transfer); struct windows_context_priv *priv = usbi_get_context_priv(ctx); struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer); - short events; int r; switch (transfer->type) { case LIBUSB_TRANSFER_TYPE_CONTROL: - events = (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) ? POLLIN : POLLOUT; - break; case LIBUSB_TRANSFER_TYPE_BULK: case LIBUSB_TRANSFER_TYPE_INTERRUPT: case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - events = IS_XFERIN(transfer) ? POLLIN : POLLOUT; break; case LIBUSB_TRANSFER_TYPE_BULK_STREAM: usbi_warn(ctx, "bulk stream transfers are not yet supported on this platform"); @@ -697,14 +717,6 @@ static int windows_submit_transfer(struct usbi_transfer *itransfer) return LIBUSB_ERROR_INVALID_PARAM; } - // Because a Windows OVERLAPPED is used for poll emulation, - // a pollable fd is created and stored with each transfer - transfer_priv->pollable_fd = usbi_create_fd(); - if (transfer_priv->pollable_fd.fd < 0) { - usbi_err(ctx, "failed to create pollable fd"); - return LIBUSB_ERROR_NO_MEM; - } - if (transfer_priv->handle != NULL) { usbi_err(ctx, "program assertion failed - transfer HANDLE is not NULL"); transfer_priv->handle = NULL; @@ -714,9 +726,6 @@ static int windows_submit_transfer(struct usbi_transfer *itransfer) if (r != LIBUSB_SUCCESS) { // Always call the backend's clear_transfer_priv() function on failure priv->backend->clear_transfer_priv(itransfer); - // Release the pollable fd since it won't be used - usbi_close(transfer_priv->pollable_fd.fd); - transfer_priv->pollable_fd = INVALID_WINFD; transfer_priv->handle = NULL; return r; } @@ -726,16 +735,6 @@ static int windows_submit_transfer(struct usbi_transfer *itransfer) if (transfer_priv->handle == NULL) usbi_err(ctx, "program assertion failed - transfer HANDLE is NULL after transfer was submitted"); - // We don't want to start monitoring the pollable fd before the transfer - // has been submitted, so start monitoring it now. Note that if the - // usbi_add_pollfd() function fails, the user will never get notified - // that the transfer has completed. We don't attempt any cleanup if this - // happens because the transfer is already in progress and could even have - // completed - if (usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, events)) - usbi_err(ctx, "failed to add pollable fd %d for transfer %p", - transfer_priv->pollable_fd.fd, transfer); - return r; } @@ -747,7 +746,7 @@ static int windows_cancel_transfer(struct usbi_transfer *itransfer) // Try CancelIoEx() on the transfer // If that fails, fall back to the backend's cancel_transfer() // function if it is available - if (CancelIoEx(transfer_priv->handle, transfer_priv->pollable_fd.overlapped)) + if (CancelIoEx(transfer_priv->handle, &transfer_priv->overlapped)) return LIBUSB_SUCCESS; else if (GetLastError() == ERROR_NOT_FOUND) return LIBUSB_ERROR_NOT_FOUND; @@ -759,98 +758,91 @@ static int windows_cancel_transfer(struct usbi_transfer *itransfer) return LIBUSB_ERROR_NOT_SUPPORTED; } -static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, usbi_nfds_t nfds, int num_ready) +static int windows_handle_transfer_completion(struct usbi_transfer *itransfer) { + struct libusb_context *ctx = ITRANSFER_CTX(itransfer); struct windows_context_priv *priv = usbi_get_context_priv(ctx); - struct usbi_transfer *itransfer; - struct windows_transfer_priv *transfer_priv; + const struct windows_backend *backend = priv->backend; + struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer); + enum libusb_transfer_status status, istatus; DWORD result, bytes_transferred; - usbi_nfds_t i; - 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; + if (GetOverlappedResult(transfer_priv->handle, &transfer_priv->overlapped, &bytes_transferred, FALSE)) + result = NO_ERROR; + else + result = GetLastError(); - num_ready--; + usbi_dbg("handling transfer %p completion with errcode %lu, length %lu", + USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer), ULONG_CAST(result), ULONG_CAST(bytes_transferred)); - transfer_priv = NULL; - usbi_mutex_lock(&ctx->flying_transfers_lock); - list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) { - transfer_priv = usbi_get_transfer_priv(itransfer); - if (transfer_priv->pollable_fd.fd == fds[i].fd) - break; - transfer_priv = NULL; - } - usbi_mutex_unlock(&ctx->flying_transfers_lock); - - if (transfer_priv == NULL) { - usbi_err(ctx, "could not find a matching transfer for fd %d", fds[i].fd); - r = LIBUSB_ERROR_NOT_FOUND; - break; - } + switch (result) { + case NO_ERROR: + status = backend->copy_transfer_data(itransfer, bytes_transferred); + 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 = backend->copy_transfer_data(itransfer, bytes_transferred); + if (istatus != LIBUSB_TRANSFER_COMPLETED) + usbi_dbg("failed to copy partial data in aborted operation: %d", (int)istatus); - usbi_remove_pollfd(ctx, transfer_priv->pollable_fd.fd); + usbi_dbg("detected operation aborted"); + status = LIBUSB_TRANSFER_CANCELLED; + break; + case ERROR_FILE_NOT_FOUND: + case ERROR_DEVICE_NOT_CONNECTED: + case ERROR_NO_SUCH_DEVICE: + usbi_dbg("detected device removed"); + status = LIBUSB_TRANSFER_NO_DEVICE; + break; + default: + usbi_err(ctx, "detected I/O error %lu: %s", + ULONG_CAST(result), windows_error_str(result)); + status = LIBUSB_TRANSFER_ERROR; + break; + } - if (GetOverlappedResult(transfer_priv->handle, transfer_priv->pollable_fd.overlapped, &bytes_transferred, FALSE)) - result = NO_ERROR; - else - result = GetLastError(); + transfer_priv->handle = NULL; - windows_transfer_callback(priv->backend, itransfer, result, bytes_transferred); - } - usbi_mutex_unlock(&ctx->open_devs_lock); + // Backend-specific cleanup + backend->clear_transfer_priv(itransfer); - return r; + if (status == LIBUSB_TRANSFER_CANCELLED) + return usbi_handle_transfer_cancellation(itransfer); + else + return usbi_handle_transfer_completion(itransfer, status); } -#if !defined(HAVE_CLOCK_GETTIME) -int usbi_clock_gettime(int clk_id, struct timespec *tp) +void usbi_get_monotonic_time(struct timespec *tp) { + static LONG hires_counter_init; + static uint64_t hires_ticks_to_ps; + static uint64_t hires_frequency; LARGE_INTEGER hires_counter; -#if !defined(_MSC_VER) || (_MSC_VER < 1900) - FILETIME filetime; - ULARGE_INTEGER rtime; -#endif - switch (clk_id) { - case USBI_CLOCK_MONOTONIC: - if (hires_frequency) { - QueryPerformanceCounter(&hires_counter); - tp->tv_sec = (long)(hires_counter.QuadPart / hires_frequency); - tp->tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency) * hires_ticks_to_ps) / UINT64_C(1000)); - return 0; - } - // Return real-time if monotonic was not detected @ timer init - // Fall through - case USBI_CLOCK_REALTIME: -#if defined(_MSC_VER) && (_MSC_VER >= 1900) - if (!timespec_get(tp, TIME_UTC)) { - errno = EIO; - return -1; - } -#else - // 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); -#endif - return 0; - default: - errno = EINVAL; - return -1; + if (InterlockedExchange(&hires_counter_init, 1L) == 0L) { + LARGE_INTEGER li_frequency; + + // Microsoft says that the QueryPerformanceFrequency() and + // QueryPerformanceCounter() functions always succeed on XP and later + QueryPerformanceFrequency(&li_frequency); + + // The hires frequency can go as high as 4 GHz, so we'll use a conversion + // to picoseconds to compute the tv_nsecs part + hires_frequency = li_frequency.QuadPart; + hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency; } + + QueryPerformanceCounter(&hires_counter); + tp->tv_sec = (long)(hires_counter.QuadPart / hires_frequency); + tp->tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency) * hires_ticks_to_ps) / UINT64_C(1000)); } -#endif // NB: MSVC6 does not support named initializers. const struct usbi_os_backend usbi_backend = { @@ -885,8 +877,8 @@ const struct usbi_os_backend usbi_backend = { windows_submit_transfer, windows_cancel_transfer, NULL, /* clear_transfer_priv */ - windows_handle_events, - NULL, /* handle_transfer_completion */ + NULL, /* handle_events */ + windows_handle_transfer_completion, sizeof(struct windows_context_priv), sizeof(union windows_device_priv), sizeof(union windows_device_handle_priv), diff --git a/libusb/os/windows_common.h b/libusb/os/windows_common.h index 00cdda3..0c4b94c 100644 --- a/libusb/os/windows_common.h +++ b/libusb/os/windows_common.h @@ -47,7 +47,7 @@ #define ULONG_CAST(x) ((unsigned long)(x)) #endif -#if defined(__CYGWIN__ ) +#if defined(__CYGWIN__) #define _stricmp strcasecmp #define _strdup strdup // _beginthreadex is MSVCRT => unavailable for cygwin. Fallback to using CreateThread @@ -60,29 +60,29 @@ * API macros - leveraged from libusb-win32 1.x */ #define DLL_STRINGIFY(s) #s -#define DLL_LOAD_LIBRARY(name) LoadLibraryA(DLL_STRINGIFY(name)) /* * Macros for handling DLL themselves */ #define DLL_HANDLE_NAME(name) __dll_##name##_handle -#define DLL_DECLARE_HANDLE(name) \ +#define DLL_DECLARE_HANDLE(name) \ static HMODULE DLL_HANDLE_NAME(name) -#define DLL_GET_HANDLE(name) \ - do { \ - DLL_HANDLE_NAME(name) = DLL_LOAD_LIBRARY(name); \ - if (!DLL_HANDLE_NAME(name)) \ - return false; \ +#define DLL_GET_HANDLE(ctx, name) \ + do { \ + DLL_HANDLE_NAME(name) = load_system_library(ctx, \ + DLL_STRINGIFY(name)); \ + if (!DLL_HANDLE_NAME(name)) \ + return false; \ } while (0) -#define DLL_FREE_HANDLE(name) \ - do { \ - if (DLL_HANDLE_NAME(name)) { \ - FreeLibrary(DLL_HANDLE_NAME(name)); \ - DLL_HANDLE_NAME(name) = NULL; \ - } \ +#define DLL_FREE_HANDLE(name) \ + do { \ + if (DLL_HANDLE_NAME(name)) { \ + FreeLibrary(DLL_HANDLE_NAME(name)); \ + DLL_HANDLE_NAME(name) = NULL; \ + } \ } while (0) /* @@ -327,6 +327,8 @@ struct windows_backend { struct windows_context_priv { const struct windows_backend *backend; + HANDLE completion_port; + HANDLE completion_port_thread; }; union windows_device_priv { @@ -340,7 +342,7 @@ union windows_device_handle_priv { }; struct windows_transfer_priv { - struct winfd pollable_fd; + OVERLAPPED overlapped; HANDLE handle; union { struct usbdk_transfer_priv usbdk_priv; @@ -351,7 +353,7 @@ struct windows_transfer_priv { static inline OVERLAPPED *get_transfer_priv_overlapped(struct usbi_transfer *itransfer) { struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer); - return transfer_priv->pollable_fd.overlapped; + return &transfer_priv->overlapped; } static inline void set_transfer_priv_handle(struct usbi_transfer *itransfer, HANDLE handle) @@ -375,9 +377,10 @@ static inline struct winusb_transfer_priv *get_winusb_transfer_priv(struct usbi_ extern const struct windows_backend usbdk_backend; extern const struct windows_backend winusb_backend; +HMODULE load_system_library(struct libusb_context *ctx, const char *name); unsigned long htab_hash(const char *str); enum libusb_transfer_status usbd_status_to_libusb_transfer_status(USBD_STATUS status); -void windows_force_sync_completion(OVERLAPPED *overlapped, ULONG size); +void windows_force_sync_completion(struct usbi_transfer *itransfer, ULONG size); #if defined(ENABLE_LOGGING) const char *windows_error_str(DWORD error_code); diff --git a/libusb/os/windows_usbdk.c b/libusb/os/windows_usbdk.c index d9e2a9c..c9ebfcf 100644 --- a/libusb/os/windows_usbdk.c +++ b/libusb/os/windows_usbdk.c @@ -81,7 +81,7 @@ static void unload_usbdk_helper_dll(void) static int load_usbdk_helper_dll(struct libusb_context *ctx) { - usbdk_helper.module = LoadLibraryA("UsbDkHelper"); + usbdk_helper.module = load_system_library(ctx, "UsbDkHelper"); if (usbdk_helper.module == NULL) { usbi_err(ctx, "Failed to load UsbDkHelper.dll: %s", windows_error_str(0)); return LIBUSB_ERROR_NOT_FOUND; @@ -160,7 +160,7 @@ static int usbdk_init(struct libusb_context *ctx) SC_HANDLE serviceHandle; HMODULE h; - h = LoadLibraryA("Advapi32"); + h = load_system_library(ctx, "Advapi32"); if (h == NULL) { usbi_warn(ctx, "failed to open Advapi32\n"); return LIBUSB_ERROR_OTHER; @@ -400,15 +400,27 @@ static int usbdk_get_active_config_descriptor(struct libusb_device *dev, void *b static int usbdk_open(struct libusb_device_handle *dev_handle) { - struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev); - - priv->redirector_handle = usbdk_helper.StartRedirect(&priv->ID); - if (priv->redirector_handle == INVALID_HANDLE_VALUE) { - usbi_err(HANDLE_CTX(dev_handle), "Redirector startup failed"); + struct libusb_device *dev = dev_handle->dev; + struct libusb_context *ctx = DEVICE_CTX(dev); + struct windows_context_priv *priv = usbi_get_context_priv(ctx); + struct usbdk_device_priv *device_priv = usbi_get_device_priv(dev); + + device_priv->redirector_handle = usbdk_helper.StartRedirect(&device_priv->ID); + if (device_priv->redirector_handle == INVALID_HANDLE_VALUE) { + usbi_err(ctx, "Redirector startup failed"); + device_priv->redirector_handle = NULL; return LIBUSB_ERROR_OTHER; } - priv->system_handle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle); + device_priv->system_handle = usbdk_helper.GetRedirectorSystemHandle(device_priv->redirector_handle); + + if (CreateIoCompletionPort(device_priv->system_handle, priv->completion_port, 0, 0) == NULL) { + usbi_err(ctx, "failed to associate handle to I/O completion port: %s", windows_error_str(0)); + usbdk_helper.StopRedirect(device_priv->redirector_handle); + device_priv->system_handle = NULL; + device_priv->redirector_handle = NULL; + return LIBUSB_ERROR_OTHER; + } return LIBUSB_SUCCESS; } @@ -419,6 +431,9 @@ static void usbdk_close(struct libusb_device_handle *dev_handle) if (!usbdk_helper.StopRedirect(priv->redirector_handle)) usbi_err(HANDLE_CTX(dev_handle), "Redirector shutdown failed"); + + priv->system_handle = NULL; + priv->redirector_handle = NULL; } static int usbdk_get_configuration(struct libusb_device_handle *dev_handle, uint8_t *config) @@ -518,6 +533,8 @@ static int usbdk_do_control_transfer(struct usbi_transfer *itransfer) transfer_priv->request.BufferLength = transfer->length; transfer_priv->request.TransferType = ControlTransferType; + set_transfer_priv_handle(itransfer, priv->system_handle); + if (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped); else @@ -525,7 +542,7 @@ static int usbdk_do_control_transfer(struct usbi_transfer *itransfer) switch (transResult) { case TransferSuccess: - windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred); + windows_force_sync_completion(itransfer, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred); break; case TransferSuccessAsync: break; @@ -534,8 +551,6 @@ static int usbdk_do_control_transfer(struct usbi_transfer *itransfer) return LIBUSB_ERROR_IO; } - set_transfer_priv_handle(itransfer, priv->system_handle); - return LIBUSB_SUCCESS; } @@ -560,6 +575,8 @@ static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer) break; } + set_transfer_priv_handle(itransfer, priv->system_handle); + if (IS_XFERIN(transfer)) transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped); else @@ -567,7 +584,7 @@ static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer) switch (transferRes) { case TransferSuccess: - windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred); + windows_force_sync_completion(itransfer, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred); break; case TransferSuccessAsync: break; @@ -576,8 +593,6 @@ static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer) return LIBUSB_ERROR_IO; } - set_transfer_priv_handle(itransfer, priv->system_handle); - return LIBUSB_SUCCESS; } @@ -612,6 +627,8 @@ static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer) for (i = 0; i < transfer->num_iso_packets; i++) transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length; + set_transfer_priv_handle(itransfer, priv->system_handle); + if (IS_XFERIN(transfer)) transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped); else @@ -619,7 +636,7 @@ static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer) switch (transferRes) { case TransferSuccess: - windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred); + windows_force_sync_completion(itransfer, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred); break; case TransferSuccessAsync: break; @@ -627,8 +644,6 @@ static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer) return LIBUSB_ERROR_IO; } - set_transfer_priv_handle(itransfer, priv->system_handle); - return LIBUSB_SUCCESS; } diff --git a/libusb/os/windows_winusb.c b/libusb/os/windows_winusb.c index 8ea9697..f291b8e 100644 --- a/libusb/os/windows_winusb.c +++ b/libusb/os/windows_winusb.c @@ -28,11 +28,9 @@ #include <windows.h> #include <setupapi.h> #include <ctype.h> -#include <errno.h> #include <fcntl.h> #include <process.h> #include <stdio.h> -#include <inttypes.h> #include <objbase.h> #include <winioctl.h> @@ -148,21 +146,21 @@ static char *normalize_path(const char *path) /* * Cfgmgr32, AdvAPI32, OLE32 and SetupAPI DLL functions */ -static bool init_dlls(void) +static bool init_dlls(struct libusb_context *ctx) { - DLL_GET_HANDLE(Cfgmgr32); + DLL_GET_HANDLE(ctx, Cfgmgr32); DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Parent, true); DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Child, true); // Prefixed to avoid conflict with header files - DLL_GET_HANDLE(AdvAPI32); + DLL_GET_HANDLE(ctx, AdvAPI32); DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExW, true); DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegCloseKey, true); - DLL_GET_HANDLE(OLE32); + DLL_GET_HANDLE(ctx, OLE32); DLL_LOAD_FUNC_PREFIXED(OLE32, p, IIDFromString, true); - DLL_GET_HANDLE(SetupAPI); + DLL_GET_HANDLE(ctx, 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); @@ -465,6 +463,28 @@ static int get_interface_by_endpoint(struct libusb_config_descriptor *conf_desc, } /* + * Open a device and associate the HANDLE with the context's I/O completion port + */ +static HANDLE windows_open(struct libusb_device *dev, const char *path, DWORD access) +{ + struct libusb_context *ctx = DEVICE_CTX(dev); + struct windows_context_priv *priv = usbi_get_context_priv(ctx); + HANDLE handle; + + handle = CreateFileA(path, access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + if (handle == INVALID_HANDLE_VALUE) + return handle; + + if (CreateIoCompletionPort(handle, priv->completion_port, 0, 0) == NULL) { + usbi_err(ctx, "failed to associate handle to I/O completion port: %s", windows_error_str(0)); + CloseHandle(handle); + return INVALID_HANDLE_VALUE; + } + + return handle; +} + +/* * Populate the endpoints addresses of the device_priv interface helper structs */ static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting) @@ -623,7 +643,7 @@ static int winusb_init(struct libusb_context *ctx) int i; // Load DLL imports - if (!init_dlls()) { + if (!init_dlls(ctx)) { usbi_err(ctx, "could not resolve DLL functions"); return LIBUSB_ERROR_OTHER; } @@ -758,6 +778,243 @@ static void cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handl } } +#define ROOT_HUB_FS_CONFIG_DESC_LENGTH 0x19 +#define ROOT_HUB_HS_CONFIG_DESC_LENGTH 0x19 +#define ROOT_HUB_SS_CONFIG_DESC_LENGTH 0x1f +#define CONFIG_DESC_WTOTAL_LENGTH_OFFSET 0x02 +#define CONFIG_DESC_EP_MAX_PACKET_OFFSET 0x16 +#define CONFIG_DESC_EP_BINTERVAL_OFFSET 0x18 + +static const uint8_t root_hub_config_descriptor_template[] = { + // Configuration Descriptor + LIBUSB_DT_CONFIG_SIZE, // bLength + LIBUSB_DT_CONFIG, // bDescriptorType + 0x00, 0x00, // wTotalLength (filled in) + 0x01, // bNumInterfaces + 0x01, // bConfigurationValue + 0x00, // iConfiguration + 0xc0, // bmAttributes (reserved + self-powered) + 0x00, // bMaxPower + // Interface Descriptor + LIBUSB_DT_INTERFACE_SIZE, // bLength + LIBUSB_DT_INTERFACE, // bDescriptorType + 0x00, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x01, // bNumEndpoints + LIBUSB_CLASS_HUB, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0x00, // iInterface + // Endpoint Descriptor + LIBUSB_DT_ENDPOINT_SIZE, // bLength + LIBUSB_DT_ENDPOINT, // bDescriptorType + 0x81, // bEndpointAddress + 0x03, // bmAttributes (Interrupt) + 0x00, 0x00, // wMaxPacketSize (filled in) + 0x00, // bInterval (filled in) + // SuperSpeed Endpoint Companion Descriptor + LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE, // bLength + LIBUSB_DT_SS_ENDPOINT_COMPANION, // bDescriptorType + 0x00, // bMaxBurst + 0x00, // bmAttributes + 0x02, 0x00 // wBytesPerInterval +}; + +static int alloc_root_hub_config_desc(struct libusb_device *dev, ULONG num_ports, + uint8_t config_desc_length, uint8_t ep_interval) +{ + struct winusb_device_priv *priv = usbi_get_device_priv(dev); + uint8_t *ptr; + + priv->config_descriptor = malloc(sizeof(*priv->config_descriptor)); + if (priv->config_descriptor == NULL) + return LIBUSB_ERROR_NO_MEM; + + // Most config descriptors come from cache_config_descriptors() which obtains the + // descriptors from the hub using an allocated USB_DESCRIPTOR_REQUEST structure. + // To avoid an extra malloc + memcpy we just hold on to the USB_DESCRIPTOR_REQUEST + // structure we already have and back up the pointer in windows_device_priv_release() + // when freeing the descriptors. To keep a single execution path, we need to offset + // the pointer here by the same amount. + ptr = malloc(USB_DESCRIPTOR_REQUEST_SIZE + config_desc_length); + if (ptr == NULL) + return LIBUSB_ERROR_NO_MEM; + + ptr += USB_DESCRIPTOR_REQUEST_SIZE; + + memcpy(ptr, root_hub_config_descriptor_template, config_desc_length); + ptr[CONFIG_DESC_WTOTAL_LENGTH_OFFSET] = config_desc_length; + ptr[CONFIG_DESC_EP_MAX_PACKET_OFFSET] = (uint8_t)((num_ports + 7) / 8); + ptr[CONFIG_DESC_EP_BINTERVAL_OFFSET] = ep_interval; + + priv->config_descriptor[0] = (PUSB_CONFIGURATION_DESCRIPTOR)ptr; + priv->active_config = 1; + + return 0; +} + +static int init_root_hub(struct libusb_device *dev) +{ + struct libusb_context *ctx = DEVICE_CTX(dev); + struct winusb_device_priv *priv = usbi_get_device_priv(dev); + USB_NODE_CONNECTION_INFORMATION_EX conn_info; + USB_NODE_CONNECTION_INFORMATION_EX_V2 conn_info_v2; + USB_NODE_INFORMATION hub_info; + enum libusb_speed speed = LIBUSB_SPEED_UNKNOWN; + uint8_t config_desc_length; + uint8_t ep_interval; + HANDLE handle; + ULONG port_number, num_ports; + DWORD size; + int r; + + // Determining the speed of a root hub is painful. Microsoft does not directly report the speed + // capabilities of the root hub itself, only its ports and/or connected devices. Therefore we + // are forced to query each individual port of the root hub to try and infer the root hub's + // speed. Note that we have to query all ports because the presence of a device on that port + // changes if/how Windows returns any useful speed information. + handle = CreateFileA(priv->path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + if (handle == INVALID_HANDLE_VALUE) { + usbi_err(ctx, "could not open root hub %s: %s", priv->path, windows_error_str(0)); + return LIBUSB_ERROR_ACCESS; + } + + if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_INFORMATION, NULL, 0, &hub_info, sizeof(hub_info), &size, NULL)) { + usbi_warn(ctx, "could not get root hub info for '%s': %s", priv->dev_id, windows_error_str(0)); + CloseHandle(handle); + return LIBUSB_ERROR_ACCESS; + } + + num_ports = hub_info.u.HubInformation.HubDescriptor.bNumberOfPorts; + usbi_dbg("root hub '%s' reports %lu ports", priv->dev_id, ULONG_CAST(num_ports)); + + if (windows_version >= WINDOWS_8) { + // Windows 8 and later is better at reporting the speed capabilities of the root hub, + // but it is not perfect. If no device is attached to the port being queried, the + // returned information will only indicate whether that port supports USB 3.0 signalling. + // That is not enough information to distinguish between SuperSpeed and SuperSpeed Plus. + for (port_number = 1; port_number <= num_ports; port_number++) { + conn_info_v2.ConnectionIndex = port_number; + conn_info_v2.Length = sizeof(conn_info_v2); + conn_info_v2.SupportedUsbProtocols.Usb300 = 1; + if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2, + &conn_info_v2, sizeof(conn_info_v2), &conn_info_v2, sizeof(conn_info_v2), &size, NULL)) { + usbi_warn(ctx, "could not get node connection information (V2) for root hub '%s' port %lu: %s", + priv->dev_id, ULONG_CAST(port_number), windows_error_str(0)); + break; + } + + if (conn_info_v2.Flags.DeviceIsSuperSpeedPlusCapableOrHigher) + speed = MAX(speed, LIBUSB_SPEED_SUPER_PLUS); + else if (conn_info_v2.Flags.DeviceIsSuperSpeedCapableOrHigher || conn_info_v2.SupportedUsbProtocols.Usb300) + speed = MAX(speed, LIBUSB_SPEED_SUPER); + else if (conn_info_v2.SupportedUsbProtocols.Usb200) + speed = MAX(speed, LIBUSB_SPEED_HIGH); + else + speed = MAX(speed, LIBUSB_SPEED_FULL); + } + + if (speed != LIBUSB_SPEED_UNKNOWN) + goto make_descriptors; + } + + // At this point the speed is still not known, most likely because we are executing on + // Windows 7 or earlier. The following hackery peeks into the root hub's Device ID and + // tries to extract speed information from it, based on observed naming conventions. + // If this does not work, we will query individual ports of the root hub. + if (strstr(priv->dev_id, "ROOT_HUB31") != NULL) + speed = LIBUSB_SPEED_SUPER_PLUS; + else if (strstr(priv->dev_id, "ROOT_HUB30") != NULL) + speed = LIBUSB_SPEED_SUPER; + else if (strstr(priv->dev_id, "ROOT_HUB20") != NULL) + speed = LIBUSB_SPEED_HIGH; + + if (speed != LIBUSB_SPEED_UNKNOWN) + goto make_descriptors; + + // Windows only reports speed information about a connected device. This means that a root + // hub with no connected devices or devices that are all operating at a speed less than the + // highest speed that the root hub supports will not give us the correct speed. + for (port_number = 1; port_number <= num_ports; port_number++) { + conn_info.ConnectionIndex = port_number; + if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, sizeof(conn_info), + &conn_info, sizeof(conn_info), &size, NULL)) { + usbi_warn(ctx, "could not get node connection information for root hub '%s' port %lu: %s", + priv->dev_id, ULONG_CAST(port_number), windows_error_str(0)); + continue; + } + + if (conn_info.ConnectionStatus != DeviceConnected) + continue; + + if (conn_info.Speed == UsbHighSpeed) { + speed = LIBUSB_SPEED_HIGH; + break; + } + } + +make_descriptors: + CloseHandle(handle); + + dev->device_descriptor.bLength = LIBUSB_DT_DEVICE_SIZE; + dev->device_descriptor.bDescriptorType = LIBUSB_DT_DEVICE; + dev->device_descriptor.bDeviceClass = LIBUSB_CLASS_HUB; + if ((dev->device_descriptor.idVendor == 0) && (dev->device_descriptor.idProduct == 0)) { + dev->device_descriptor.idVendor = 0x1d6b; // Linux Foundation + dev->device_descriptor.idProduct = (uint16_t)speed; + } + dev->device_descriptor.bcdDevice = 0x0100; + dev->device_descriptor.bNumConfigurations = 1; + + switch (speed) { + case LIBUSB_SPEED_SUPER_PLUS: + dev->device_descriptor.bcdUSB = 0x0310; + config_desc_length = ROOT_HUB_SS_CONFIG_DESC_LENGTH; + ep_interval = 0x0c; // 256ms + break; + case LIBUSB_SPEED_SUPER: + dev->device_descriptor.bcdUSB = 0x0300; + config_desc_length = ROOT_HUB_SS_CONFIG_DESC_LENGTH; + ep_interval = 0x0c; // 256ms + break; + case LIBUSB_SPEED_HIGH: + dev->device_descriptor.bcdUSB = 0x0200; + config_desc_length = ROOT_HUB_HS_CONFIG_DESC_LENGTH; + ep_interval = 0x0c; // 256ms + break; + case LIBUSB_SPEED_LOW: // Not used, but keeps compiler happy + case LIBUSB_SPEED_UNKNOWN: + // This case means absolutely no information about this root hub was determined. + // There is not much choice than to be pessimistic and label this as a + // full-speed device. + speed = LIBUSB_SPEED_FULL; + // fallthrough + case LIBUSB_SPEED_FULL: + dev->device_descriptor.bcdUSB = 0x0110; + config_desc_length = ROOT_HUB_FS_CONFIG_DESC_LENGTH; + ep_interval = 0xff; // 255ms + break; + default: // Impossible, buts keeps compiler happy + usbi_err(ctx, "program assertion failed - unknown root hub speed"); + return LIBUSB_ERROR_INVALID_PARAM; + } + + if (speed >= LIBUSB_SPEED_SUPER) { + dev->device_descriptor.bDeviceProtocol = 0x03; // USB 3.0 Hub + dev->device_descriptor.bMaxPacketSize0 = 0x09; // 2^9 bytes + } else { + dev->device_descriptor.bMaxPacketSize0 = 0x40; // 64 bytes + } + + dev->speed = speed; + + r = alloc_root_hub_config_desc(dev, num_ports, config_desc_length, ep_interval); + if (r) + usbi_err(ctx, "could not allocate config descriptor for root hub '%s'", priv->dev_id); + + return r; +} + /* * Populate a libusb device structure */ @@ -801,6 +1058,10 @@ static int init_device(struct libusb_device *dev, struct libusb_device *parent_d for (depth = 1; bus_number == 0; depth++) { tmp_dev = get_ancestor(ctx, devinst, &devinst); + if (tmp_dev == NULL) { + usbi_warn(ctx, "ancestor for device '%s' not found at depth %u", priv->dev_id, depth); + return LIBUSB_ERROR_NO_DEVICE; + } if (tmp_dev->bus_number != 0) { bus_number = tmp_dev->bus_number; tmp_priv = usbi_get_device_priv(tmp_dev); @@ -822,8 +1083,7 @@ static int init_device(struct libusb_device *dev, struct libusb_device *parent_d dev->parent_dev = parent_dev; priv->depth = depth; - hub_handle = CreateFileA(parent_priv->path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - 0, NULL); + hub_handle = CreateFileA(parent_priv->path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hub_handle == INVALID_HANDLE_VALUE) { usbi_warn(ctx, "could not open hub %s: %s", parent_priv->path, windows_error_str(0)); return LIBUSB_ERROR_ACCESS; @@ -847,6 +1107,12 @@ static int init_device(struct libusb_device *dev, struct libusb_device *parent_d return LIBUSB_ERROR_NO_DEVICE; } + if ((conn_info.DeviceDescriptor.bLength != LIBUSB_DT_DEVICE_SIZE) + || (conn_info.DeviceDescriptor.bDescriptorType != LIBUSB_DT_DEVICE)) { + SleepEx(50, TRUE); + continue; + } + static_assert(sizeof(dev->device_descriptor) == sizeof(conn_info.DeviceDescriptor), "mismatch between libusb and OS device descriptor sizes"); memcpy(&dev->device_descriptor, &conn_info.DeviceDescriptor, LIBUSB_DT_DEVICE_SIZE); @@ -862,6 +1128,13 @@ static int init_device(struct libusb_device *dev, struct libusb_device *parent_d } } while (priv->active_config == 0 && --ginfotimeout >= 0); + if ((conn_info.DeviceDescriptor.bLength != LIBUSB_DT_DEVICE_SIZE) + || (conn_info.DeviceDescriptor.bDescriptorType != LIBUSB_DT_DEVICE)) { + usbi_err(ctx, "device '%s' has invalid descriptor!", priv->dev_id); + CloseHandle(hub_handle); + return LIBUSB_ERROR_OTHER; + } + if (priv->active_config == 0) { usbi_info(ctx, "0x%x:0x%x found %u configurations but device isn't configured, " "forcing current configuration to 1", @@ -884,11 +1157,11 @@ static int init_device(struct libusb_device *dev, struct libusb_device *parent_d if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2, &conn_info_v2, sizeof(conn_info_v2), &conn_info_v2, sizeof(conn_info_v2), &size, NULL)) { usbi_warn(ctx, "could not get node connection information (V2) for device '%s': %s", - priv->dev_id, windows_error_str(0)); + priv->dev_id, windows_error_str(0)); } else if (conn_info_v2.Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher) { - conn_info.Speed = 4; + conn_info.Speed = UsbSuperSpeedPlus; } else if (conn_info_v2.Flags.DeviceIsOperatingAtSuperSpeedOrHigher) { - conn_info.Speed = 3; + conn_info.Speed = UsbSuperSpeed; } } @@ -900,15 +1173,19 @@ static int init_device(struct libusb_device *dev, struct libusb_device *parent_d dev->device_address = (uint8_t)conn_info.DeviceAddress; 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; - case 4: dev->speed = LIBUSB_SPEED_SUPER_PLUS; break; + case UsbLowSpeed: dev->speed = LIBUSB_SPEED_LOW; break; + case UsbFullSpeed: dev->speed = LIBUSB_SPEED_FULL; break; + case UsbHighSpeed: dev->speed = LIBUSB_SPEED_HIGH; break; + case UsbSuperSpeed: dev->speed = LIBUSB_SPEED_SUPER; break; + case UsbSuperSpeedPlus: dev->speed = LIBUSB_SPEED_SUPER_PLUS; break; default: usbi_warn(ctx, "unknown device speed %u", conn_info.Speed); break; } + } else { + r = init_root_hub(dev); + if (r) + return r; } r = usbi_sanitize_device(dev); @@ -946,19 +1223,13 @@ static int enumerate_hcd_root_hub(struct libusb_context *ctx, const char *dev_id if (dev->bus_number == 0) { // Only do this once usbi_dbg("assigning HCD '%s' bus number %u", dev_id, bus_number); - priv = usbi_get_device_priv(dev); dev->bus_number = bus_number; - dev->device_descriptor.bLength = LIBUSB_DT_DEVICE_SIZE; - dev->device_descriptor.bDescriptorType = LIBUSB_DT_DEVICE; - dev->device_descriptor.bDeviceClass = LIBUSB_CLASS_HUB; - dev->device_descriptor.bNumConfigurations = 1; - priv->active_config = 1; - priv->root_hub = true; - if (sscanf(dev_id, "PCI\\VEN_%04hx&DEV_%04hx%*s", &dev->device_descriptor.idVendor, &dev->device_descriptor.idProduct) != 2) { + + if (sscanf(dev_id, "PCI\\VEN_%04hx&DEV_%04hx%*s", &dev->device_descriptor.idVendor, &dev->device_descriptor.idProduct) != 2) usbi_warn(ctx, "could not infer VID/PID of HCD root hub from '%s'", dev_id); - dev->device_descriptor.idVendor = 0x1d6b; // Linux Foundation root hub - dev->device_descriptor.idProduct = 1; - } + + priv = usbi_get_device_priv(dev); + priv->root_hub = true; } libusb_unref_device(dev); @@ -990,7 +1261,7 @@ static void get_api_type(HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, // 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 + // (currently ';'), so even if an unsupported 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; @@ -1466,9 +1737,10 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_ 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 + } else { + // Failed to initialize a single device doesn't stop us from enumerating all other devices, + // but we skip it (don't add to list of discovered devices) + usbi_warn(ctx, "failed to initialize device '%s'", priv->dev_id); r = LIBUSB_SUCCESS; } break; @@ -1941,7 +2213,7 @@ static bool winusbx_init(struct libusb_context *ctx) { HMODULE hWinUSB, hlibusbK; - hWinUSB = LoadLibraryA("WinUSB"); + hWinUSB = load_system_library(ctx, "WinUSB"); if (hWinUSB != NULL) { WinUSB_Set(hWinUSB, AbortPipe, true); WinUSB_Set(hWinUSB, ControlTransfer, true); @@ -1980,7 +2252,7 @@ cleanup_winusb: usbi_info(ctx, "WinUSB DLL is not available"); } - hlibusbK = LoadLibraryA("libusbK"); + hlibusbK = load_system_library(ctx, "libusbK"); if (hlibusbK != NULL) { LibK_GetVersion_t pLibK_GetVersion; LibK_GetProcAddress_t pLibK_GetProcAddress; @@ -2090,8 +2362,7 @@ static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle) 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_FLAG_OVERLAPPED, NULL); + file_handle = windows_open(dev_handle->dev, priv->usb_interface[i].path, GENERIC_READ | GENERIC_WRITE); if (file_handle == INVALID_HANDLE_VALUE) { usbi_err(HANDLE_CTX(dev_handle), "could not open device %s (interface %d): %s", priv->usb_interface[i].path, i, windows_error_str(0)); switch (GetLastError()) { @@ -2103,6 +2374,7 @@ static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle) return LIBUSB_ERROR_IO; } } + handle_priv->interface_handle[i].dev_handle = file_handle; } } @@ -2262,8 +2534,7 @@ static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev *dev_interface_path_guid_start = '\0'; if (strncmp(dev_interface_path, priv->usb_interface[iface].path, strlen(dev_interface_path)) == 0) { - file_handle = CreateFileA(filter_path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + file_handle = windows_open(dev_handle->dev, filter_path, GENERIC_READ | GENERIC_WRITE); if (file_handle != INVALID_HANDLE_VALUE) { if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) { // Replace the existing file handle with the working one @@ -2457,9 +2728,9 @@ static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *it && (setup->Request == LIBUSB_REQUEST_SET_CONFIGURATION)) { if (setup->Value != priv->active_config) { usbi_warn(TRANSFER_CTX(transfer), "cannot set configuration other than the default one"); - return LIBUSB_ERROR_INVALID_PARAM; + return LIBUSB_ERROR_NOT_SUPPORTED; } - windows_force_sync_completion(overlapped, 0); + windows_force_sync_completion(itransfer, 0); } else { if (!WinUSBX[sub_api].ControlTransfer(winusb_handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, overlapped)) { if (GetLastError() != ERROR_IO_PENDING) { @@ -2680,7 +2951,7 @@ static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itrans } // Important note: the WinUSB_Read/WriteIsochPipeAsap API requires a ContinueStream parameter that tells whether the isochronous - // stream must be continued or if the WinUSB driver can schedule the transfer at its conveniance. Profiling subsequent transfers + // stream must be continued or if the WinUSB driver can schedule the transfer at its convenience. Profiling subsequent transfers // with ContinueStream = FALSE showed that 5 frames, i.e. about 5 milliseconds, were left empty between each transfer. This // is critical as this greatly diminish the achievable isochronous bandwidth. We solved the problem using the following strategy: // - Transfers are first scheduled with ContinueStream = TRUE and with winusbx_iso_transfer_continue_stream_callback as user callback. @@ -3342,9 +3613,7 @@ static int _hid_class_request(struct libusb_device *dev, HANDLE hid_handle, int */ static bool hid_init(struct libusb_context *ctx) { - UNUSED(ctx); - - DLL_GET_HANDLE(hid); + DLL_GET_HANDLE(ctx, hid); DLL_LOAD_FUNC(hid, HidD_GetAttributes, true); DLL_LOAD_FUNC(hid, HidD_GetHidGuid, true); @@ -3393,15 +3662,14 @@ static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) CHECK_HID_AVAILABLE; if (priv->hid == NULL) { - usbi_err(HANDLE_CTX(dev_handle), "program assertion failed - private HID structure is unitialized"); + usbi_err(HANDLE_CTX(dev_handle), "program assertion failed - private HID structure is uninitialized"); 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_FLAG_OVERLAPPED, NULL); + hid_handle = windows_open(dev, priv->usb_interface[i].path, GENERIC_READ | GENERIC_WRITE); /* * 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 @@ -3411,8 +3679,7 @@ static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) */ if (hid_handle == INVALID_HANDLE_VALUE) { usbi_warn(HANDLE_CTX(dev_handle), "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_FLAG_OVERLAPPED, NULL); + hid_handle = windows_open(dev, priv->usb_interface[i].path, 0); if (hid_handle == INVALID_HANDLE_VALUE) { usbi_err(HANDLE_CTX(dev_handle), "could not open device %s (interface %d): %s", priv->path, i, windows_error_str(0)); switch (GetLastError()) { @@ -3692,7 +3959,7 @@ static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itrans if (r == LIBUSB_COMPLETED) { // Force request to be completed synchronously. Transferred size has been set by previous call - windows_force_sync_completion(overlapped, (ULONG)size); + windows_force_sync_completion(itransfer, (ULONG)size); r = LIBUSB_SUCCESS; } diff --git a/libusb/os/windows_winusb.h b/libusb/os/windows_winusb.h index 88863ff..49355d4 100644 --- a/libusb/os/windows_winusb.h +++ b/libusb/os/windows_winusb.h @@ -283,6 +283,9 @@ DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_ DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDeviceInterfaceRegKey, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, DWORD, DWORD)); +#ifndef USB_GET_NODE_INFORMATION +#define USB_GET_NODE_INFORMATION 258 +#endif #ifndef USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION #define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260 #endif @@ -300,6 +303,9 @@ DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDeviceInterfaceRegKey, (HD #define USB_CTL_CODE(id) \ CTL_CODE(FILE_DEVICE_USB, (id), METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_USB_GET_NODE_INFORMATION \ + USB_CTL_CODE(USB_GET_NODE_INFORMATION) + #define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \ USB_CTL_CODE(USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION) @@ -309,7 +315,7 @@ DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDeviceInterfaceRegKey, (HD #define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 \ USB_CTL_CODE(USB_GET_NODE_CONNECTION_INFORMATION_EX_V2) -typedef enum USB_CONNECTION_STATUS { +typedef enum _USB_CONNECTION_STATUS { NoDeviceConnected, DeviceConnected, DeviceFailedEnumeration, @@ -318,10 +324,20 @@ typedef enum USB_CONNECTION_STATUS { DeviceNotEnoughPower, DeviceNotEnoughBandwidth, DeviceHubNestedTooDeeply, - DeviceInLegacyHub -} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS; - -typedef enum USB_HUB_NODE { + DeviceInLegacyHub, + DeviceEnumerating, + DeviceReset +} USB_CONNECTION_STATUS; + +typedef enum _USB_DEVICE_SPEED { + UsbLowSpeed = 0, + UsbFullSpeed, + UsbHighSpeed, + UsbSuperSpeed, + UsbSuperSpeedPlus // Not in Microsoft headers +} USB_DEVICE_SPEED; + +typedef enum _USB_HUB_NODE { UsbHub, UsbMIParent } USB_HUB_NODE; @@ -329,6 +345,29 @@ typedef enum USB_HUB_NODE { // Most of the structures below need to be packed #include <pshpack1.h> +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_HUB_INFORMATION { + USB_HUB_DESCRIPTOR HubDescriptor; + BOOLEAN HubIsBusPowered; +} USB_HUB_INFORMATION, *PUSB_HUB_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_DESCRIPTOR_REQUEST { ULONG ConnectionIndex; struct { diff --git a/libusb/sync.c b/libusb/sync.c index eac7572..adc95b4 100644 --- a/libusb/sync.c +++ b/libusb/sync.c @@ -81,7 +81,7 @@ static void sync_transfer_wait_for_completion(struct libusb_transfer *transfer) * (depending on direction bits within bmRequestType) * \param wLength the length field for the setup packet. The data buffer should * be at least this size. - * \param timeout timeout (in millseconds) that this function should wait + * \param timeout timeout (in milliseconds) that this function should wait * before giving up due to no response being received. For an unlimited * timeout, use value 0. * \returns on success, the number of bytes actually transferred @@ -91,7 +91,7 @@ static void sync_transfer_wait_for_completion(struct libusb_transfer *transfer) * \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 + * the operating system and/or hardware can support (see \ref asynclimits) * \returns another LIBUSB_ERROR code on other failures */ int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle, @@ -243,7 +243,7 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle, * underlying O/S requirements, meaning that the timeout may expire after * the first few chunks have completed. libusb is careful not to lose any data * that may have been transferred; do not assume that timeout conditions - * indicate a complete lack of I/O. + * indicate a complete lack of I/O. See \ref asynctimeout for more details. * * \param dev_handle a handle for the device to communicate with * \param endpoint the address of a valid endpoint to communicate with @@ -255,7 +255,7 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle, * 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 + * \param timeout timeout (in milliseconds) that this function should wait * before giving up due to no response being received. For an unlimited * timeout, use value 0. * @@ -267,6 +267,8 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle, * \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 LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than + * the operating system and/or hardware can support (see \ref asynclimits) * \returns another LIBUSB_ERROR code on other failures */ int API_EXPORTED libusb_bulk_transfer(libusb_device_handle *dev_handle, @@ -294,7 +296,7 @@ int API_EXPORTED libusb_bulk_transfer(libusb_device_handle *dev_handle, * underlying O/S requirements, meaning that the timeout may expire after * the first few chunks have completed. libusb is careful not to lose any data * that may have been transferred; do not assume that timeout conditions - * indicate a complete lack of I/O. + * indicate a complete lack of I/O. See \ref asynctimeout for more details. * * The default endpoint bInterval value is used as the polling interval. * @@ -308,7 +310,7 @@ int API_EXPORTED libusb_bulk_transfer(libusb_device_handle *dev_handle, * 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 + * \param timeout timeout (in milliseconds) that this function should wait * before giving up due to no response being received. For an unlimited * timeout, use value 0. * @@ -319,6 +321,8 @@ int API_EXPORTED libusb_bulk_transfer(libusb_device_handle *dev_handle, * \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 LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than + * the operating system and/or hardware can support (see \ref asynclimits) * \returns another LIBUSB_ERROR code on other error */ int API_EXPORTED libusb_interrupt_transfer(libusb_device_handle *dev_handle, diff --git a/libusb/version.h b/libusb/version.h index 8fccd35..d8ebde4 100644 --- a/libusb/version.h +++ b/libusb/version.h @@ -7,7 +7,7 @@ #define LIBUSB_MINOR 0 #endif #ifndef LIBUSB_MICRO -#define LIBUSB_MICRO 23 +#define LIBUSB_MICRO 24 #endif #ifndef LIBUSB_NANO #define LIBUSB_NANO 0 diff --git a/libusb/version_nano.h b/libusb/version_nano.h index f1ac20f..0f100a8 100644 --- a/libusb/version_nano.h +++ b/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 11522 +#define LIBUSB_NANO 11584 diff --git a/msvc/config.h b/msvc/config.h index 58d1ed7..8aafd9d 100644 --- a/msvc/config.h +++ b/msvc/config.h @@ -47,11 +47,12 @@ /* Define to 1 to enable message logging. */ #define ENABLE_LOGGING 1 -/* Define to 1 if using the Windows poll() implementation. */ -#define POLL_WINDOWS 1 +/* Define to 1 if compiling for a Windows platform. */ +#define PLATFORM_WINDOWS 1 -/* Define to 1 if using Windows threads. */ -#define THREADS_WINDOWS 1 +/* Define to the attribute for enabling parameter checks on printf-like + functions. */ +#define PRINTF_FORMAT(a, b) /**/ /* Define to 1 to output logging messages to the systemwide log. */ /* #undef USE_SYSTEM_LOGGING_FACILITY */ diff --git a/msvc/dpfp_2013.vcxproj b/msvc/dpfp_2013.vcxproj new file mode 100644 index 0000000..d9753e7 --- /dev/null +++ b/msvc/dpfp_2013.vcxproj @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>dpfp</ProjectName> + <ProjectGuid>{8c7814a1-fd6e-4185-9ea0-8208119756d4}</ProjectGuid> + <RootNamespace>examples</RootNamespace> + <Keyword>Win32Proj</Keyword> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + <WholeProgramOptimization Condition="'$(Configuration)'=='Release'">true</WholeProgramOptimization> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <IntDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\</IntDir> + <OutDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <WarningLevel>Level3</WarningLevel> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Debug'"> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <MinimalRebuild>true</MinimalRebuild> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Release'"> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <ProgramDatabaseFile>$(TargetDir)$(ProjectName).pdb</ProgramDatabaseFile> + <SubSystem>Console</SubSystem> + <AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link Condition="'$(Configuration)'=='Debug'"> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\examples\dpfp.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include=".\libusb_static_2013.vcxproj"> + <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/msvc/dpfp_2013.vcxproj.filters b/msvc/dpfp_2013.vcxproj.filters new file mode 100644 index 0000000..6af88cf --- /dev/null +++ b/msvc/dpfp_2013.vcxproj.filters @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4fc737f1-c7a5-4376-a066-2a32d752a2ff}</UniqueIdentifier> + <Extensions>c</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89bd-4b04-88eb-625fbe52ebfb}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\examples\dpfp.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/msvc/dpfp_2015.vcxproj b/msvc/dpfp_2015.vcxproj new file mode 100644 index 0000000..0db1a55 --- /dev/null +++ b/msvc/dpfp_2015.vcxproj @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>dpfp</ProjectName> + <ProjectGuid>{8c7814a1-fd6e-4185-9ea0-8208119756d4}</ProjectGuid> + <RootNamespace>examples</RootNamespace> + <Keyword>Win32Proj</Keyword> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v140</PlatformToolset> + <WholeProgramOptimization Condition="'$(Configuration)'=='Release'">true</WholeProgramOptimization> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <IntDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\</IntDir> + <OutDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <WarningLevel>Level3</WarningLevel> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Debug'"> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Release'"> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <ProgramDatabaseFile>$(TargetDir)$(ProjectName).pdb</ProgramDatabaseFile> + <SubSystem>Console</SubSystem> + <AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link Condition="'$(Configuration)'=='Debug'"> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\examples\dpfp.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include=".\libusb_static_2015.vcxproj"> + <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/msvc/dpfp_2015.vcxproj.filters b/msvc/dpfp_2015.vcxproj.filters new file mode 100644 index 0000000..6af88cf --- /dev/null +++ b/msvc/dpfp_2015.vcxproj.filters @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4fc737f1-c7a5-4376-a066-2a32d752a2ff}</UniqueIdentifier> + <Extensions>c</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89bd-4b04-88eb-625fbe52ebfb}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\examples\dpfp.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/msvc/dpfp_2017.vcxproj b/msvc/dpfp_2017.vcxproj new file mode 100644 index 0000000..308cd55 --- /dev/null +++ b/msvc/dpfp_2017.vcxproj @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|ARM"> + <Configuration>Debug</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|ARM64"> + <Configuration>Debug</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM"> + <Configuration>Release</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM64"> + <Configuration>Release</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>dpfp</ProjectName> + <ProjectGuid>{8c7814a1-fd6e-4185-9ea0-8208119756d4}</ProjectGuid> + <RootNamespace>examples</RootNamespace> + <Keyword>Win32Proj</Keyword> + <WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport> + <WindowsSDKDesktopARM64Support>true</WindowsSDKDesktopARM64Support> + <WindowsTargetPlatformVersion Condition="'$(Platform)'=='ARM' Or '$(Platform)'=='ARM64'">10.0.17763.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization Condition="'$(Configuration)'=='Release'">true</WholeProgramOptimization> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <IntDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\</IntDir> + <OutDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <WarningLevel>Level3</WarningLevel> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Debug'"> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Release'"> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <ProgramDatabaseFile>$(TargetDir)$(ProjectName).pdb</ProgramDatabaseFile> + <SubSystem>Console</SubSystem> + <AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link Condition="'$(Configuration)'=='Debug'"> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\examples\dpfp.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include=".\libusb_static_2017.vcxproj"> + <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/msvc/dpfp_2017.vcxproj.filters b/msvc/dpfp_2017.vcxproj.filters new file mode 100644 index 0000000..6af88cf --- /dev/null +++ b/msvc/dpfp_2017.vcxproj.filters @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4fc737f1-c7a5-4376-a066-2a32d752a2ff}</UniqueIdentifier> + <Extensions>c</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89bd-4b04-88eb-625fbe52ebfb}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\examples\dpfp.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/msvc/dpfp_2019.vcxproj b/msvc/dpfp_2019.vcxproj new file mode 100644 index 0000000..0fea8bb --- /dev/null +++ b/msvc/dpfp_2019.vcxproj @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|ARM"> + <Configuration>Debug</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|ARM64"> + <Configuration>Debug</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM"> + <Configuration>Release</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM64"> + <Configuration>Release</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>dpfp</ProjectName> + <ProjectGuid>{8c7814a1-fd6e-4185-9ea0-8208119756d4}</ProjectGuid> + <RootNamespace>examples</RootNamespace> + <Keyword>Win32Proj</Keyword> + <WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport> + <WindowsSDKDesktopARM64Support>true</WindowsSDKDesktopARM64Support> + <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v142</PlatformToolset> + <WholeProgramOptimization Condition="'$(Configuration)'=='Release'">true</WholeProgramOptimization> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <IntDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\</IntDir> + <OutDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <WarningLevel>Level3</WarningLevel> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Debug'"> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Release'"> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <ProgramDatabaseFile>$(TargetDir)$(ProjectName).pdb</ProgramDatabaseFile> + <SubSystem>Console</SubSystem> + <AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link Condition="'$(Configuration)'=='Debug'"> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\examples\dpfp.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include=".\libusb_static_2019.vcxproj"> + <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/msvc/dpfp_2019.vcxproj.filters b/msvc/dpfp_2019.vcxproj.filters new file mode 100644 index 0000000..6af88cf --- /dev/null +++ b/msvc/dpfp_2019.vcxproj.filters @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4fc737f1-c7a5-4376-a066-2a32d752a2ff}</UniqueIdentifier> + <Extensions>c</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89bd-4b04-88eb-625fbe52ebfb}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\examples\dpfp.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/msvc/dpfp_threaded_2013.vcxproj b/msvc/dpfp_threaded_2013.vcxproj new file mode 100644 index 0000000..dfdfc52 --- /dev/null +++ b/msvc/dpfp_threaded_2013.vcxproj @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>dpfp_threaded</ProjectName> + <ProjectGuid>{8c7814a2-fd6e-4185-9ea0-8208119756d4}</ProjectGuid> + <RootNamespace>examples</RootNamespace> + <Keyword>Win32Proj</Keyword> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + <WholeProgramOptimization Condition="'$(Configuration)'=='Release'">true</WholeProgramOptimization> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <IntDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\</IntDir> + <OutDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>DPFP_THREADED;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <WarningLevel>Level3</WarningLevel> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Debug'"> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <MinimalRebuild>true</MinimalRebuild> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Release'"> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <ProgramDatabaseFile>$(TargetDir)$(ProjectName).pdb</ProgramDatabaseFile> + <SubSystem>Console</SubSystem> + <AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link Condition="'$(Configuration)'=='Debug'"> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\examples\dpfp.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include=".\libusb_static_2013.vcxproj"> + <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/msvc/dpfp_threaded_2013.vcxproj.filters b/msvc/dpfp_threaded_2013.vcxproj.filters new file mode 100644 index 0000000..b97fc29 --- /dev/null +++ b/msvc/dpfp_threaded_2013.vcxproj.filters @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4fc737f2-c7a5-4376-a066-2a32d752a2ff}</UniqueIdentifier> + <Extensions>c</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995381-89bd-4b04-88eb-625fbe52ebfb}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\examples\dpfp.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/msvc/dpfp_threaded_2015.vcxproj b/msvc/dpfp_threaded_2015.vcxproj new file mode 100644 index 0000000..84516b4 --- /dev/null +++ b/msvc/dpfp_threaded_2015.vcxproj @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>dpfp_threaded</ProjectName> + <ProjectGuid>{8c7814a2-fd6e-4185-9ea0-8208119756d4}</ProjectGuid> + <RootNamespace>examples</RootNamespace> + <Keyword>Win32Proj</Keyword> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v140</PlatformToolset> + <WholeProgramOptimization Condition="'$(Configuration)'=='Release'">true</WholeProgramOptimization> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <IntDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\</IntDir> + <OutDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>DPFP_THREADED;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <WarningLevel>Level3</WarningLevel> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Debug'"> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Release'"> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <ProgramDatabaseFile>$(TargetDir)$(ProjectName).pdb</ProgramDatabaseFile> + <SubSystem>Console</SubSystem> + <AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link Condition="'$(Configuration)'=='Debug'"> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\examples\dpfp.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include=".\libusb_static_2015.vcxproj"> + <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/msvc/dpfp_threaded_2015.vcxproj.filters b/msvc/dpfp_threaded_2015.vcxproj.filters new file mode 100644 index 0000000..b97fc29 --- /dev/null +++ b/msvc/dpfp_threaded_2015.vcxproj.filters @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4fc737f2-c7a5-4376-a066-2a32d752a2ff}</UniqueIdentifier> + <Extensions>c</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995381-89bd-4b04-88eb-625fbe52ebfb}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\examples\dpfp.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/msvc/dpfp_threaded_2017.vcxproj b/msvc/dpfp_threaded_2017.vcxproj new file mode 100644 index 0000000..04f4734 --- /dev/null +++ b/msvc/dpfp_threaded_2017.vcxproj @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|ARM"> + <Configuration>Debug</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|ARM64"> + <Configuration>Debug</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM"> + <Configuration>Release</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM64"> + <Configuration>Release</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>dpfp_threaded</ProjectName> + <ProjectGuid>{8c7814a2-fd6e-4185-9ea0-8208119756d4}</ProjectGuid> + <RootNamespace>examples</RootNamespace> + <Keyword>Win32Proj</Keyword> + <WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport> + <WindowsSDKDesktopARM64Support>true</WindowsSDKDesktopARM64Support> + <WindowsTargetPlatformVersion Condition="'$(Platform)'=='ARM' Or '$(Platform)'=='ARM64'">10.0.17763.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization Condition="'$(Configuration)'=='Release'">true</WholeProgramOptimization> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <IntDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\</IntDir> + <OutDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>DPFP_THREADED;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <WarningLevel>Level3</WarningLevel> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Debug'"> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Release'"> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <ProgramDatabaseFile>$(TargetDir)$(ProjectName).pdb</ProgramDatabaseFile> + <SubSystem>Console</SubSystem> + <AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link Condition="'$(Configuration)'=='Debug'"> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\examples\dpfp.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include=".\libusb_static_2017.vcxproj"> + <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/msvc/dpfp_threaded_2017.vcxproj.filters b/msvc/dpfp_threaded_2017.vcxproj.filters new file mode 100644 index 0000000..b97fc29 --- /dev/null +++ b/msvc/dpfp_threaded_2017.vcxproj.filters @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4fc737f2-c7a5-4376-a066-2a32d752a2ff}</UniqueIdentifier> + <Extensions>c</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995381-89bd-4b04-88eb-625fbe52ebfb}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\examples\dpfp.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/msvc/dpfp_threaded_2019.vcxproj b/msvc/dpfp_threaded_2019.vcxproj new file mode 100644 index 0000000..27f961a --- /dev/null +++ b/msvc/dpfp_threaded_2019.vcxproj @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|ARM"> + <Configuration>Debug</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|ARM64"> + <Configuration>Debug</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM"> + <Configuration>Release</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM64"> + <Configuration>Release</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>dpfp_threaded</ProjectName> + <ProjectGuid>{8c7814a2-fd6e-4185-9ea0-8208119756d4}</ProjectGuid> + <RootNamespace>examples</RootNamespace> + <Keyword>Win32Proj</Keyword> + <WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport> + <WindowsSDKDesktopARM64Support>true</WindowsSDKDesktopARM64Support> + <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v142</PlatformToolset> + <WholeProgramOptimization Condition="'$(Configuration)'=='Release'">true</WholeProgramOptimization> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <IntDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\</IntDir> + <OutDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>DPFP_THREADED;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <WarningLevel>Level3</WarningLevel> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Debug'"> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Release'"> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <ProgramDatabaseFile>$(TargetDir)$(ProjectName).pdb</ProgramDatabaseFile> + <SubSystem>Console</SubSystem> + <AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link Condition="'$(Configuration)'=='Debug'"> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\examples\dpfp.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include=".\libusb_static_2019.vcxproj"> + <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/msvc/dpfp_threaded_2019.vcxproj.filters b/msvc/dpfp_threaded_2019.vcxproj.filters new file mode 100644 index 0000000..b97fc29 --- /dev/null +++ b/msvc/dpfp_threaded_2019.vcxproj.filters @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4fc737f2-c7a5-4376-a066-2a32d752a2ff}</UniqueIdentifier> + <Extensions>c</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995381-89bd-4b04-88eb-625fbe52ebfb}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\examples\dpfp.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/msvc/fxload_2013.vcxproj b/msvc/fxload_2013.vcxproj index 00f5c8d..6b7cebd 100644 --- a/msvc/fxload_2013.vcxproj +++ b/msvc/fxload_2013.vcxproj @@ -73,7 +73,10 @@ <ClCompile Include="..\examples\fxload.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include=".\getopt\getopt.h" /> <ClInclude Include="..\examples\ezusb.h" /> + <ClInclude Include="..\libusb\libusb.h" /> </ItemGroup> <ItemGroup> <ProjectReference Include=".\getopt_2013.vcxproj"> diff --git a/msvc/fxload_2013.vcxproj.filters b/msvc/fxload_2013.vcxproj.filters index 2d6fbc9..2129604 100644 --- a/msvc/fxload_2013.vcxproj.filters +++ b/msvc/fxload_2013.vcxproj.filters @@ -11,9 +11,18 @@ </Filter> </ItemGroup> <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include=".\getopt\getopt.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\examples\ezusb.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\ezusb.c"> diff --git a/msvc/fxload_2015.vcxproj b/msvc/fxload_2015.vcxproj index bd4a851..01c12b3 100644 --- a/msvc/fxload_2015.vcxproj +++ b/msvc/fxload_2015.vcxproj @@ -73,7 +73,10 @@ <ClCompile Include="..\examples\fxload.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include=".\getopt\getopt.h" /> <ClInclude Include="..\examples\ezusb.h" /> + <ClInclude Include="..\libusb\libusb.h" /> </ItemGroup> <ItemGroup> <ProjectReference Include=".\getopt_2015.vcxproj"> diff --git a/msvc/fxload_2015.vcxproj.filters b/msvc/fxload_2015.vcxproj.filters index 2d6fbc9..2129604 100644 --- a/msvc/fxload_2015.vcxproj.filters +++ b/msvc/fxload_2015.vcxproj.filters @@ -11,9 +11,18 @@ </Filter> </ItemGroup> <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include=".\getopt\getopt.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\examples\ezusb.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\ezusb.c"> diff --git a/msvc/fxload_2017.vcxproj b/msvc/fxload_2017.vcxproj index 61f312b..c8186ef 100644 --- a/msvc/fxload_2017.vcxproj +++ b/msvc/fxload_2017.vcxproj @@ -92,7 +92,10 @@ <ClCompile Include="..\examples\fxload.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include=".\getopt\getopt.h" /> <ClInclude Include="..\examples\ezusb.h" /> + <ClInclude Include="..\libusb\libusb.h" /> </ItemGroup> <ItemGroup> <ProjectReference Include=".\getopt_2017.vcxproj"> diff --git a/msvc/fxload_2017.vcxproj.filters b/msvc/fxload_2017.vcxproj.filters index 2d6fbc9..2129604 100644 --- a/msvc/fxload_2017.vcxproj.filters +++ b/msvc/fxload_2017.vcxproj.filters @@ -11,9 +11,18 @@ </Filter> </ItemGroup> <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include=".\getopt\getopt.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\examples\ezusb.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\ezusb.c"> diff --git a/msvc/fxload_2019.vcxproj b/msvc/fxload_2019.vcxproj index 131c82a..9e32da6 100644 --- a/msvc/fxload_2019.vcxproj +++ b/msvc/fxload_2019.vcxproj @@ -92,7 +92,10 @@ <ClCompile Include="..\examples\fxload.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include=".\getopt\getopt.h" /> <ClInclude Include="..\examples\ezusb.h" /> + <ClInclude Include="..\libusb\libusb.h" /> </ItemGroup> <ItemGroup> <ProjectReference Include=".\getopt_2019.vcxproj"> diff --git a/msvc/fxload_2019.vcxproj.filters b/msvc/fxload_2019.vcxproj.filters index 2d6fbc9..2129604 100644 --- a/msvc/fxload_2019.vcxproj.filters +++ b/msvc/fxload_2019.vcxproj.filters @@ -11,9 +11,18 @@ </Filter> </ItemGroup> <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include=".\getopt\getopt.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\examples\ezusb.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\ezusb.c"> diff --git a/msvc/hotplugtest_2013.vcxproj b/msvc/hotplugtest_2013.vcxproj index 915392c..2fad4a7 100644 --- a/msvc/hotplugtest_2013.vcxproj +++ b/msvc/hotplugtest_2013.vcxproj @@ -45,7 +45,7 @@ </PropertyGroup> <ItemDefinitionGroup> <ClCompile> - <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <WarningLevel>Level3</WarningLevel> </ClCompile> @@ -72,6 +72,9 @@ <ClCompile Include="..\examples\hotplugtest.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include=".\libusb_static_2013.vcxproj"> <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> diff --git a/msvc/hotplugtest_2013.vcxproj.filters b/msvc/hotplugtest_2013.vcxproj.filters index 93c5f9a..6228bd3 100644 --- a/msvc/hotplugtest_2013.vcxproj.filters +++ b/msvc/hotplugtest_2013.vcxproj.filters @@ -5,6 +5,15 @@ <UniqueIdentifier>{2499509b-af28-4409-aed1-a0c3cc458288}</UniqueIdentifier> <Extensions>c</Extensions> </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{6fa5acdf-d7e4-48e3-a554-9000deb594d1}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\hotplugtest.c"> diff --git a/msvc/hotplugtest_2015.vcxproj b/msvc/hotplugtest_2015.vcxproj index 2b39f6e..9a56aee 100644 --- a/msvc/hotplugtest_2015.vcxproj +++ b/msvc/hotplugtest_2015.vcxproj @@ -46,7 +46,7 @@ <ItemDefinitionGroup> <ClCompile> <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> - <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <WarningLevel>Level3</WarningLevel> </ClCompile> @@ -72,6 +72,9 @@ <ClCompile Include="..\examples\hotplugtest.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include=".\libusb_static_2015.vcxproj"> <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> diff --git a/msvc/hotplugtest_2015.vcxproj.filters b/msvc/hotplugtest_2015.vcxproj.filters index 93c5f9a..6228bd3 100644 --- a/msvc/hotplugtest_2015.vcxproj.filters +++ b/msvc/hotplugtest_2015.vcxproj.filters @@ -5,6 +5,15 @@ <UniqueIdentifier>{2499509b-af28-4409-aed1-a0c3cc458288}</UniqueIdentifier> <Extensions>c</Extensions> </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{6fa5acdf-d7e4-48e3-a554-9000deb594d1}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\hotplugtest.c"> diff --git a/msvc/hotplugtest_2017.vcxproj b/msvc/hotplugtest_2017.vcxproj index 2c48c78..ca383d3 100644 --- a/msvc/hotplugtest_2017.vcxproj +++ b/msvc/hotplugtest_2017.vcxproj @@ -65,7 +65,7 @@ <ItemDefinitionGroup> <ClCompile> <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> - <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <WarningLevel>Level3</WarningLevel> </ClCompile> @@ -91,6 +91,9 @@ <ClCompile Include="..\examples\hotplugtest.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include=".\libusb_static_2017.vcxproj"> <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> diff --git a/msvc/hotplugtest_2017.vcxproj.filters b/msvc/hotplugtest_2017.vcxproj.filters index 93c5f9a..6228bd3 100644 --- a/msvc/hotplugtest_2017.vcxproj.filters +++ b/msvc/hotplugtest_2017.vcxproj.filters @@ -5,6 +5,15 @@ <UniqueIdentifier>{2499509b-af28-4409-aed1-a0c3cc458288}</UniqueIdentifier> <Extensions>c</Extensions> </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{6fa5acdf-d7e4-48e3-a554-9000deb594d1}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\hotplugtest.c"> diff --git a/msvc/hotplugtest_2019.vcxproj b/msvc/hotplugtest_2019.vcxproj index 0aa1db6..d65bb6f 100644 --- a/msvc/hotplugtest_2019.vcxproj +++ b/msvc/hotplugtest_2019.vcxproj @@ -65,7 +65,7 @@ <ItemDefinitionGroup> <ClCompile> <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> - <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <WarningLevel>Level3</WarningLevel> </ClCompile> @@ -91,6 +91,9 @@ <ClCompile Include="..\examples\hotplugtest.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include=".\libusb_static_2019.vcxproj"> <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> diff --git a/msvc/hotplugtest_2019.vcxproj.filters b/msvc/hotplugtest_2019.vcxproj.filters index 93c5f9a..6228bd3 100644 --- a/msvc/hotplugtest_2019.vcxproj.filters +++ b/msvc/hotplugtest_2019.vcxproj.filters @@ -5,6 +5,15 @@ <UniqueIdentifier>{2499509b-af28-4409-aed1-a0c3cc458288}</UniqueIdentifier> <Extensions>c</Extensions> </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{6fa5acdf-d7e4-48e3-a554-9000deb594d1}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\hotplugtest.c"> diff --git a/msvc/libusb_2013.sln b/msvc/libusb_2013.sln index 3429f9b..44fca6d 100644 --- a/msvc/libusb_2013.sln +++ b/msvc/libusb_2013.sln @@ -6,6 +6,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (static)", "libu EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (dll)", "libusb_dll_2013.vcxproj", "{349EE8FA-7D25-4909-AAF5-FF3FADE72187}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dpfp", "dpfp_2013.vcxproj", "{8C7814A1-FD6E-4185-9EA0-8208119756D4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dpfp_threaded", "dpfp_threaded_2013.vcxproj", "{8C7814A2-FD6E-4185-9EA0-8208119756D4}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fxload", "fxload_2013.vcxproj", "{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getopt", "getopt_2013.vcxproj", "{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}" @@ -14,6 +18,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hotplugtest", "hotplugtest_ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "listdevs", "listdevs_2013.vcxproj", "{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sam3u_benchmark", "sam3u_benchmark_2013.vcxproj", "{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stress", "stress_2013.vcxproj", "{53942EFF-C810-458D-B3CB-EE5CE9F1E781}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testlibusb", "testlibusb_2013.vcxproj", "{70828935-325B-4749-B381-0E55EF31AEE8}" @@ -44,6 +50,22 @@ Global {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 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.ActiveCfg = Debug|Win32 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.Build.0 = Debug|Win32 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|x64.ActiveCfg = Debug|x64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|x64.Build.0 = Debug|x64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|Win32.ActiveCfg = Release|Win32 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|Win32.Build.0 = Release|Win32 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|x64.ActiveCfg = Release|x64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|x64.Build.0 = Release|x64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.ActiveCfg = Debug|Win32 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.Build.0 = Debug|Win32 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|x64.ActiveCfg = Debug|x64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|x64.Build.0 = Debug|x64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|Win32.ActiveCfg = Release|Win32 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|Win32.Build.0 = Release|Win32 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|x64.ActiveCfg = Release|x64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.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 @@ -76,6 +98,14 @@ Global {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 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|Win32.ActiveCfg = Debug|Win32 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|Win32.Build.0 = Debug|Win32 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|x64.ActiveCfg = Debug|x64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|x64.Build.0 = Debug|x64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|Win32.ActiveCfg = Release|Win32 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|Win32.Build.0 = Release|Win32 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|x64.ActiveCfg = Release|x64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.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 diff --git a/msvc/libusb_2015.sln b/msvc/libusb_2015.sln index 6b514dd..8c86639 100644 --- a/msvc/libusb_2015.sln +++ b/msvc/libusb_2015.sln @@ -6,6 +6,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (static)", "libu 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}") = "dpfp", "dpfp_2015.vcxproj", "{8C7814A1-FD6E-4185-9EA0-8208119756D4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dpfp_threaded", "dpfp_threaded_2015.vcxproj", "{8C7814A2-FD6E-4185-9EA0-8208119756D4}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fxload", "fxload_2015.vcxproj", "{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getopt", "getopt_2015.vcxproj", "{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}" @@ -14,6 +18,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hotplugtest", "hotplugtest_ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "listdevs", "listdevs_2015.vcxproj", "{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sam3u_benchmark", "sam3u_benchmark_2015.vcxproj", "{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stress", "stress_2015.vcxproj", "{53942EFF-C810-458D-B3CB-EE5CE9F1E781}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testlibusb", "testlibusb_2015.vcxproj", "{70828935-325B-4749-B381-0E55EF31AEE8}" @@ -44,6 +50,22 @@ Global {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 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.ActiveCfg = Debug|Win32 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.Build.0 = Debug|Win32 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|x64.ActiveCfg = Debug|x64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|x64.Build.0 = Debug|x64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|Win32.ActiveCfg = Release|Win32 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|Win32.Build.0 = Release|Win32 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|x64.ActiveCfg = Release|x64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|x64.Build.0 = Release|x64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.ActiveCfg = Debug|Win32 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.Build.0 = Debug|Win32 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|x64.ActiveCfg = Debug|x64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|x64.Build.0 = Debug|x64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|Win32.ActiveCfg = Release|Win32 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|Win32.Build.0 = Release|Win32 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|x64.ActiveCfg = Release|x64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.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 @@ -76,6 +98,14 @@ Global {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 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|Win32.ActiveCfg = Debug|Win32 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|Win32.Build.0 = Debug|Win32 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|x64.ActiveCfg = Debug|x64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|x64.Build.0 = Debug|x64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|Win32.ActiveCfg = Release|Win32 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|Win32.Build.0 = Release|Win32 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|x64.ActiveCfg = Release|x64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.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 diff --git a/msvc/libusb_2017.sln b/msvc/libusb_2017.sln index df0b2c2..3535138 100644 --- a/msvc/libusb_2017.sln +++ b/msvc/libusb_2017.sln @@ -6,6 +6,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (static)", "libu EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (dll)", "libusb_dll_2017.vcxproj", "{349EE8FA-7D25-4909-AAF5-FF3FADE72187}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dpfp", "dpfp_2017.vcxproj", "{8C7814A1-FD6E-4185-9EA0-8208119756D4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dpfp_threaded", "dpfp_threaded_2017.vcxproj", "{8C7814A2-FD6E-4185-9EA0-8208119756D4}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fxload", "fxload_2017.vcxproj", "{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getopt", "getopt_2017.vcxproj", "{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}" @@ -14,6 +18,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hotplugtest", "hotplugtest_ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "listdevs", "listdevs_2017.vcxproj", "{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sam3u_benchmark", "sam3u_benchmark_2017.vcxproj", "{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stress", "stress_2017.vcxproj", "{53942EFF-C810-458D-B3CB-EE5CE9F1E781}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testlibusb", "testlibusb_2017.vcxproj", "{70828935-325B-4749-B381-0E55EF31AEE8}" @@ -64,6 +70,38 @@ Global {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 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|ARM.ActiveCfg = Debug|ARM + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|ARM.Build.0 = Debug|ARM + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|ARM64.Build.0 = Debug|ARM64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.ActiveCfg = Debug|Win32 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.Build.0 = Debug|Win32 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|x64.ActiveCfg = Debug|x64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|x64.Build.0 = Debug|x64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|ARM.ActiveCfg = Release|ARM + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|ARM.Build.0 = Release|ARM + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|ARM64.ActiveCfg = Release|ARM64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|ARM64.Build.0 = Release|ARM64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|Win32.ActiveCfg = Release|Win32 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|Win32.Build.0 = Release|Win32 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|x64.ActiveCfg = Release|x64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|x64.Build.0 = Release|x64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|ARM.ActiveCfg = Debug|ARM + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|ARM.Build.0 = Debug|ARM + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|ARM64.Build.0 = Debug|ARM64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.ActiveCfg = Debug|Win32 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.Build.0 = Debug|Win32 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|x64.ActiveCfg = Debug|x64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|x64.Build.0 = Debug|x64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|ARM.ActiveCfg = Release|ARM + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|ARM.Build.0 = Release|ARM + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|ARM64.ActiveCfg = Release|ARM64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|ARM64.Build.0 = Release|ARM64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|Win32.ActiveCfg = Release|Win32 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|Win32.Build.0 = Release|Win32 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|x64.ActiveCfg = Release|x64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|x64.Build.0 = Release|x64 {9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|ARM.ActiveCfg = Debug|ARM {9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|ARM.Build.0 = Debug|ARM {9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|ARM64.ActiveCfg = Debug|ARM64 @@ -128,6 +166,22 @@ Global {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 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|ARM.ActiveCfg = Debug|ARM + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|ARM.Build.0 = Debug|ARM + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|ARM64.Build.0 = Debug|ARM64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|Win32.ActiveCfg = Debug|Win32 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|Win32.Build.0 = Debug|Win32 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|x64.ActiveCfg = Debug|x64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|x64.Build.0 = Debug|x64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|ARM.ActiveCfg = Release|ARM + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|ARM.Build.0 = Release|ARM + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|ARM64.ActiveCfg = Release|ARM64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|ARM64.Build.0 = Release|ARM64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|Win32.ActiveCfg = Release|Win32 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|Win32.Build.0 = Release|Win32 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|x64.ActiveCfg = Release|x64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|x64.Build.0 = Release|x64 {53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug|ARM.ActiveCfg = Debug|ARM {53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug|ARM.Build.0 = Debug|ARM {53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug|ARM64.ActiveCfg = Debug|ARM64 diff --git a/msvc/libusb_2019.sln b/msvc/libusb_2019.sln index 6fea170..0a6a1c4 100644 --- a/msvc/libusb_2019.sln +++ b/msvc/libusb_2019.sln @@ -6,6 +6,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (static)", "libu EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (dll)", "libusb_dll_2019.vcxproj", "{349EE8FA-7D25-4909-AAF5-FF3FADE72187}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dpfp", "dpfp_2019.vcxproj", "{8C7814A1-FD6E-4185-9EA0-8208119756D4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dpfp_threaded", "dpfp_threaded_2019.vcxproj", "{8C7814A2-FD6E-4185-9EA0-8208119756D4}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fxload", "fxload_2019.vcxproj", "{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getopt", "getopt_2019.vcxproj", "{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}" @@ -14,6 +18,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hotplugtest", "hotplugtest_ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "listdevs", "listdevs_2019.vcxproj", "{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sam3u_benchmark", "sam3u_benchmark_2019.vcxproj", "{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stress", "stress_2019.vcxproj", "{53942EFF-C810-458D-B3CB-EE5CE9F1E781}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testlibusb", "testlibusb_2019.vcxproj", "{70828935-325B-4749-B381-0E55EF31AEE8}" @@ -64,6 +70,38 @@ Global {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 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|ARM.ActiveCfg = Debug|ARM + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|ARM.Build.0 = Debug|ARM + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|ARM64.Build.0 = Debug|ARM64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.ActiveCfg = Debug|Win32 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.Build.0 = Debug|Win32 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|x64.ActiveCfg = Debug|x64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|x64.Build.0 = Debug|x64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|ARM.ActiveCfg = Release|ARM + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|ARM.Build.0 = Release|ARM + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|ARM64.ActiveCfg = Release|ARM64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|ARM64.Build.0 = Release|ARM64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|Win32.ActiveCfg = Release|Win32 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|Win32.Build.0 = Release|Win32 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|x64.ActiveCfg = Release|x64 + {8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|x64.Build.0 = Release|x64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|ARM.ActiveCfg = Debug|ARM + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|ARM.Build.0 = Debug|ARM + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|ARM64.Build.0 = Debug|ARM64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.ActiveCfg = Debug|Win32 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.Build.0 = Debug|Win32 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|x64.ActiveCfg = Debug|x64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|x64.Build.0 = Debug|x64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|ARM.ActiveCfg = Release|ARM + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|ARM.Build.0 = Release|ARM + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|ARM64.ActiveCfg = Release|ARM64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|ARM64.Build.0 = Release|ARM64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|Win32.ActiveCfg = Release|Win32 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|Win32.Build.0 = Release|Win32 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|x64.ActiveCfg = Release|x64 + {8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|x64.Build.0 = Release|x64 {9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|ARM.ActiveCfg = Debug|ARM {9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|ARM.Build.0 = Debug|ARM {9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|ARM64.ActiveCfg = Debug|ARM64 @@ -128,6 +166,22 @@ Global {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 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|ARM.ActiveCfg = Debug|ARM + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|ARM.Build.0 = Debug|ARM + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|ARM64.Build.0 = Debug|ARM64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|Win32.ActiveCfg = Debug|Win32 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|Win32.Build.0 = Debug|Win32 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|x64.ActiveCfg = Debug|x64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|x64.Build.0 = Debug|x64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|ARM.ActiveCfg = Release|ARM + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|ARM.Build.0 = Release|ARM + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|ARM64.ActiveCfg = Release|ARM64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|ARM64.Build.0 = Release|ARM64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|Win32.ActiveCfg = Release|Win32 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|Win32.Build.0 = Release|Win32 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|x64.ActiveCfg = Release|x64 + {861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|x64.Build.0 = Release|x64 {53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug|ARM.ActiveCfg = Debug|ARM {53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug|ARM.Build.0 = Debug|ARM {53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug|ARM64.ActiveCfg = Debug|ARM64 diff --git a/msvc/libusb_dll_2013.vcxproj b/msvc/libusb_dll_2013.vcxproj index b858f77..56ffd75 100644 --- a/msvc/libusb_dll_2013.vcxproj +++ b/msvc/libusb_dll_2013.vcxproj @@ -70,9 +70,9 @@ <ItemGroup> <ClCompile Include="..\libusb\core.c" /> <ClCompile Include="..\libusb\descriptor.c" /> + <ClCompile Include="..\libusb\os\events_windows.c" /> <ClCompile Include="..\libusb\hotplug.c" /> <ClCompile Include="..\libusb\io.c" /> - <ClCompile Include="..\libusb\os\poll_windows.c" /> <ClCompile Include="..\libusb\strerror.c" /> <ClCompile Include="..\libusb\sync.c" /> <ClCompile Include="..\libusb\os\threads_windows.c" /> @@ -82,10 +82,10 @@ </ItemGroup> <ItemGroup> <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\os\events_windows.h" /> <ClInclude Include="..\libusb\hotplug.h" /> <ClInclude Include="..\libusb\libusb.h" /> <ClInclude Include="..\libusb\libusbi.h" /> - <ClInclude Include="..\libusb\os\poll_windows.h" /> <ClInclude Include="..\libusb\os\threads_windows.h" /> <ClInclude Include="..\libusb\version.h" /> <ClInclude Include="..\libusb\version_nano.h" /> diff --git a/msvc/libusb_dll_2013.vcxproj.filters b/msvc/libusb_dll_2013.vcxproj.filters index 2e6cc93..8da28e3 100644 --- a/msvc/libusb_dll_2013.vcxproj.filters +++ b/msvc/libusb_dll_2013.vcxproj.filters @@ -18,6 +18,9 @@ <ClInclude Include=".\config.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\libusb\os\events_windows.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\libusb\hotplug.h"> <Filter>Header Files</Filter> </ClInclude> @@ -27,9 +30,6 @@ <ClInclude Include="..\libusb\libusbi.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\libusb\os\poll_windows.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\libusb\os\threads_windows.h"> <Filter>Header Files</Filter> </ClInclude> @@ -61,13 +61,13 @@ <ClCompile Include="..\libusb\descriptor.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\hotplug.c"> + <ClCompile Include="..\libusb\os\events_windows.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\io.c"> + <ClCompile Include="..\libusb\hotplug.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\os\poll_windows.c"> + <ClCompile Include="..\libusb\io.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\libusb\strerror.c"> diff --git a/msvc/libusb_dll_2015.vcxproj b/msvc/libusb_dll_2015.vcxproj index 4a73ef7..d2c850d 100644 --- a/msvc/libusb_dll_2015.vcxproj +++ b/msvc/libusb_dll_2015.vcxproj @@ -71,9 +71,9 @@ <ItemGroup> <ClCompile Include="..\libusb\core.c" /> <ClCompile Include="..\libusb\descriptor.c" /> + <ClCompile Include="..\libusb\os\events_windows.c" /> <ClCompile Include="..\libusb\hotplug.c" /> <ClCompile Include="..\libusb\io.c" /> - <ClCompile Include="..\libusb\os\poll_windows.c" /> <ClCompile Include="..\libusb\strerror.c" /> <ClCompile Include="..\libusb\sync.c" /> <ClCompile Include="..\libusb\os\threads_windows.c" /> @@ -83,10 +83,10 @@ </ItemGroup> <ItemGroup> <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\os\events_windows.h" /> <ClInclude Include="..\libusb\hotplug.h" /> <ClInclude Include="..\libusb\libusb.h" /> <ClInclude Include="..\libusb\libusbi.h" /> - <ClInclude Include="..\libusb\os\poll_windows.h" /> <ClInclude Include="..\libusb\os\threads_windows.h" /> <ClInclude Include="..\libusb\version.h" /> <ClInclude Include="..\libusb\version_nano.h" /> diff --git a/msvc/libusb_dll_2015.vcxproj.filters b/msvc/libusb_dll_2015.vcxproj.filters index 2e6cc93..8da28e3 100644 --- a/msvc/libusb_dll_2015.vcxproj.filters +++ b/msvc/libusb_dll_2015.vcxproj.filters @@ -18,6 +18,9 @@ <ClInclude Include=".\config.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\libusb\os\events_windows.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\libusb\hotplug.h"> <Filter>Header Files</Filter> </ClInclude> @@ -27,9 +30,6 @@ <ClInclude Include="..\libusb\libusbi.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\libusb\os\poll_windows.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\libusb\os\threads_windows.h"> <Filter>Header Files</Filter> </ClInclude> @@ -61,13 +61,13 @@ <ClCompile Include="..\libusb\descriptor.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\hotplug.c"> + <ClCompile Include="..\libusb\os\events_windows.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\io.c"> + <ClCompile Include="..\libusb\hotplug.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\os\poll_windows.c"> + <ClCompile Include="..\libusb\io.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\libusb\strerror.c"> diff --git a/msvc/libusb_dll_2017.vcxproj b/msvc/libusb_dll_2017.vcxproj index 20fa6c4..598159d 100644 --- a/msvc/libusb_dll_2017.vcxproj +++ b/msvc/libusb_dll_2017.vcxproj @@ -90,9 +90,9 @@ <ItemGroup> <ClCompile Include="..\libusb\core.c" /> <ClCompile Include="..\libusb\descriptor.c" /> + <ClCompile Include="..\libusb\os\events_windows.c" /> <ClCompile Include="..\libusb\hotplug.c" /> <ClCompile Include="..\libusb\io.c" /> - <ClCompile Include="..\libusb\os\poll_windows.c" /> <ClCompile Include="..\libusb\strerror.c" /> <ClCompile Include="..\libusb\sync.c" /> <ClCompile Include="..\libusb\os\threads_windows.c" /> @@ -102,10 +102,10 @@ </ItemGroup> <ItemGroup> <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\os\events_windows.h" /> <ClInclude Include="..\libusb\hotplug.h" /> <ClInclude Include="..\libusb\libusb.h" /> <ClInclude Include="..\libusb\libusbi.h" /> - <ClInclude Include="..\libusb\os\poll_windows.h" /> <ClInclude Include="..\libusb\os\threads_windows.h" /> <ClInclude Include="..\libusb\version.h" /> <ClInclude Include="..\libusb\version_nano.h" /> diff --git a/msvc/libusb_dll_2017.vcxproj.filters b/msvc/libusb_dll_2017.vcxproj.filters index 2e6cc93..8da28e3 100644 --- a/msvc/libusb_dll_2017.vcxproj.filters +++ b/msvc/libusb_dll_2017.vcxproj.filters @@ -18,6 +18,9 @@ <ClInclude Include=".\config.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\libusb\os\events_windows.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\libusb\hotplug.h"> <Filter>Header Files</Filter> </ClInclude> @@ -27,9 +30,6 @@ <ClInclude Include="..\libusb\libusbi.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\libusb\os\poll_windows.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\libusb\os\threads_windows.h"> <Filter>Header Files</Filter> </ClInclude> @@ -61,13 +61,13 @@ <ClCompile Include="..\libusb\descriptor.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\hotplug.c"> + <ClCompile Include="..\libusb\os\events_windows.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\io.c"> + <ClCompile Include="..\libusb\hotplug.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\os\poll_windows.c"> + <ClCompile Include="..\libusb\io.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\libusb\strerror.c"> diff --git a/msvc/libusb_dll_2019.vcxproj b/msvc/libusb_dll_2019.vcxproj index 69e42e1..dbd8717 100644 --- a/msvc/libusb_dll_2019.vcxproj +++ b/msvc/libusb_dll_2019.vcxproj @@ -90,9 +90,9 @@ <ItemGroup> <ClCompile Include="..\libusb\core.c" /> <ClCompile Include="..\libusb\descriptor.c" /> + <ClCompile Include="..\libusb\os\events_windows.c" /> <ClCompile Include="..\libusb\hotplug.c" /> <ClCompile Include="..\libusb\io.c" /> - <ClCompile Include="..\libusb\os\poll_windows.c" /> <ClCompile Include="..\libusb\strerror.c" /> <ClCompile Include="..\libusb\sync.c" /> <ClCompile Include="..\libusb\os\threads_windows.c" /> @@ -102,10 +102,10 @@ </ItemGroup> <ItemGroup> <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\os\events_windows.h" /> <ClInclude Include="..\libusb\hotplug.h" /> <ClInclude Include="..\libusb\libusb.h" /> <ClInclude Include="..\libusb\libusbi.h" /> - <ClInclude Include="..\libusb\os\poll_windows.h" /> <ClInclude Include="..\libusb\os\threads_windows.h" /> <ClInclude Include="..\libusb\version.h" /> <ClInclude Include="..\libusb\version_nano.h" /> diff --git a/msvc/libusb_dll_2019.vcxproj.filters b/msvc/libusb_dll_2019.vcxproj.filters index 2e6cc93..8da28e3 100644 --- a/msvc/libusb_dll_2019.vcxproj.filters +++ b/msvc/libusb_dll_2019.vcxproj.filters @@ -18,6 +18,9 @@ <ClInclude Include=".\config.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\libusb\os\events_windows.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\libusb\hotplug.h"> <Filter>Header Files</Filter> </ClInclude> @@ -27,9 +30,6 @@ <ClInclude Include="..\libusb\libusbi.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\libusb\os\poll_windows.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\libusb\os\threads_windows.h"> <Filter>Header Files</Filter> </ClInclude> @@ -61,13 +61,13 @@ <ClCompile Include="..\libusb\descriptor.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\hotplug.c"> + <ClCompile Include="..\libusb\os\events_windows.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\io.c"> + <ClCompile Include="..\libusb\hotplug.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\os\poll_windows.c"> + <ClCompile Include="..\libusb\io.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\libusb\strerror.c"> diff --git a/msvc/libusb_static_2013.vcxproj b/msvc/libusb_static_2013.vcxproj index 559acf1..1b287e5 100644 --- a/msvc/libusb_static_2013.vcxproj +++ b/msvc/libusb_static_2013.vcxproj @@ -66,9 +66,9 @@ <ItemGroup> <ClCompile Include="..\libusb\core.c" /> <ClCompile Include="..\libusb\descriptor.c" /> + <ClCompile Include="..\libusb\os\events_windows.c" /> <ClCompile Include="..\libusb\hotplug.c" /> <ClCompile Include="..\libusb\io.c" /> - <ClCompile Include="..\libusb\os\poll_windows.c" /> <ClCompile Include="..\libusb\strerror.c" /> <ClCompile Include="..\libusb\sync.c" /> <ClCompile Include="..\libusb\os\threads_windows.c" /> @@ -78,10 +78,10 @@ </ItemGroup> <ItemGroup> <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\os\events_windows.h" /> <ClInclude Include="..\libusb\hotplug.h" /> <ClInclude Include="..\libusb\libusb.h" /> <ClInclude Include="..\libusb\libusbi.h" /> - <ClInclude Include="..\libusb\os\poll_windows.h" /> <ClInclude Include="..\libusb\os\threads_windows.h" /> <ClInclude Include="..\libusb\version.h" /> <ClInclude Include="..\libusb\version_nano.h" /> diff --git a/msvc/libusb_static_2013.vcxproj.filters b/msvc/libusb_static_2013.vcxproj.filters index c35bf87..2994ca1 100644 --- a/msvc/libusb_static_2013.vcxproj.filters +++ b/msvc/libusb_static_2013.vcxproj.filters @@ -14,6 +14,9 @@ <ClInclude Include=".\config.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\libusb\os\events_windows.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\libusb\hotplug.h"> <Filter>Header Files</Filter> </ClInclude> @@ -23,9 +26,6 @@ <ClInclude Include="..\libusb\libusbi.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\libusb\os\poll_windows.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\libusb\os\threads_windows.h"> <Filter>Header Files</Filter> </ClInclude> @@ -52,13 +52,13 @@ <ClCompile Include="..\libusb\descriptor.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\hotplug.c"> + <ClCompile Include="..\libusb\os\events_windows.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\io.c"> + <ClCompile Include="..\libusb\hotplug.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\os\poll_windows.c"> + <ClCompile Include="..\libusb\io.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\libusb\strerror.c"> diff --git a/msvc/libusb_static_2015.vcxproj b/msvc/libusb_static_2015.vcxproj index ba07666..9fa30da 100644 --- a/msvc/libusb_static_2015.vcxproj +++ b/msvc/libusb_static_2015.vcxproj @@ -67,9 +67,9 @@ <ItemGroup> <ClCompile Include="..\libusb\core.c" /> <ClCompile Include="..\libusb\descriptor.c" /> + <ClCompile Include="..\libusb\os\events_windows.c" /> <ClCompile Include="..\libusb\hotplug.c" /> <ClCompile Include="..\libusb\io.c" /> - <ClCompile Include="..\libusb\os\poll_windows.c" /> <ClCompile Include="..\libusb\strerror.c" /> <ClCompile Include="..\libusb\sync.c" /> <ClCompile Include="..\libusb\os\threads_windows.c" /> @@ -79,10 +79,10 @@ </ItemGroup> <ItemGroup> <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\os\events_windows.h" /> <ClInclude Include="..\libusb\hotplug.h" /> <ClInclude Include="..\libusb\libusb.h" /> <ClInclude Include="..\libusb\libusbi.h" /> - <ClInclude Include="..\libusb\os\poll_windows.h" /> <ClInclude Include="..\libusb\os\threads_windows.h" /> <ClInclude Include="..\libusb\version.h" /> <ClInclude Include="..\libusb\version_nano.h" /> diff --git a/msvc/libusb_static_2015.vcxproj.filters b/msvc/libusb_static_2015.vcxproj.filters index c35bf87..2994ca1 100644 --- a/msvc/libusb_static_2015.vcxproj.filters +++ b/msvc/libusb_static_2015.vcxproj.filters @@ -14,6 +14,9 @@ <ClInclude Include=".\config.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\libusb\os\events_windows.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\libusb\hotplug.h"> <Filter>Header Files</Filter> </ClInclude> @@ -23,9 +26,6 @@ <ClInclude Include="..\libusb\libusbi.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\libusb\os\poll_windows.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\libusb\os\threads_windows.h"> <Filter>Header Files</Filter> </ClInclude> @@ -52,13 +52,13 @@ <ClCompile Include="..\libusb\descriptor.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\hotplug.c"> + <ClCompile Include="..\libusb\os\events_windows.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\io.c"> + <ClCompile Include="..\libusb\hotplug.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\os\poll_windows.c"> + <ClCompile Include="..\libusb\io.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\libusb\strerror.c"> diff --git a/msvc/libusb_static_2017.vcxproj b/msvc/libusb_static_2017.vcxproj index 08816d2..62076e0 100644 --- a/msvc/libusb_static_2017.vcxproj +++ b/msvc/libusb_static_2017.vcxproj @@ -86,9 +86,9 @@ <ItemGroup> <ClCompile Include="..\libusb\core.c" /> <ClCompile Include="..\libusb\descriptor.c" /> + <ClCompile Include="..\libusb\os\events_windows.c" /> <ClCompile Include="..\libusb\hotplug.c" /> <ClCompile Include="..\libusb\io.c" /> - <ClCompile Include="..\libusb\os\poll_windows.c" /> <ClCompile Include="..\libusb\strerror.c" /> <ClCompile Include="..\libusb\sync.c" /> <ClCompile Include="..\libusb\os\threads_windows.c" /> @@ -98,10 +98,10 @@ </ItemGroup> <ItemGroup> <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\os\events_windows.h" /> <ClInclude Include="..\libusb\hotplug.h" /> <ClInclude Include="..\libusb\libusb.h" /> <ClInclude Include="..\libusb\libusbi.h" /> - <ClInclude Include="..\libusb\os\poll_windows.h" /> <ClInclude Include="..\libusb\os\threads_windows.h" /> <ClInclude Include="..\libusb\version.h" /> <ClInclude Include="..\libusb\version_nano.h" /> diff --git a/msvc/libusb_static_2017.vcxproj.filters b/msvc/libusb_static_2017.vcxproj.filters index c35bf87..2994ca1 100644 --- a/msvc/libusb_static_2017.vcxproj.filters +++ b/msvc/libusb_static_2017.vcxproj.filters @@ -14,6 +14,9 @@ <ClInclude Include=".\config.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\libusb\os\events_windows.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\libusb\hotplug.h"> <Filter>Header Files</Filter> </ClInclude> @@ -23,9 +26,6 @@ <ClInclude Include="..\libusb\libusbi.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\libusb\os\poll_windows.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\libusb\os\threads_windows.h"> <Filter>Header Files</Filter> </ClInclude> @@ -52,13 +52,13 @@ <ClCompile Include="..\libusb\descriptor.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\hotplug.c"> + <ClCompile Include="..\libusb\os\events_windows.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\io.c"> + <ClCompile Include="..\libusb\hotplug.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\os\poll_windows.c"> + <ClCompile Include="..\libusb\io.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\libusb\strerror.c"> diff --git a/msvc/libusb_static_2019.vcxproj b/msvc/libusb_static_2019.vcxproj index 24ab3e3..60ad642 100644 --- a/msvc/libusb_static_2019.vcxproj +++ b/msvc/libusb_static_2019.vcxproj @@ -86,9 +86,9 @@ <ItemGroup> <ClCompile Include="..\libusb\core.c" /> <ClCompile Include="..\libusb\descriptor.c" /> + <ClCompile Include="..\libusb\os\events_windows.c" /> <ClCompile Include="..\libusb\hotplug.c" /> <ClCompile Include="..\libusb\io.c" /> - <ClCompile Include="..\libusb\os\poll_windows.c" /> <ClCompile Include="..\libusb\strerror.c" /> <ClCompile Include="..\libusb\sync.c" /> <ClCompile Include="..\libusb\os\threads_windows.c" /> @@ -98,10 +98,10 @@ </ItemGroup> <ItemGroup> <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\os\events_windows.h" /> <ClInclude Include="..\libusb\hotplug.h" /> <ClInclude Include="..\libusb\libusb.h" /> <ClInclude Include="..\libusb\libusbi.h" /> - <ClInclude Include="..\libusb\os\poll_windows.h" /> <ClInclude Include="..\libusb\os\threads_windows.h" /> <ClInclude Include="..\libusb\version.h" /> <ClInclude Include="..\libusb\version_nano.h" /> diff --git a/msvc/libusb_static_2019.vcxproj.filters b/msvc/libusb_static_2019.vcxproj.filters index c35bf87..2994ca1 100644 --- a/msvc/libusb_static_2019.vcxproj.filters +++ b/msvc/libusb_static_2019.vcxproj.filters @@ -14,6 +14,9 @@ <ClInclude Include=".\config.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\libusb\os\events_windows.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\libusb\hotplug.h"> <Filter>Header Files</Filter> </ClInclude> @@ -23,9 +26,6 @@ <ClInclude Include="..\libusb\libusbi.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\libusb\os\poll_windows.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\libusb\os\threads_windows.h"> <Filter>Header Files</Filter> </ClInclude> @@ -52,13 +52,13 @@ <ClCompile Include="..\libusb\descriptor.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\hotplug.c"> + <ClCompile Include="..\libusb\os\events_windows.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\io.c"> + <ClCompile Include="..\libusb\hotplug.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\libusb\os\poll_windows.c"> + <ClCompile Include="..\libusb\io.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="..\libusb\strerror.c"> diff --git a/msvc/listdevs_2013.vcxproj b/msvc/listdevs_2013.vcxproj index b1c51fd..08c0a3f 100644 --- a/msvc/listdevs_2013.vcxproj +++ b/msvc/listdevs_2013.vcxproj @@ -45,7 +45,7 @@ </PropertyGroup> <ItemDefinitionGroup> <ClCompile> - <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <WarningLevel>Level3</WarningLevel> </ClCompile> @@ -72,6 +72,9 @@ <ClCompile Include="..\examples\listdevs.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include=".\libusb_static_2013.vcxproj"> <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> diff --git a/msvc/listdevs_2013.vcxproj.filters b/msvc/listdevs_2013.vcxproj.filters index c33708f..895e2bc 100644 --- a/msvc/listdevs_2013.vcxproj.filters +++ b/msvc/listdevs_2013.vcxproj.filters @@ -5,6 +5,15 @@ <UniqueIdentifier>{2ceecece-c641-4d87-8e75-ea3622a2a50c}</UniqueIdentifier> <Extensions>c</Extensions> </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{6162aa6f-aa3a-43b0-92b2-f40207a0b581}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\listdevs.c"> diff --git a/msvc/listdevs_2015.vcxproj b/msvc/listdevs_2015.vcxproj index 110fa5a..7791894 100644 --- a/msvc/listdevs_2015.vcxproj +++ b/msvc/listdevs_2015.vcxproj @@ -46,7 +46,7 @@ <ItemDefinitionGroup> <ClCompile> <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> - <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <WarningLevel>Level3</WarningLevel> </ClCompile> @@ -72,6 +72,9 @@ <ClCompile Include="..\examples\listdevs.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include=".\libusb_static_2015.vcxproj"> <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> diff --git a/msvc/listdevs_2015.vcxproj.filters b/msvc/listdevs_2015.vcxproj.filters index c33708f..895e2bc 100644 --- a/msvc/listdevs_2015.vcxproj.filters +++ b/msvc/listdevs_2015.vcxproj.filters @@ -5,6 +5,15 @@ <UniqueIdentifier>{2ceecece-c641-4d87-8e75-ea3622a2a50c}</UniqueIdentifier> <Extensions>c</Extensions> </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{6162aa6f-aa3a-43b0-92b2-f40207a0b581}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\listdevs.c"> diff --git a/msvc/listdevs_2017.vcxproj b/msvc/listdevs_2017.vcxproj index b685238..f7ae424 100644 --- a/msvc/listdevs_2017.vcxproj +++ b/msvc/listdevs_2017.vcxproj @@ -65,7 +65,7 @@ <ItemDefinitionGroup> <ClCompile> <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> - <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <WarningLevel>Level3</WarningLevel> </ClCompile> @@ -91,6 +91,9 @@ <ClCompile Include="..\examples\listdevs.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include=".\libusb_static_2017.vcxproj"> <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> diff --git a/msvc/listdevs_2017.vcxproj.filters b/msvc/listdevs_2017.vcxproj.filters index c33708f..895e2bc 100644 --- a/msvc/listdevs_2017.vcxproj.filters +++ b/msvc/listdevs_2017.vcxproj.filters @@ -5,6 +5,15 @@ <UniqueIdentifier>{2ceecece-c641-4d87-8e75-ea3622a2a50c}</UniqueIdentifier> <Extensions>c</Extensions> </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{6162aa6f-aa3a-43b0-92b2-f40207a0b581}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\listdevs.c"> diff --git a/msvc/listdevs_2019.vcxproj b/msvc/listdevs_2019.vcxproj index cbab3d4..cbb97cf 100644 --- a/msvc/listdevs_2019.vcxproj +++ b/msvc/listdevs_2019.vcxproj @@ -65,7 +65,7 @@ <ItemDefinitionGroup> <ClCompile> <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> - <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <WarningLevel>Level3</WarningLevel> </ClCompile> @@ -91,6 +91,9 @@ <ClCompile Include="..\examples\listdevs.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include=".\libusb_static_2019.vcxproj"> <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> diff --git a/msvc/listdevs_2019.vcxproj.filters b/msvc/listdevs_2019.vcxproj.filters index c33708f..895e2bc 100644 --- a/msvc/listdevs_2019.vcxproj.filters +++ b/msvc/listdevs_2019.vcxproj.filters @@ -5,6 +5,15 @@ <UniqueIdentifier>{2ceecece-c641-4d87-8e75-ea3622a2a50c}</UniqueIdentifier> <Extensions>c</Extensions> </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{6162aa6f-aa3a-43b0-92b2-f40207a0b581}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\listdevs.c"> diff --git a/msvc/sam3u_benchmark_2013.vcxproj b/msvc/sam3u_benchmark_2013.vcxproj new file mode 100644 index 0000000..42a1cb1 --- /dev/null +++ b/msvc/sam3u_benchmark_2013.vcxproj @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>sam3u_benchmark</ProjectName> + <ProjectGuid>{861cdd5f-59a2-4f34-957e-5c1af98be0a4}</ProjectGuid> + <RootNamespace>examples</RootNamespace> + <Keyword>Win32Proj</Keyword> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + <WholeProgramOptimization Condition="'$(Configuration)'=='Release'">true</WholeProgramOptimization> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <IntDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\</IntDir> + <OutDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <WarningLevel>Level3</WarningLevel> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Debug'"> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <MinimalRebuild>true</MinimalRebuild> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Release'"> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <ProgramDatabaseFile>$(TargetDir)$(ProjectName).pdb</ProgramDatabaseFile> + <SubSystem>Console</SubSystem> + <AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link Condition="'$(Configuration)'=='Debug'"> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\examples\sam3u_benchmark.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include=".\libusb_static_2013.vcxproj"> + <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/msvc/sam3u_benchmark_2013.vcxproj.filters b/msvc/sam3u_benchmark_2013.vcxproj.filters new file mode 100644 index 0000000..e0f6bd0 --- /dev/null +++ b/msvc/sam3u_benchmark_2013.vcxproj.filters @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{a19ef59c-c0d8-48a6-8d62-c158c7bac2fe}</UniqueIdentifier> + <Extensions>c</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{5a6ad543-f221-4cb6-addd-c9020acd752e}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\examples\sam3u_benchmark.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/msvc/sam3u_benchmark_2015.vcxproj b/msvc/sam3u_benchmark_2015.vcxproj new file mode 100644 index 0000000..7d2d2e6 --- /dev/null +++ b/msvc/sam3u_benchmark_2015.vcxproj @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>sam3u_benchmark</ProjectName> + <ProjectGuid>{861cdd5f-59a2-4f34-957e-5c1af98be0a4}</ProjectGuid> + <RootNamespace>examples</RootNamespace> + <Keyword>Win32Proj</Keyword> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v140</PlatformToolset> + <WholeProgramOptimization Condition="'$(Configuration)'=='Release'">true</WholeProgramOptimization> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <IntDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\</IntDir> + <OutDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <WarningLevel>Level3</WarningLevel> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Debug'"> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Release'"> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <ProgramDatabaseFile>$(TargetDir)$(ProjectName).pdb</ProgramDatabaseFile> + <SubSystem>Console</SubSystem> + <AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link Condition="'$(Configuration)'=='Debug'"> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\examples\sam3u_benchmark.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include=".\libusb_static_2015.vcxproj"> + <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/msvc/sam3u_benchmark_2015.vcxproj.filters b/msvc/sam3u_benchmark_2015.vcxproj.filters new file mode 100644 index 0000000..e0f6bd0 --- /dev/null +++ b/msvc/sam3u_benchmark_2015.vcxproj.filters @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{a19ef59c-c0d8-48a6-8d62-c158c7bac2fe}</UniqueIdentifier> + <Extensions>c</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{5a6ad543-f221-4cb6-addd-c9020acd752e}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\examples\sam3u_benchmark.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/msvc/sam3u_benchmark_2017.vcxproj b/msvc/sam3u_benchmark_2017.vcxproj new file mode 100644 index 0000000..ca29706 --- /dev/null +++ b/msvc/sam3u_benchmark_2017.vcxproj @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|ARM"> + <Configuration>Debug</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|ARM64"> + <Configuration>Debug</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM"> + <Configuration>Release</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM64"> + <Configuration>Release</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>sam3u_benchmark</ProjectName> + <ProjectGuid>{861cdd5f-59a2-4f34-957e-5c1af98be0a4}</ProjectGuid> + <RootNamespace>examples</RootNamespace> + <Keyword>Win32Proj</Keyword> + <WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport> + <WindowsSDKDesktopARM64Support>true</WindowsSDKDesktopARM64Support> + <WindowsTargetPlatformVersion Condition="'$(Platform)'=='ARM' Or '$(Platform)'=='ARM64'">10.0.17763.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization Condition="'$(Configuration)'=='Release'">true</WholeProgramOptimization> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <IntDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\</IntDir> + <OutDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <WarningLevel>Level3</WarningLevel> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Debug'"> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Release'"> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <ProgramDatabaseFile>$(TargetDir)$(ProjectName).pdb</ProgramDatabaseFile> + <SubSystem>Console</SubSystem> + <AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link Condition="'$(Configuration)'=='Debug'"> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\examples\sam3u_benchmark.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include=".\libusb_static_2017.vcxproj"> + <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/msvc/sam3u_benchmark_2017.vcxproj.filters b/msvc/sam3u_benchmark_2017.vcxproj.filters new file mode 100644 index 0000000..e0f6bd0 --- /dev/null +++ b/msvc/sam3u_benchmark_2017.vcxproj.filters @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{a19ef59c-c0d8-48a6-8d62-c158c7bac2fe}</UniqueIdentifier> + <Extensions>c</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{5a6ad543-f221-4cb6-addd-c9020acd752e}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\examples\sam3u_benchmark.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/msvc/sam3u_benchmark_2019.vcxproj b/msvc/sam3u_benchmark_2019.vcxproj new file mode 100644 index 0000000..fd5317a --- /dev/null +++ b/msvc/sam3u_benchmark_2019.vcxproj @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|ARM"> + <Configuration>Debug</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|ARM64"> + <Configuration>Debug</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM"> + <Configuration>Release</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM64"> + <Configuration>Release</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>sam3u_benchmark</ProjectName> + <ProjectGuid>{861cdd5f-59a2-4f34-957e-5c1af98be0a4}</ProjectGuid> + <RootNamespace>examples</RootNamespace> + <Keyword>Win32Proj</Keyword> + <WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport> + <WindowsSDKDesktopARM64Support>true</WindowsSDKDesktopARM64Support> + <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v142</PlatformToolset> + <WholeProgramOptimization Condition="'$(Configuration)'=='Release'">true</WholeProgramOptimization> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <IntDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\</IntDir> + <OutDir>$(ProjectDir)..\$(Platform)\$(Configuration)\examples\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <WarningLevel>Level3</WarningLevel> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Debug'"> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <ClCompile Condition="'$(Configuration)'=='Release'"> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <ProgramDatabaseFile>$(TargetDir)$(ProjectName).pdb</ProgramDatabaseFile> + <SubSystem>Console</SubSystem> + <AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link Condition="'$(Configuration)'=='Debug'"> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\examples\sam3u_benchmark.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include=".\libusb_static_2019.vcxproj"> + <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/msvc/sam3u_benchmark_2019.vcxproj.filters b/msvc/sam3u_benchmark_2019.vcxproj.filters new file mode 100644 index 0000000..e0f6bd0 --- /dev/null +++ b/msvc/sam3u_benchmark_2019.vcxproj.filters @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{a19ef59c-c0d8-48a6-8d62-c158c7bac2fe}</UniqueIdentifier> + <Extensions>c</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{5a6ad543-f221-4cb6-addd-c9020acd752e}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\examples\sam3u_benchmark.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/msvc/stress_2013.vcxproj b/msvc/stress_2013.vcxproj index 83c1f16..2d5a3c1 100644 --- a/msvc/stress_2013.vcxproj +++ b/msvc/stress_2013.vcxproj @@ -73,6 +73,8 @@ <ClCompile Include="..\tests\testlib.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\libusb.h" /> <ClInclude Include="..\tests\libusb_testlib.h" /> </ItemGroup> <ItemGroup> diff --git a/msvc/stress_2013.vcxproj.filters b/msvc/stress_2013.vcxproj.filters index 9d821b3..9c867ea 100644 --- a/msvc/stress_2013.vcxproj.filters +++ b/msvc/stress_2013.vcxproj.filters @@ -11,6 +11,12 @@ </Filter> </ItemGroup> <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\tests\libusb_testlib.h"> <Filter>Header Files</Filter> </ClInclude> diff --git a/msvc/stress_2015.vcxproj b/msvc/stress_2015.vcxproj index 85a2cc3..dc1d1d2 100644 --- a/msvc/stress_2015.vcxproj +++ b/msvc/stress_2015.vcxproj @@ -73,6 +73,8 @@ <ClCompile Include="..\tests\testlib.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\libusb.h" /> <ClInclude Include="..\tests\libusb_testlib.h" /> </ItemGroup> <ItemGroup> diff --git a/msvc/stress_2015.vcxproj.filters b/msvc/stress_2015.vcxproj.filters index 9d821b3..9c867ea 100644 --- a/msvc/stress_2015.vcxproj.filters +++ b/msvc/stress_2015.vcxproj.filters @@ -11,6 +11,12 @@ </Filter> </ItemGroup> <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\tests\libusb_testlib.h"> <Filter>Header Files</Filter> </ClInclude> diff --git a/msvc/stress_2017.vcxproj b/msvc/stress_2017.vcxproj index d2dea81..9d412db 100644 --- a/msvc/stress_2017.vcxproj +++ b/msvc/stress_2017.vcxproj @@ -92,6 +92,8 @@ <ClCompile Include="..\tests\testlib.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\libusb.h" /> <ClInclude Include="..\tests\libusb_testlib.h" /> </ItemGroup> <ItemGroup> diff --git a/msvc/stress_2017.vcxproj.filters b/msvc/stress_2017.vcxproj.filters index 9d821b3..9c867ea 100644 --- a/msvc/stress_2017.vcxproj.filters +++ b/msvc/stress_2017.vcxproj.filters @@ -11,6 +11,12 @@ </Filter> </ItemGroup> <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\tests\libusb_testlib.h"> <Filter>Header Files</Filter> </ClInclude> diff --git a/msvc/stress_2019.vcxproj b/msvc/stress_2019.vcxproj index a89920f..d9ca666 100644 --- a/msvc/stress_2019.vcxproj +++ b/msvc/stress_2019.vcxproj @@ -92,6 +92,8 @@ <ClCompile Include="..\tests\testlib.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include=".\config.h" /> + <ClInclude Include="..\libusb\libusb.h" /> <ClInclude Include="..\tests\libusb_testlib.h" /> </ItemGroup> <ItemGroup> diff --git a/msvc/stress_2019.vcxproj.filters b/msvc/stress_2019.vcxproj.filters index 9d821b3..9c867ea 100644 --- a/msvc/stress_2019.vcxproj.filters +++ b/msvc/stress_2019.vcxproj.filters @@ -11,6 +11,12 @@ </Filter> </ItemGroup> <ItemGroup> + <ClInclude Include=".\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\tests\libusb_testlib.h"> <Filter>Header Files</Filter> </ClInclude> diff --git a/msvc/testlibusb_2013.vcxproj b/msvc/testlibusb_2013.vcxproj index 4c8a107..dd7f1b6 100644 --- a/msvc/testlibusb_2013.vcxproj +++ b/msvc/testlibusb_2013.vcxproj @@ -45,7 +45,7 @@ </PropertyGroup> <ItemDefinitionGroup> <ClCompile> - <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <WarningLevel>Level3</WarningLevel> </ClCompile> @@ -72,6 +72,9 @@ <ClCompile Include="..\examples\testlibusb.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include=".\libusb_static_2013.vcxproj"> <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> diff --git a/msvc/testlibusb_2013.vcxproj.filters b/msvc/testlibusb_2013.vcxproj.filters index 9db38ab..d655f83 100644 --- a/msvc/testlibusb_2013.vcxproj.filters +++ b/msvc/testlibusb_2013.vcxproj.filters @@ -5,6 +5,15 @@ <UniqueIdentifier>{4a89b408-009b-41e4-bb05-78f07a7c7f82}</UniqueIdentifier> <Extensions>c</Extensions> </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{9dc8bfc2-c1d0-41d9-9fd2-858137d5d7c7}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\testlibusb.c"> diff --git a/msvc/testlibusb_2015.vcxproj b/msvc/testlibusb_2015.vcxproj index 609e23a..c2f356b 100644 --- a/msvc/testlibusb_2015.vcxproj +++ b/msvc/testlibusb_2015.vcxproj @@ -46,7 +46,7 @@ <ItemDefinitionGroup> <ClCompile> <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> - <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <WarningLevel>Level3</WarningLevel> </ClCompile> @@ -72,6 +72,9 @@ <ClCompile Include="..\examples\testlibusb.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include=".\libusb_static_2015.vcxproj"> <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> diff --git a/msvc/testlibusb_2015.vcxproj.filters b/msvc/testlibusb_2015.vcxproj.filters index 9db38ab..d655f83 100644 --- a/msvc/testlibusb_2015.vcxproj.filters +++ b/msvc/testlibusb_2015.vcxproj.filters @@ -5,6 +5,15 @@ <UniqueIdentifier>{4a89b408-009b-41e4-bb05-78f07a7c7f82}</UniqueIdentifier> <Extensions>c</Extensions> </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{9dc8bfc2-c1d0-41d9-9fd2-858137d5d7c7}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\testlibusb.c"> diff --git a/msvc/testlibusb_2017.vcxproj b/msvc/testlibusb_2017.vcxproj index 67c7c88..c7cbc84 100644 --- a/msvc/testlibusb_2017.vcxproj +++ b/msvc/testlibusb_2017.vcxproj @@ -65,7 +65,7 @@ <ItemDefinitionGroup> <ClCompile> <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> - <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <WarningLevel>Level3</WarningLevel> </ClCompile> @@ -91,6 +91,9 @@ <ClCompile Include="..\examples\testlibusb.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include=".\libusb_static_2017.vcxproj"> <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> diff --git a/msvc/testlibusb_2017.vcxproj.filters b/msvc/testlibusb_2017.vcxproj.filters index 9db38ab..d655f83 100644 --- a/msvc/testlibusb_2017.vcxproj.filters +++ b/msvc/testlibusb_2017.vcxproj.filters @@ -5,6 +5,15 @@ <UniqueIdentifier>{4a89b408-009b-41e4-bb05-78f07a7c7f82}</UniqueIdentifier> <Extensions>c</Extensions> </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{9dc8bfc2-c1d0-41d9-9fd2-858137d5d7c7}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\testlibusb.c"> diff --git a/msvc/testlibusb_2019.vcxproj b/msvc/testlibusb_2019.vcxproj index aec8c07..896d4fb 100644 --- a/msvc/testlibusb_2019.vcxproj +++ b/msvc/testlibusb_2019.vcxproj @@ -65,7 +65,7 @@ <ItemDefinitionGroup> <ClCompile> <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> - <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <WarningLevel>Level3</WarningLevel> </ClCompile> @@ -91,6 +91,9 @@ <ClCompile Include="..\examples\testlibusb.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include=".\libusb_static_2019.vcxproj"> <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> diff --git a/msvc/testlibusb_2019.vcxproj.filters b/msvc/testlibusb_2019.vcxproj.filters index 9db38ab..d655f83 100644 --- a/msvc/testlibusb_2019.vcxproj.filters +++ b/msvc/testlibusb_2019.vcxproj.filters @@ -5,6 +5,15 @@ <UniqueIdentifier>{4a89b408-009b-41e4-bb05-78f07a7c7f82}</UniqueIdentifier> <Extensions>c</Extensions> </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{9dc8bfc2-c1d0-41d9-9fd2-858137d5d7c7}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\testlibusb.c"> diff --git a/msvc/xusb_2013.vcxproj b/msvc/xusb_2013.vcxproj index 195c73d..ba9cd72 100644 --- a/msvc/xusb_2013.vcxproj +++ b/msvc/xusb_2013.vcxproj @@ -45,7 +45,7 @@ </PropertyGroup> <ItemDefinitionGroup> <ClCompile> - <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <WarningLevel>Level3</WarningLevel> </ClCompile> @@ -72,6 +72,9 @@ <ClCompile Include="..\examples\xusb.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include=".\libusb_static_2013.vcxproj"> <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> diff --git a/msvc/xusb_2013.vcxproj.filters b/msvc/xusb_2013.vcxproj.filters index e29356d..30dca26 100644 --- a/msvc/xusb_2013.vcxproj.filters +++ b/msvc/xusb_2013.vcxproj.filters @@ -5,6 +5,15 @@ <UniqueIdentifier>{4bdcefa9-8c79-431b-965b-15b234737380}</UniqueIdentifier> <Extensions>c</Extensions> </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{f81e24cd-e12b-4324-ada3-accbab00ef08}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\xusb.c"> diff --git a/msvc/xusb_2015.vcxproj b/msvc/xusb_2015.vcxproj index 1393007..1b5d944 100644 --- a/msvc/xusb_2015.vcxproj +++ b/msvc/xusb_2015.vcxproj @@ -46,7 +46,7 @@ <ItemDefinitionGroup> <ClCompile> <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> - <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <WarningLevel>Level3</WarningLevel> </ClCompile> @@ -72,6 +72,9 @@ <ClCompile Include="..\examples\xusb.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include=".\libusb_static_2015.vcxproj"> <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> diff --git a/msvc/xusb_2015.vcxproj.filters b/msvc/xusb_2015.vcxproj.filters index e29356d..30dca26 100644 --- a/msvc/xusb_2015.vcxproj.filters +++ b/msvc/xusb_2015.vcxproj.filters @@ -5,6 +5,15 @@ <UniqueIdentifier>{4bdcefa9-8c79-431b-965b-15b234737380}</UniqueIdentifier> <Extensions>c</Extensions> </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{f81e24cd-e12b-4324-ada3-accbab00ef08}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\xusb.c"> diff --git a/msvc/xusb_2017.vcxproj b/msvc/xusb_2017.vcxproj index 7ffb546..4526d94 100644 --- a/msvc/xusb_2017.vcxproj +++ b/msvc/xusb_2017.vcxproj @@ -65,7 +65,7 @@ <ItemDefinitionGroup> <ClCompile> <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> - <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <WarningLevel>Level3</WarningLevel> </ClCompile> @@ -91,6 +91,9 @@ <ClCompile Include="..\examples\xusb.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include=".\libusb_static_2017.vcxproj"> <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> diff --git a/msvc/xusb_2017.vcxproj.filters b/msvc/xusb_2017.vcxproj.filters index e29356d..30dca26 100644 --- a/msvc/xusb_2017.vcxproj.filters +++ b/msvc/xusb_2017.vcxproj.filters @@ -5,6 +5,15 @@ <UniqueIdentifier>{4bdcefa9-8c79-431b-965b-15b234737380}</UniqueIdentifier> <Extensions>c</Extensions> </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{f81e24cd-e12b-4324-ada3-accbab00ef08}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\xusb.c"> diff --git a/msvc/xusb_2019.vcxproj b/msvc/xusb_2019.vcxproj index adefefb..d61b0cb 100644 --- a/msvc/xusb_2019.vcxproj +++ b/msvc/xusb_2019.vcxproj @@ -65,7 +65,7 @@ <ItemDefinitionGroup> <ClCompile> <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions> - <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <WarningLevel>Level3</WarningLevel> </ClCompile> @@ -91,6 +91,9 @@ <ClCompile Include="..\examples\xusb.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\libusb\libusb.h" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include=".\libusb_static_2019.vcxproj"> <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> diff --git a/msvc/xusb_2019.vcxproj.filters b/msvc/xusb_2019.vcxproj.filters index e29356d..30dca26 100644 --- a/msvc/xusb_2019.vcxproj.filters +++ b/msvc/xusb_2019.vcxproj.filters @@ -5,6 +5,15 @@ <UniqueIdentifier>{4bdcefa9-8c79-431b-965b-15b234737380}</UniqueIdentifier> <Extensions>c</Extensions> </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{f81e24cd-e12b-4324-ada3-accbab00ef08}</UniqueIdentifier> + <Extensions>h</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\libusb\libusb.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\examples\xusb.c"> diff --git a/tests/Makefile.am b/tests/Makefile.am index cb8fad9..157c2a2 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -4,4 +4,4 @@ LIBS = noinst_PROGRAMS = stress -stress_SOURCES = stress.c libusb_testlib.h testlib.c +stress_SOURCES = stress.c libusb_testlib.h testlib.c config.h diff --git a/tests/libusb_testlib.h b/tests/libusb_testlib.h index 6c987d3..145f4e6 100644 --- a/tests/libusb_testlib.h +++ b/tests/libusb_testlib.h @@ -20,17 +20,7 @@ #ifndef LIBUSB_TESTLIB_H #define LIBUSB_TESTLIB_H -#include <stdio.h> - -#if !defined(bool) -#define bool int -#endif -#if !defined(true) -#define true (1 == 1) -#endif -#if !defined(false) -#define false (!true) -#endif +#include <config.h> /** Values returned from a test function to indicate test result */ typedef enum { @@ -41,53 +31,33 @@ typedef enum { /** Indicates that an unexpected error occurred. */ TEST_STATUS_ERROR, /** Indicates that the test can't be run. For example this may be - * due to no suitable device being connected to perform the tests.*/ + * due to no suitable device being connected to perform the tests. */ TEST_STATUS_SKIP } libusb_testlib_result; /** - * Context for test library functions - */ -typedef struct { - char ** test_names; - int test_count; - bool list_tests; - bool verbose; - int old_stdout; - int old_stderr; - FILE* output_file; - int null_fd; -} libusb_testlib_ctx; - -/** * Logs some test information or state */ -void libusb_testlib_logf(libusb_testlib_ctx * ctx, - const char* fmt, ...); - -/** - * Function pointer for a libusb test function. - * - * Should return TEST_STATUS_SUCCESS on success or another TEST_STATUS value. - */ -typedef libusb_testlib_result -(*libusb_testlib_test_function)(libusb_testlib_ctx * ctx); +void libusb_testlib_logf(const char *fmt, ...) PRINTF_FORMAT(1, 2); /** * Structure holding a test description. */ typedef struct { /** Human readable name of the test. */ - const char * name; - /** The test library will call this function to run the test. */ - libusb_testlib_test_function function; + const char *name; + /** The test library will call this function to run the test. + * + * Should return TEST_STATUS_SUCCESS on success or another TEST_STATUS value. + */ + libusb_testlib_result (*function)(void); } libusb_testlib_test; /** * Value to use at the end of a test array to indicate the last * element. */ -#define LIBUSB_NULL_TEST {NULL, NULL} +#define LIBUSB_NULL_TEST { NULL, NULL } /** * Runs the tests provided. @@ -100,8 +70,7 @@ typedef struct { * \param tests A NULL_TEST terminated array of tests * \return 0 on success, non-zero on failure */ -int libusb_testlib_run_tests(int argc, - char ** argv, - const libusb_testlib_test * tests); +int libusb_testlib_run_tests(int argc, char *argv[], + const libusb_testlib_test *tests); #endif //LIBUSB_TESTLIB_H diff --git a/tests/stress.c b/tests/stress.c index 0e2dbe5..6dcb8f3 100644 --- a/tests/stress.c +++ b/tests/stress.c @@ -17,111 +17,116 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <stdio.h> +#include <config.h> + #include <string.h> -#include <memory.h> #include "libusb.h" #include "libusb_testlib.h" /** Test that creates and destroys a single concurrent context * 10000 times. */ -static libusb_testlib_result test_init_and_exit(libusb_testlib_ctx * tctx) +static libusb_testlib_result test_init_and_exit(void) { - libusb_context * ctx = NULL; - int i; - for (i = 0; i < 10000; ++i) { - int r = libusb_init(&ctx); + for (int i = 0; i < 10000; ++i) { + libusb_context *ctx = NULL; + int r; + + r = libusb_init(&ctx); if (r != LIBUSB_SUCCESS) { - libusb_testlib_logf(tctx, + libusb_testlib_logf( "Failed to init libusb on iteration %d: %d", i, r); return TEST_STATUS_FAILURE; } libusb_exit(ctx); - ctx = NULL; } return TEST_STATUS_SUCCESS; } /** Tests that devices can be listed 1000 times. */ -static libusb_testlib_result test_get_device_list(libusb_testlib_ctx * tctx) +static libusb_testlib_result test_get_device_list(void) { - libusb_context * ctx = NULL; - int r, i; + libusb_context *ctx; + int r; + r = libusb_init(&ctx); if (r != LIBUSB_SUCCESS) { - libusb_testlib_logf(tctx, "Failed to init libusb: %d", r); + libusb_testlib_logf("Failed to init libusb: %d", r); return TEST_STATUS_FAILURE; } - for (i = 0; i < 1000; ++i) { - libusb_device ** device_list; + + for (int i = 0; i < 1000; ++i) { + libusb_device **device_list = NULL; ssize_t list_size = libusb_get_device_list(ctx, &device_list); - if (list_size < 0 || device_list == NULL) { - libusb_testlib_logf(tctx, - "Failed to get device list on iteration %d: %d (%p)", - i, -list_size, device_list); + if (list_size < 0 || !device_list) { + libusb_testlib_logf( + "Failed to get device list on iteration %d: %ld (%p)", + i, (long)-list_size, device_list); + libusb_exit(ctx); return TEST_STATUS_FAILURE; } libusb_free_device_list(device_list, 1); } + libusb_exit(ctx); return TEST_STATUS_SUCCESS; } /** Tests that 100 concurrent device lists can be open at a time. */ -static libusb_testlib_result test_many_device_lists(libusb_testlib_ctx * tctx) +static libusb_testlib_result test_many_device_lists(void) { #define LIST_COUNT 100 - libusb_context * ctx = NULL; - libusb_device ** device_lists[LIST_COUNT]; - int r, i; - memset(device_lists, 0, sizeof(device_lists)); + libusb_testlib_result result = TEST_STATUS_SUCCESS; + libusb_context *ctx = NULL; + libusb_device **device_lists[LIST_COUNT]; + int r; r = libusb_init(&ctx); if (r != LIBUSB_SUCCESS) { - libusb_testlib_logf(tctx, "Failed to init libusb: %d", r); + libusb_testlib_logf("Failed to init libusb: %d", r); return TEST_STATUS_FAILURE; } + memset(device_lists, 0, sizeof(device_lists)); + /* Create the 100 device lists. */ - for (i = 0; i < LIST_COUNT; ++i) { - ssize_t list_size = libusb_get_device_list(ctx, &(device_lists[i])); - if (list_size < 0 || device_lists[i] == NULL) { - libusb_testlib_logf(tctx, - "Failed to get device list on iteration %d: %d (%p)", - i, -list_size, device_lists[i]); - return TEST_STATUS_FAILURE; + for (int i = 0; i < LIST_COUNT; ++i) { + ssize_t list_size = libusb_get_device_list(ctx, &device_lists[i]); + if (list_size < 0 || !device_lists[i]) { + libusb_testlib_logf( + "Failed to get device list on iteration %d: %ld (%p)", + i, (long)-list_size, device_lists[i]); + result = TEST_STATUS_FAILURE; + break; } } /* Destroy the 100 device lists. */ - for (i = 0; i < LIST_COUNT; ++i) { - if (device_lists[i]) { + for (int i = 0; i < LIST_COUNT; ++i) { + if (device_lists[i]) libusb_free_device_list(device_lists[i], 1); - device_lists[i] = NULL; - } } libusb_exit(ctx); - return TEST_STATUS_SUCCESS; + return result; #undef LIST_COUNT } /** Tests that the default context (used for various things including * logging) works correctly when the first context created in a * process is destroyed. */ -static libusb_testlib_result test_default_context_change(libusb_testlib_ctx * tctx) +static libusb_testlib_result test_default_context_change(void) { - libusb_context * ctx = NULL; - int r, i; + for (int i = 0; i < 100; ++i) { + libusb_context *ctx = NULL; + int r; - for (i = 0; i < 100; ++i) { /* First create a new context */ r = libusb_init(&ctx); if (r != LIBUSB_SUCCESS) { - libusb_testlib_logf(tctx, "Failed to init libusb: %d", r); + libusb_testlib_logf("Failed to init libusb: %d", r); return TEST_STATUS_FAILURE; } @@ -132,7 +137,8 @@ static libusb_testlib_result test_default_context_change(libusb_testlib_ctx * tc /* Now create a reference to the default context */ r = libusb_init(NULL); if (r != LIBUSB_SUCCESS) { - libusb_testlib_logf(tctx, "Failed to init libusb: %d", r); + libusb_testlib_logf("Failed to init libusb: %d", r); + libusb_exit(ctx); return TEST_STATUS_FAILURE; } @@ -147,14 +153,14 @@ static libusb_testlib_result test_default_context_change(libusb_testlib_ctx * tc /* Fill in the list of tests. */ static const libusb_testlib_test tests[] = { - {"init_and_exit", &test_init_and_exit}, - {"get_device_list", &test_get_device_list}, - {"many_device_lists", &test_many_device_lists}, - {"default_context_change", &test_default_context_change}, + { "init_and_exit", &test_init_and_exit }, + { "get_device_list", &test_get_device_list }, + { "many_device_lists", &test_many_device_lists }, + { "default_context_change", &test_default_context_change }, LIBUSB_NULL_TEST }; -int main (int argc, char ** argv) +int main(int argc, char *argv[]) { return libusb_testlib_run_tests(argc, argv, tests); } diff --git a/tests/testlib.c b/tests/testlib.c index 95c9c0a..3825341 100644 --- a/tests/testlib.c +++ b/tests/testlib.c @@ -17,37 +17,26 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libusb_testlib.h" +#include <config.h> -#include <stdio.h> +#include <errno.h> #include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> #include <string.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#if defined(_WIN32) -#include <io.h> -#define dup _dup -#define dup2 _dup2 -#define open _open -#define close _close -#define fdopen _fdopen -#define NULL_PATH "nul" -#define STDOUT_FILENO 1 -#define STDERR_FILENO 2 -#else -#include <unistd.h> +#include "libusb_testlib.h" + +#if defined(PLATFORM_POSIX) #define NULL_PATH "/dev/null" +#elif defined(PLATFORM_WINDOWS) +#define NULL_PATH "nul" #endif -#define INVALID_FD -1 -#define IGNORE_RETVAL(expr) do { (void)(expr); } while(0) /** * Converts a test result code into a human readable string. */ -static const char* test_result_to_str(libusb_testlib_result result) +static const char *test_result_to_str(libusb_testlib_result result) { switch (result) { case TEST_STATUS_SUCCESS: @@ -63,96 +52,27 @@ static const char* test_result_to_str(libusb_testlib_result result) } } -static void print_usage(int argc, char ** argv) +static void print_usage(const char *progname) { - printf("Usage: %s [-l] [-v] [<test_name> ...]\n", - argc > 0 ? argv[0] : "test_*"); + printf("Usage: %s [-l] [-v] [<test_name> ...]\n", progname); printf(" -l List available tests\n"); - printf(" -v Don't redirect STDERR/STDOUT during tests\n"); -} - -static void cleanup_test_output(libusb_testlib_ctx * ctx) -{ - if (!ctx->verbose) { - if (ctx->old_stdout != INVALID_FD) { - IGNORE_RETVAL(dup2(ctx->old_stdout, STDOUT_FILENO)); - ctx->old_stdout = INVALID_FD; - } - if (ctx->old_stderr != INVALID_FD) { - IGNORE_RETVAL(dup2(ctx->old_stderr, STDERR_FILENO)); - ctx->old_stderr = INVALID_FD; - } - if (ctx->null_fd != INVALID_FD) { - close(ctx->null_fd); - ctx->null_fd = INVALID_FD; - } - if (ctx->output_file != stdout) { - fclose(ctx->output_file); - ctx->output_file = stdout; - } - } -} - -/** - * Setup test output handles - * \return zero on success, non-zero on failure - */ -static int setup_test_output(libusb_testlib_ctx * ctx) -{ - /* Stop output to stdout and stderr from being displayed if using non-verbose output */ - if (!ctx->verbose) { - /* Keep a copy of STDOUT and STDERR */ - ctx->old_stdout = dup(STDOUT_FILENO); - if (ctx->old_stdout < 0) { - ctx->old_stdout = INVALID_FD; - printf("Failed to duplicate stdout handle: %d\n", errno); - return 1; - } - ctx->old_stderr = dup(STDERR_FILENO); - if (ctx->old_stderr < 0) { - ctx->old_stderr = INVALID_FD; - cleanup_test_output(ctx); - printf("Failed to duplicate stderr handle: %d\n", errno); - return 1; - } - /* Redirect STDOUT_FILENO and STDERR_FILENO to /dev/null or "nul"*/ - ctx->null_fd = open(NULL_PATH, O_WRONLY); - if (ctx->null_fd < 0) { - ctx->null_fd = INVALID_FD; - cleanup_test_output(ctx); - printf("Failed to open null handle: %d\n", errno); - return 1; - } - if ((dup2(ctx->null_fd, STDOUT_FILENO) < 0) || - (dup2(ctx->null_fd, STDERR_FILENO) < 0)) { - cleanup_test_output(ctx); - return 1; - } - ctx->output_file = fdopen(ctx->old_stdout, "w"); - if (!ctx->output_file) { - ctx->output_file = stdout; - cleanup_test_output(ctx); - printf("Failed to open FILE for output handle: %d\n", errno); - return 1; - } - } - return 0; + printf(" -v Don't redirect STDERR before running tests\n"); + printf(" -h Display this help and exit\n"); } -void libusb_testlib_logf(libusb_testlib_ctx * ctx, - const char* fmt, ...) +void libusb_testlib_logf(const char *fmt, ...) { va_list va; + va_start(va, fmt); - vfprintf(ctx->output_file, fmt, va); + vfprintf(stdout, fmt, va); va_end(va); - fprintf(ctx->output_file, "\n"); - fflush(ctx->output_file); + fputc('\n', stdout); + fflush(stdout); } -int libusb_testlib_run_tests(int argc, - char ** argv, - const libusb_testlib_test * tests) +int libusb_testlib_run_tests(int argc, char *argv[], + const libusb_testlib_test *tests) { int run_count = 0; int idx = 0; @@ -160,108 +80,105 @@ int libusb_testlib_run_tests(int argc, int fail_count = 0; int error_count = 0; int skip_count = 0; - int r, j; - size_t arglen; - libusb_testlib_result test_result; - libusb_testlib_ctx ctx; /* Setup default mode of operation */ - ctx.test_names = NULL; - ctx.test_count = 0; - ctx.list_tests = false; - ctx.verbose = false; - ctx.old_stdout = INVALID_FD; - ctx.old_stderr = INVALID_FD; - ctx.output_file = stdout; - ctx.null_fd = INVALID_FD; + char **test_names = NULL; + int test_count = 0; + bool list_tests = false; + bool verbose = false; /* Parse command line options */ if (argc >= 2) { - for (j = 1; j < argc; j++) { - arglen = strlen(argv[j]); - if ( ((argv[j][0] == '-') || (argv[j][0] == '/')) && - arglen >=2 ) { - switch (argv[j][1]) { + for (int j = 1; j < argc; j++) { + const char *argstr = argv[j]; + size_t arglen = strlen(argstr); + + if (argstr[0] == '-' || argstr[0] == '/') { + if (arglen == 2) { + switch (argstr[1]) { case 'l': - ctx.list_tests = true; - break; + list_tests = true; + continue; case 'v': - ctx.verbose = true; - break; - default: - printf("Unknown option: '%s'\n", argv[j]); - print_usage(argc, argv); - return 1; + verbose = true; + continue; + case 'h': + print_usage(argv[0]); + return 0; } + } + + fprintf(stderr, "Unknown option: '%s'\n", argstr); + print_usage(argv[0]); + return 1; } else { /* End of command line options, remaining must be list of tests to run */ - ctx.test_names = argv + j; - ctx.test_count = argc - j; + test_names = argv + j; + test_count = argc - j; break; } } } /* Validate command line options */ - if (ctx.test_names && ctx.list_tests) { - printf("List of tests requested but test list provided\n"); - print_usage(argc, argv); + if (test_names && list_tests) { + fprintf(stderr, "List of tests requested but test list provided\n"); + print_usage(argv[0]); return 1; } /* Setup test log output */ - r = setup_test_output(&ctx); - if (r != 0) - return r; + if (!verbose) { + if (!freopen(NULL_PATH, "w", stderr)) { + printf("Failed to open null handle: %d\n", errno); + return 1; + } + } /* Act on any options not related to running tests */ - if (ctx.list_tests) { - while (tests[idx].function != NULL) { - libusb_testlib_logf(&ctx, tests[idx].name); - ++idx; - } - cleanup_test_output(&ctx); + if (list_tests) { + while (tests[idx].function) + libusb_testlib_logf("%s", tests[idx++].name); return 0; } /* Run any requested tests */ - while (tests[idx].function != NULL) { - const libusb_testlib_test * test = &tests[idx]; - ++idx; - if (ctx.test_count > 0) { + while (tests[idx].function) { + const libusb_testlib_test *test = &tests[idx++]; + libusb_testlib_result test_result; + + if (test_count > 0) { /* Filtering tests to run, check if this is one of them */ int i; - for (i = 0; i < ctx.test_count; ++i) { - if (strcmp(ctx.test_names[i], test->name) == 0) + + for (i = 0; i < test_count; i++) { + if (!strcmp(test_names[i], test->name)) /* Matches a requested test name */ break; } - if (i >= ctx.test_count) { + if (i == test_count) { /* Failed to find a test match, so do the next loop iteration */ continue; } } - libusb_testlib_logf(&ctx, - "Starting test run: %s...", test->name); - test_result = test->function(&ctx); - libusb_testlib_logf(&ctx, - "%s (%d)", - test_result_to_str(test_result), test_result); + libusb_testlib_logf("Starting test run: %s...", test->name); + test_result = test->function(); + libusb_testlib_logf("%s (%d)", test_result_to_str(test_result), test_result); switch (test_result) { case TEST_STATUS_SUCCESS: pass_count++; break; case TEST_STATUS_FAILURE: fail_count++; break; case TEST_STATUS_ERROR: error_count++; break; case TEST_STATUS_SKIP: skip_count++; break; } - ++run_count; + run_count++; } - libusb_testlib_logf(&ctx, "---"); - libusb_testlib_logf(&ctx, "Ran %d tests", run_count); - libusb_testlib_logf(&ctx, "Passed %d tests", pass_count); - libusb_testlib_logf(&ctx, "Failed %d tests", fail_count); - libusb_testlib_logf(&ctx, "Error in %d tests", error_count); - libusb_testlib_logf(&ctx, "Skipped %d tests", skip_count); - cleanup_test_output(&ctx); + libusb_testlib_logf("---"); + libusb_testlib_logf("Ran %d tests", run_count); + libusb_testlib_logf("Passed %d tests", pass_count); + libusb_testlib_logf("Failed %d tests", fail_count); + libusb_testlib_logf("Error in %d tests", error_count); + libusb_testlib_logf("Skipped %d tests", skip_count); + return pass_count != run_count; } |