aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--.private/wbs.txt5
-rw-r--r--.travis.yml12
-rw-r--r--AUTHORS56
-rw-r--r--ChangeLog28
-rw-r--r--INSTALL_WIN.txt9
-rw-r--r--[l---------]README33
l---------[-rw-r--r--]README.md33
-rw-r--r--Xcode/config.h145
-rw-r--r--Xcode/libusb.xcodeproj/project.pbxproj240
-rw-r--r--android/config.h9
-rw-r--r--android/jni/examples.mk11
-rw-r--r--android/jni/libusb.mk5
-rw-r--r--android/jni/tests.mk1
-rwxr-xr-xautogen.sh2
-rwxr-xr-xbootstrap.sh6
-rw-r--r--configure.ac127
-rw-r--r--doc/Makefile.in2
-rw-r--r--doc/doxygen.cfg.in2
-rw-r--r--examples/Makefile.am14
-rw-r--r--examples/dpfp.c324
-rw-r--r--examples/dpfp_threaded.c557
-rw-r--r--examples/ezusb.c6
-rw-r--r--examples/ezusb.h9
-rw-r--r--examples/fxload.c5
-rw-r--r--examples/hotplugtest.c2
-rw-r--r--examples/sam3u_benchmark.c65
-rw-r--r--[-rwxr-xr-x]examples/testlibusb.c92
-rw-r--r--libusb/Makefile.am23
-rw-r--r--libusb/core.c250
-rw-r--r--libusb/descriptor.c443
-rw-r--r--libusb/hotplug.c29
-rw-r--r--libusb/hotplug.h6
-rw-r--r--libusb/io.c780
-rw-r--r--libusb/libusb-1.0.def2
-rw-r--r--libusb/libusb-1.0.rc2
-rw-r--r--libusb/libusb.h33
-rw-r--r--libusb/libusbi.h347
-rw-r--r--libusb/os/darwin_iousbhost.m268
-rw-r--r--libusb/os/darwin_usb.c68
-rw-r--r--libusb/os/darwin_usb.h15
-rw-r--r--libusb/os/events_posix.c300
-rw-r--r--libusb/os/events_posix.h59
-rw-r--r--libusb/os/events_windows.c214
-rw-r--r--libusb/os/events_windows.h46
-rw-r--r--libusb/os/haiku_pollfs.cpp4
-rw-r--r--libusb/os/linux_netlink.c68
-rw-r--r--libusb/os/linux_udev.c77
-rw-r--r--libusb/os/linux_usbfs.c97
-rw-r--r--libusb/os/linux_usbfs.h10
-rw-r--r--libusb/os/openbsd_usb.c7
-rw-r--r--libusb/os/poll_posix.c81
-rw-r--r--libusb/os/poll_posix.h20
-rw-r--r--libusb/os/poll_windows.c556
-rw-r--r--libusb/os/poll_windows.h60
-rw-r--r--libusb/os/sunos_usb.c7
-rw-r--r--libusb/os/threads_posix.c54
-rw-r--r--libusb/os/threads_posix.h37
-rw-r--r--libusb/os/threads_windows.c4
-rw-r--r--libusb/os/threads_windows.h24
-rw-r--r--libusb/os/windows_common.c428
-rw-r--r--libusb/os/windows_common.h37
-rw-r--r--libusb/os/windows_usbdk.c49
-rw-r--r--libusb/os/windows_winusb.c369
-rw-r--r--libusb/os/windows_winusb.h49
-rw-r--r--libusb/sync.c16
-rw-r--r--libusb/version.h2
-rw-r--r--libusb/version_nano.h2
-rw-r--r--msvc/config.h9
-rw-r--r--msvc/dpfp_2013.vcxproj87
-rw-r--r--msvc/dpfp_2013.vcxproj.filters26
-rw-r--r--msvc/dpfp_2015.vcxproj87
-rw-r--r--msvc/dpfp_2015.vcxproj.filters26
-rw-r--r--msvc/dpfp_2017.vcxproj106
-rw-r--r--msvc/dpfp_2017.vcxproj.filters26
-rw-r--r--msvc/dpfp_2019.vcxproj106
-rw-r--r--msvc/dpfp_2019.vcxproj.filters26
-rw-r--r--msvc/dpfp_threaded_2013.vcxproj87
-rw-r--r--msvc/dpfp_threaded_2013.vcxproj.filters26
-rw-r--r--msvc/dpfp_threaded_2015.vcxproj87
-rw-r--r--msvc/dpfp_threaded_2015.vcxproj.filters26
-rw-r--r--msvc/dpfp_threaded_2017.vcxproj106
-rw-r--r--msvc/dpfp_threaded_2017.vcxproj.filters26
-rw-r--r--msvc/dpfp_threaded_2019.vcxproj106
-rw-r--r--msvc/dpfp_threaded_2019.vcxproj.filters26
-rw-r--r--msvc/fxload_2013.vcxproj3
-rw-r--r--msvc/fxload_2013.vcxproj.filters9
-rw-r--r--msvc/fxload_2015.vcxproj3
-rw-r--r--msvc/fxload_2015.vcxproj.filters9
-rw-r--r--msvc/fxload_2017.vcxproj3
-rw-r--r--msvc/fxload_2017.vcxproj.filters9
-rw-r--r--msvc/fxload_2019.vcxproj3
-rw-r--r--msvc/fxload_2019.vcxproj.filters9
-rw-r--r--msvc/hotplugtest_2013.vcxproj5
-rw-r--r--msvc/hotplugtest_2013.vcxproj.filters9
-rw-r--r--msvc/hotplugtest_2015.vcxproj5
-rw-r--r--msvc/hotplugtest_2015.vcxproj.filters9
-rw-r--r--msvc/hotplugtest_2017.vcxproj5
-rw-r--r--msvc/hotplugtest_2017.vcxproj.filters9
-rw-r--r--msvc/hotplugtest_2019.vcxproj5
-rw-r--r--msvc/hotplugtest_2019.vcxproj.filters9
-rw-r--r--msvc/libusb_2013.sln30
-rw-r--r--msvc/libusb_2015.sln30
-rw-r--r--msvc/libusb_2017.sln54
-rw-r--r--msvc/libusb_2019.sln54
-rw-r--r--msvc/libusb_dll_2013.vcxproj4
-rw-r--r--msvc/libusb_dll_2013.vcxproj.filters12
-rw-r--r--msvc/libusb_dll_2015.vcxproj4
-rw-r--r--msvc/libusb_dll_2015.vcxproj.filters12
-rw-r--r--msvc/libusb_dll_2017.vcxproj4
-rw-r--r--msvc/libusb_dll_2017.vcxproj.filters12
-rw-r--r--msvc/libusb_dll_2019.vcxproj4
-rw-r--r--msvc/libusb_dll_2019.vcxproj.filters12
-rw-r--r--msvc/libusb_static_2013.vcxproj4
-rw-r--r--msvc/libusb_static_2013.vcxproj.filters12
-rw-r--r--msvc/libusb_static_2015.vcxproj4
-rw-r--r--msvc/libusb_static_2015.vcxproj.filters12
-rw-r--r--msvc/libusb_static_2017.vcxproj4
-rw-r--r--msvc/libusb_static_2017.vcxproj.filters12
-rw-r--r--msvc/libusb_static_2019.vcxproj4
-rw-r--r--msvc/libusb_static_2019.vcxproj.filters12
-rw-r--r--msvc/listdevs_2013.vcxproj5
-rw-r--r--msvc/listdevs_2013.vcxproj.filters9
-rw-r--r--msvc/listdevs_2015.vcxproj5
-rw-r--r--msvc/listdevs_2015.vcxproj.filters9
-rw-r--r--msvc/listdevs_2017.vcxproj5
-rw-r--r--msvc/listdevs_2017.vcxproj.filters9
-rw-r--r--msvc/listdevs_2019.vcxproj5
-rw-r--r--msvc/listdevs_2019.vcxproj.filters9
-rw-r--r--msvc/sam3u_benchmark_2013.vcxproj87
-rw-r--r--msvc/sam3u_benchmark_2013.vcxproj.filters26
-rw-r--r--msvc/sam3u_benchmark_2015.vcxproj87
-rw-r--r--msvc/sam3u_benchmark_2015.vcxproj.filters26
-rw-r--r--msvc/sam3u_benchmark_2017.vcxproj106
-rw-r--r--msvc/sam3u_benchmark_2017.vcxproj.filters26
-rw-r--r--msvc/sam3u_benchmark_2019.vcxproj106
-rw-r--r--msvc/sam3u_benchmark_2019.vcxproj.filters26
-rw-r--r--msvc/stress_2013.vcxproj2
-rw-r--r--msvc/stress_2013.vcxproj.filters6
-rw-r--r--msvc/stress_2015.vcxproj2
-rw-r--r--msvc/stress_2015.vcxproj.filters6
-rw-r--r--msvc/stress_2017.vcxproj2
-rw-r--r--msvc/stress_2017.vcxproj.filters6
-rw-r--r--msvc/stress_2019.vcxproj2
-rw-r--r--msvc/stress_2019.vcxproj.filters6
-rw-r--r--msvc/testlibusb_2013.vcxproj5
-rw-r--r--msvc/testlibusb_2013.vcxproj.filters9
-rw-r--r--msvc/testlibusb_2015.vcxproj5
-rw-r--r--msvc/testlibusb_2015.vcxproj.filters9
-rw-r--r--msvc/testlibusb_2017.vcxproj5
-rw-r--r--msvc/testlibusb_2017.vcxproj.filters9
-rw-r--r--msvc/testlibusb_2019.vcxproj5
-rw-r--r--msvc/testlibusb_2019.vcxproj.filters9
-rw-r--r--msvc/xusb_2013.vcxproj5
-rw-r--r--msvc/xusb_2013.vcxproj.filters9
-rw-r--r--msvc/xusb_2015.vcxproj5
-rw-r--r--msvc/xusb_2015.vcxproj.filters9
-rw-r--r--msvc/xusb_2017.vcxproj5
-rw-r--r--msvc/xusb_2017.vcxproj.filters9
-rw-r--r--msvc/xusb_2019.vcxproj5
-rw-r--r--msvc/xusb_2019.vcxproj.filters9
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/libusb_testlib.h55
-rw-r--r--tests/stress.c102
-rw-r--r--tests/testlib.c239
165 files changed, 5830 insertions, 3393 deletions
diff --git a/.gitignore b/.gitignore
index 1dc2e35..0418511 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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:
diff --git a/AUTHORS b/AUTHORS
index e90ad9b..a366189 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -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
diff --git a/ChangeLog b/ChangeLog
index 0999d07..df47bd5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/README b/README
index 42061c0..a47b4bd 120000..100644
--- a/README
+++ b/README
@@ -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
diff --git a/autogen.sh b/autogen.sh
index 24f39ee..62d68e5 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -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, &timestamp_origin);
- }
+ if (!timestamp_origin.tv_sec)
+ usbi_get_monotonic_time(&timestamp_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(&timestamp);
+ TIMESPEC_SUB(&timestamp, &timestamp_origin, &timestamp);
+
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;
}