early-access version 1701

This commit is contained in:
pineappleEA 2021-05-21 07:39:33 +02:00
parent f11e1d29de
commit 9256601d27
199 changed files with 15535 additions and 7268 deletions

View file

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 1700. This is the source code for early-access 1701.
## Legal Notice ## Legal Notice

View file

@ -48,7 +48,7 @@ if(WIN32 OR CYGWIN)
libusb/libusb/os/threads_windows.c libusb/libusb/os/threads_windows.c
libusb/libusb/os/windows_winusb.c libusb/libusb/os/windows_winusb.c
libusb/libusb/os/windows_usbdk.c libusb/libusb/os/windows_usbdk.c
libusb/libusb/os/windows_nt_common.c libusb/libusb/os/windows_common.c
) )
set(OS_WINDOWS TRUE) set(OS_WINDOWS TRUE)
elseif(APPLE) elseif(APPLE)
@ -105,7 +105,7 @@ endif()
if(UNIX) if(UNIX)
target_sources(usb PRIVATE target_sources(usb PRIVATE
libusb/libusb/os/poll_posix.c libusb/libusb/os/events_posix.c
libusb/libusb/os/threads_posix.c libusb/libusb/os/threads_posix.c
) )
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
@ -118,7 +118,7 @@ if(UNIX)
set(THREADS_POSIX TRUE) set(THREADS_POSIX TRUE)
elseif(WIN32) elseif(WIN32)
target_sources(usb PRIVATE target_sources(usb PRIVATE
libusb/libusb/os/poll_windows.c libusb/libusb/os/events_windows.c
libusb/libusb/os/threads_windows.c libusb/libusb/os/threads_windows.c
) )
endif() endif()

View file

@ -1,11 +1,7 @@
*.sh eol=lf
*.ac eol=lf *.ac eol=lf
*.am eol=lf *.am eol=lf
*.dsw eol=crlf *.bat eol=crlf
*.dsp eol=crlf whitespace=space-before-tab *.sh eol=lf
*.sln eol=crlf
*.vcproj eol=crlf
*.vcxproj* eol=crlf
.gitattributes export-ignore .gitattributes export-ignore
.gitignore export-ignore .gitignore export-ignore
INSTALL_WIN.txt eol=crlf INSTALL_WIN.txt eol=crlf

View file

@ -2,6 +2,7 @@
.libs .libs
Makefile Makefile
Makefile.in Makefile.in
!doc/Makefile.in
*.la *.la
*.lo *.lo
*.o *.o
@ -37,14 +38,17 @@ examples/hotplugtest
examples/sam3u_benchmark examples/sam3u_benchmark
examples/testlibusb examples/testlibusb
tests/stress tests/stress
android/libs
android/obj
*.exe *.exe
*.pc *.pc
doc/html doc/api-1.0
*.plg *.plg
*.ncb *.ncb
*.opt *.opt
Debug Debug
Release Release
*.db
*.user *.user
*.suo *.suo
*.sdf *.sdf
@ -54,7 +58,11 @@ Release
*.orig *.orig
.dirstamp .dirstamp
.amend .amend
.DS_Store
Xcode/build
xcshareddata
xcuserdata xcuserdata
*.xcuserdatad *.xcuserdatad
*.xccheckout *.xccheckout
*.xcscmblueprint *.xcscmblueprint
*.xcworkspace

View file

@ -0,0 +1,22 @@
#!/bin/bash
set -eu
buildsys="${1}-${Platform}"
if [ "${buildsys}" == "MinGW-Win32" ]; then
export PATH="/c/mingw-w64/i686-6.3.0-posix-dwarf-rt_v5-rev1/mingw32/bin:${PATH}"
elif [ "${buildsys}" == "MinGW-x64" ]; then
export PATH="/c/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/bin:${PATH}"
fi
builddir="build-${buildsys}"
installdir="${PWD}/libusb-${buildsys}"
cd libusb
echo "Bootstrapping ..."
./bootstrap.sh
echo ""
exec .private/ci-build.sh --build-dir "${builddir}" --install -- "--prefix=${installdir}"

67
externals/libusb/libusb/.private/ci-build.sh vendored Executable file
View file

@ -0,0 +1,67 @@
#!/bin/bash
set -e
builddir=
install=no
while [ $# -gt 0 ]; do
case "$1" in
--build-dir)
if [ $# -lt 2 ]; then
echo "ERROR: missing argument for --build-dir option" >&2
exit 1
fi
builddir=$2
shift 2
;;
--install)
install=yes
shift
;;
--)
shift
break;
;;
*)
echo "ERROR: Unexpected argument: $1" >&2
exit 1
esac
done
if [ -z "${builddir}" ]; then
echo "ERROR: --build-dir option not specified" >&2
exit 1
fi
if [ -e "${builddir}" ]; then
echo "ERROR: directory entry named '${builddir}' already exists" >&2
exit 1
fi
mkdir "${builddir}"
cd "${builddir}"
cflags="-O2"
# enable extra warnings
cflags+=" -Winline"
cflags+=" -Wmissing-include-dirs"
cflags+=" -Wnested-externs"
cflags+=" -Wpointer-arith"
cflags+=" -Wredundant-decls"
cflags+=" -Wswitch-enum"
echo ""
echo "Configuring ..."
CFLAGS="${cflags}" ../configure --enable-examples-build --enable-tests-build "$@"
echo ""
echo "Building ..."
make -j4 -k
if [ "${install}" = "yes" ]; then
echo ""
echo "Installing ..."
make install
fi

View file

@ -14,6 +14,10 @@
# derivative branch, such as one you would create for private development. # derivative branch, such as one you would create for private development.
# #
if [ -n "$LIBUSB_SKIP_NANO" ]; then
exit 0
fi
case "$1" in case "$1" in
amend) amend)
# Check if a .amend exists. If none, create one and warn user to re-commit. # Check if a .amend exists. If none, create one and warn user to re-commit.

View file

@ -26,6 +26,10 @@
BRANCH_OFFSET=10000 BRANCH_OFFSET=10000
################################################################################ ################################################################################
if [ -n "$LIBUSB_SKIP_NANO" ]; then
exit 0
fi
if [ "$BASH_VERSION" = '' ]; then if [ "$BASH_VERSION" = '' ]; then
TYPE_CMD="type git >/dev/null 2>&1" TYPE_CMD="type git >/dev/null 2>&1"
else else

View file

@ -2,7 +2,7 @@
********************************************************************* *********************************************************************
* The latest version of this snapshot can always be downloaded at: * * 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: o Visual Studio:
@ -24,24 +24,6 @@ o Visual Studio:
remember that you need to have a copy of the DLL either in the runtime remember that you need to have a copy of the DLL either in the runtime
directory or in system32 directory or in system32
o WDK/DDK:
- The following is an example of a sources files that you can use to compile
a libusb 1.0 based console application. In this sample ..\libusb\ is the
directory where you would have copied libusb.h as well as the relevant
libusb-1.0.lib
TARGETNAME=your_app
TARGETTYPE=PROGRAM
USE_MSVCRT=1
UMTYPE=console
INCLUDES=..\libusb;$(DDK_INC_PATH)
TARGETLIBS=..\libusb\libusb-1.0.lib
SOURCES=your_app.c
- Note that if you plan to use libCMT instead of MSVCRT (USE_LIBCMT=1 instead
of USE_MSVCRT=1), you will need to recompile libusb to use libCMT. This can
easily be achieved, in the DDK environment, by running 'ddk_build /MT'
o MinGW/cygwin o MinGW/cygwin
- Copy libusb.h, from include/libusb-1.0/ to your default include directory, - Copy libusb.h, from include/libusb-1.0/ to your default include directory,
and copy the MinGW32/ or MinGW64/ .a files to your default library directory. and copy the MinGW32/ or MinGW64/ .a files to your default library directory.
@ -55,6 +37,9 @@ o Additional information:
- For some libusb samples (including source), please have a look in examples/ - For some libusb samples (including source), please have a look in examples/
- For additional information on the libusb 1.0 Windows backend please visit: - For additional information on the libusb 1.0 Windows backend please visit:
http://windows.libusb.info 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 - 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. 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 - If you find any issue, please visit http://libusb.info/ and check the

View file

@ -1,49 +1,59 @@
language: c language: c
git:
depth: 1
matrix: matrix:
include: include:
- os: linux - os: linux
dist: trusty dist: focal
sudo: required compiler: clang
- os: linux
dist: focal
compiler: gcc compiler: gcc
- os: linux - os: linux
dist: trusty dist: bionic
sudo: required
compiler: clang compiler: clang
- os: osx - os: linux
osx_image: xcode8 dist: bionic
compiler: gcc
- os: linux
dist: xenial
compiler: clang
- os: linux
dist: xenial
compiler: gcc compiler: gcc
- os: osx - os: osx
osx_image: xcode8 osx_image: xcode12.2
compiler: clang compiler: clang
- os: osx - os: osx
osx_image: xcode7.1 osx_image: xcode11.3
compiler: gcc
- os: osx
osx_image: xcode7.1
compiler: clang compiler: clang
- os: osx - os: osx
osx_image: beta-xcode6.2 osx_image: xcode9.4
compiler: gcc
- os: osx
osx_image: beta-xcode6.2
compiler: clang compiler: clang
addons: addons:
homebrew:
update: true
brewfile: true
apt: apt:
packages: packages:
- autoconf - autoconf
- automake - automake
- libtool - libtool
- m4
- libudev-dev - libudev-dev
sources: - m4
- ubuntu-toolchain-r-test homebrew:
packages:
- autoconf
- automake
- libtool
- m4
update: true
before_script:
- ./bootstrap.sh
script: script:
- ./autogen.sh && make clean && make - if [ "$TRAVIS_OS_NAME" = "linux" ]; then .private/ci-build.sh --build-dir build-netlink -- --disable-udev; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./travis-autogen.sh --disable-udev && make clean && make ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then .private/ci-build.sh --build-dir build-udev -- --enable-udev; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then cd Xcode && xcodebuild -project libusb.xcodeproj ; fi - if [ "$TRAVIS_OS_NAME" = "osx" ]; then .private/ci-build.sh --build-dir build; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then cd Xcode && xcodebuild -project libusb.xcodeproj; fi

View file

@ -11,11 +11,18 @@ Copyright © 2012-2013 Toby Gray <toby.gray@realvnc.com>
Copyright © 2013-2018 Chris Dickens <christopher.a.dickens@gmail.com> Copyright © 2013-2018 Chris Dickens <christopher.a.dickens@gmail.com>
Other contributors: Other contributors:
Aaron Luft
Adrian Bunk Adrian Bunk
Adrien Destugues
Akshay Jaggi Akshay Jaggi
Alan Ott Alan Ott
Alan Stern Alan Stern
Aleksandr Mezin
Alexander Pyhalov
Alexander Schlarb
Alexander Stein
Alex Vatchenko Alex Vatchenko
Andrew Aldridge
Andrew Fernandes Andrew Fernandes
Andy Chunyu Andy Chunyu
Andy McFadden Andy McFadden
@ -25,18 +32,25 @@ Anthony Clay
Antonio Ospite Antonio Ospite
Artem Egorkine Artem Egorkine
Aurelien Jarno Aurelien Jarno
Axel Gembe
Aymeric Vincent
Baruch Siach
Bastien Nocera Bastien Nocera
Bei Zhang Bei Zhang
Bence Csokas
Benjamin Dobell Benjamin Dobell
Brent Rector Brent Rector
Carl Karsten Carl Karsten
Chris Zhu
Christophe Zeitouny Christophe Zeitouny
Chunyu Xie
Colin Walters Colin Walters
Dave Camarillo Dave Camarillo
David Engraf David Engraf
David Moore
Davidlohr Bueso Davidlohr Bueso
David Moore
Dmitry Fleytman Dmitry Fleytman
Dmitry Kostjuchenko
Doug Johnston Doug Johnston
Evan Hunter Evan Hunter
Federico Manzan Federico Manzan
@ -44,60 +58,85 @@ Felipe Balbi
Florian Albrechtskirchinger Florian Albrechtskirchinger
Francesco Montorsi Francesco Montorsi
Francisco Facioni Francisco Facioni
Frank Li
Frederik Carlier
Gaurav Gupta Gaurav Gupta
Graeme Gill Graeme Gill
Greg Kroah-Hartman
Gustavo Zacarias Gustavo Zacarias
Hans Ulrich Niedermann Hans Ulrich Niedermann
Harry Mallon
Hector Martin Hector Martin
Hoi-Ho Chan Hoi-Ho Chan
Ido Yariv
Igor Anokhin
Ihor Dutchak
Ilya Konstantinov Ilya Konstantinov
Jakub Klama Jakub Klama
James Hanko James Hanko
Jeffrey Nichols Jeffrey Nichols
Jie Zhang
Johann Richard Johann Richard
John Keeping
John Sheu John Sheu
Jonas Malaco
Jonathon Jongsma Jonathon Jongsma
Joost Muller Joost Muller
Josh Gao Josh Gao
Joshua Blake Joshua Blake
Joshua Hou
Juan Cruz Viotti
Justin Bischoff Justin Bischoff
KIMURA Masaru
Karsten Koenig Karsten Koenig
Kenjiro Tsuji
KIMURA Masaru
Konrad Rzepecki Konrad Rzepecki
Kuangye Guo Kuangye Guo
Lars Kanis Lars Kanis
Lars Wirzenius Lars Wirzenius
Lei Chen Lei Chen
Léo Lam
Luca Longinotti Luca Longinotti
Marcus Meissner Marcus Meissner
Markus Heidelberg Markus Heidelberg
Martin Ettl Martin Ettl
Martin Koegler Martin Koegler
Martin Thierer
Matthew Stapleton Matthew Stapleton
Matthias Bolte Matthias Bolte
Michel Zou Michel Zou
Mike Frysinger Mike Frysinger
Mikhail Gusarov Mikhail Gusarov
Mikolaj Kucharski
Morgan Leborgne Morgan Leborgne
Moritz Fischer Moritz Fischer
Ларионов Даниил Nia Alarie
Nicholas Corgan Nicholas Corgan
Omri Iluz Omri Iluz
Orin Eman Orin Eman
Patrick Stewart
Paul Fertser Paul Fertser
Paul Qureshi
Pekka Nikander Pekka Nikander
Philémon Favrod
Pino Toscano
Rob Walker Rob Walker
Romain Vimont Romain Vimont
Roman Kalashnikov Roman Kalashnikov
Saleem Rashid
Sameeh Jubran Sameeh Jubran
Sean McBride Sean McBride
Sebastian Pipping Sebastian Pipping
Sebastian von Ohr
Sergey Serb Sergey Serb
Simon Haggett Simon Haggett
Simon Newton Simon Newton
Slash Gordon
Stefan Agner Stefan Agner
Stefan Tauner Stefan Tauner
Steinar H. Gunderson Steinar H. Gunderson
Stephen Groat
Theo Buehler
Thomas Röfer Thomas Röfer
Tim Hutt Tim Hutt
Tim Roberts Tim Roberts
@ -106,14 +145,25 @@ Toby Peterson
Tormod Volden Tormod Volden
Trygve Laugstøl Trygve Laugstøl
Uri Lublin Uri Lublin
Uwe Bonnes
Vasily Khoruzhick Vasily Khoruzhick
Vegard Storheil Eriksen Vegard Storheil Eriksen
Venkatesh Shukla Venkatesh Shukla
Vianney le Clément de Saint-Marcq Vianney le Clément de Saint-Marcq
Victor Toso Victor Toso
Vinicius Tinti
Vitali Lovich Vitali Lovich
Vladimir Beloborodov
William Orr
William Skellenger William Skellenger
Xiaofan Chen Xiaofan Chen
Zhiqiang Liu
Zoltán Kovács Zoltán Kovács
Сергей Валерьевич
Ларионов Даниил
Роман Донченко Роман Донченко
liangyunwang
parafin parafin
RipleyTom
saur0n
winterrace

View file

@ -1,6 +1,30 @@
For detailed information about the changes below, please see the git log or For detailed information about the changes below, please see the git log or
visit: http://log.libusb.info 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 2019-08-28: v1.0.23
* Add German translation (#446) * Add German translation (#446)
* Add Hungarian translation (#493) * Add Hungarian translation (#493)
@ -22,7 +46,7 @@ visit: http://log.libusb.info
* Windows: Add support for isochronous transfers with WinUSB * Windows: Add support for isochronous transfers with WinUSB
* Various other bug fixes and improvements * Various other bug fixes and improvements
2018-03-24: v1.0.22: 2018-03-24: v1.0.22
* New libusb_set_option() API * New libusb_set_option() API
* Fix transfer timeout not being cleared upon resubmission * Fix transfer timeout not being cleared upon resubmission
* Report super speed plus devices on modern Linux and macOS * 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) * Windows: Support cancelation of individual transfers (Vista and later)
* Various other bug fixes and improvements * 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 * Core: Refactor code related to transfer flags and timeout handling
* Darwin: Ignore root hub simulation devices * Darwin: Ignore root hub simulation devices
* Darwin: Improved support for OS X El Capitan * Darwin: Improved support for OS X El Capitan

View file

@ -1,73 +1,51 @@
Installation Instructions for Windows 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: If you are using Microsoft Visual Studio:
- Open the relevant solution file in /msvc: - Open the relevant solution file in /msvc:
libusb.dsw for MSVC6, libusb_2005.sln for Visual Studio 2005 or 2008, libusb_2013.sln for Visual Studio 2013,
libusb_2010.sln for Visual Studio 2010, libusb_2015.sln for Visual Studio 2015,
libusb_2012.sln for Visual Studio 2012 or later, libusb_2017.sln for Visual Studio 2017,
libusb_wince.sln for Windows CE support in Visual Studio 2005. libusb_2019.sln for Visual Studio 2019 or later.
- If you want to debug the library, uncomment the ENABLE_DEBUG_LOGGING define - If you want to debug the library, uncomment the ENABLE_DEBUG_LOGGING define
in msvc\config.h in msvc\config.h
- Select your configuration and compile the project - Select your configuration and compile the project
Note that if you are using Visual Studio Express, you may have to install the Installing and building libusb via vcpkg
Windows SDK to be able to compile the 64 bit version of the library. ****************************************
If you are using the freely available Windows DDK/WDK (Driver Development Kit) You can download and install libusb using the vcpkg dependency manager:
- If you want to debug the library, uncomment the ENABLE_DEBUG_LOGGING define
in msvc\config.h
- Open one of the relevant Free Build or Checked Build prompt for your target
platform
- Navigate to the msvc\ directory where the ddk_build.cmd file is located, and
run 'ddk_build'
- To produce a DLL rather than a static library, use: 'ddk_build DLL'
- To produce a static library that uses LIBCMT[d] instead of MSVCRT[d] (/MT[d]
vs /MD[d] in Visual Studio) use: 'ddk_build /MT'
Note that using the Windows DDK, it is possible to compile both the 32 and 64 git clone https://github.com/Microsoft/vcpkg.git
bit versions of the library. cd vcpkg
./bootstrap-vcpkg.bat
./vcpkg integrate install
vcpkg install libusb
If you are building for Windows CE then you will need the Windows CE Standard 5.00 SDK. The libusb port in vcpkg is kept up to date by Microsoft team members and
community contributors. If the version is out of date, please create an issue
or pull request (https://github.com/Microsoft/vcpkg) on the vcpkg repository.
Destination directories Destination directories
*********************** ***********************
The 32 bit binaries compiled either from Visual Studio or the DDK are placed in The 32-bit binaries are placed in a Win32\ directory at the root of the
a Win32\ directory at the root of the library library.
The 64 bit binaries are placed in an x64\ directory The 64-bit binaries are placed in a x64\ directory.
Windows CE binaries are placed in one of the following directories, depending
on the target processor: ARMV4I, MIPSII, MIPSII_FP, MIPSIV, MIPSIV_FP, SH4 or x86.
Troubleshooting Troubleshooting
*************** ***************
If the compilation process complains about missing libraries, ensure that the If the compilation process complains about missing libraries, ensure that the
default library paths for your project points to the relevant directories. default library paths for your project points to the relevant directories.
If needed, these libraries can be obtained by installing either the latest If needed, these libraries can be obtained by installing the latest Windows
Windows SDK or the DDK (Links provided at the end of this file). SDK.
For Windows CE it is necessary to install the CE USB Kernel Wrapper driver for
libusb to function on a device.
Links Links
***** *****
Additional information related to the Windows backend: Additional information related to the Windows backend:
http://windows.libusb.info http://windows.libusb.info
Latest Windows Driver (Development) Kit (WDK):
http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=36a2630f-5d56-43b5-b996-7633f2ec14ff
Latest Microsoft Windows SDK:
http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=c17ba869-9671-4330-a63e-1fd44e0e2505
Windows CE Standard 5.00 SDK:
http://www.microsoft.com/en-gb/download/details.aspx?id=17310
Windows CE USB Kernel Wrapper Driver:
https://github.com/RealVNC/CEUSBKWrapper

View file

@ -1,10 +1,8 @@
AUTOMAKE_OPTIONS = dist-bzip2 no-dist-gzip AUTOMAKE_OPTIONS = dist-bzip2 no-dist-gzip
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
DISTCLEANFILES = libusb-1.0.pc EXTRA_DIST = INSTALL_WIN.txt PORTING doc/libusb.png \
EXTRA_DIST = TODO PORTING msvc libusb/libusb-1.0.def libusb/version_nano.h \ android msvc Xcode
examples/getopt/getopt.c examples/getopt/getopt1.c examples/getopt/getopt.h \ SUBDIRS = libusb
android Xcode
SUBDIRS = libusb doc
if BUILD_EXAMPLES if BUILD_EXAMPLES
SUBDIRS += examples SUBDIRS += examples
@ -17,12 +15,36 @@ endif
pkgconfigdir = $(libdir)/pkgconfig pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libusb-1.0.pc pkgconfig_DATA = libusb-1.0.pc
.PHONY: dist-up # The package name is libusb-1.0, but we want the distribution
# to be created as libusb-x.y.z instead of libusb-1.0-x.y.z
distdir = libusb-$(VERSION)
# Ensure any generated docs are cleaned out
# We need this here because make does not recurse into doc/
clean-local:
rm -rf doc/$(DOXYGEN_HTMLDIR)
# Use dist-hook to accomplish the following things for the dist recipe:
# 1) Remove the GitHub Markdown from the README file
# 2) Remove the .gitattributes file from the msvc directory
dist-hook:
chmod u+w $(distdir)/README $(distdir)/msvc
$(SED) -i.orig -e '/Build Status/d' $(distdir)/README
$(SED) -i.orig -e '/^$$/N;/^\n$$/D' $(distdir)/README
$(SED) -i.orig -e 's/\[\([A-Z]*\)\](\1)/\1/' $(distdir)/README
rm -f $(distdir)/README.orig
rm -f $(distdir)/msvc/.gitattributes
reldir = .release/$(distdir) reldir = .release/$(distdir)
dist-up: dist sfurl = frs.sourceforge.net:/home/frs/project/libusb/libusb-1.0
.PHONY: dist-upload
dist-upload: dist
rm -rf $(reldir) rm -rf $(reldir)
mkdir -p $(reldir) mkdir -p $(reldir)
cp $(distdir).tar.bz2 $(reldir) cp $(distdir).tar.bz2 $(reldir)
rsync -rv $(reldir) frs.sourceforge.net:/home/frs/project/l/li/libusb/libusb-1.0/ if [ -z "$$SF_USER" ]; then \
rsync -rv $(reldir) $(sfurl); \
else \
rsync -rv $(reldir) $$SF_USER@$(sfurl); \
fi
rm -rf $(reldir) rm -rf $(reldir)

View file

@ -1,11 +1,11 @@
# libusb # libusb
[![Build Status](https://travis-ci.org/libusb/libusb.svg?branch=master)](https://travis-ci.org/libusb/libusb) [![Build Status](https://travis-ci.org/libusb/libusb.svg?branch=master)](https://travis-ci.org/libusb/libusb)
[![Build status](https://ci.appveyor.com/api/projects/status/xvrfam94jii4a6lw?svg=true)](https://ci.appveyor.com/project/LudovicRousseau/libusb) [![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) [![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, libusb is a library for USB device access from Linux, macOS,
Windows, OpenBSD/NetBSD and Haiku userspace. Windows, OpenBSD/NetBSD, Haiku and Solaris userspace.
It is written in C (Haiku backend in C++) and licensed under the GNU 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 Lesser General Public License version 2.1 or, at your option, any later
version (see [COPYING](COPYING)). version (see [COPYING](COPYING)).

View file

@ -1,11 +1,11 @@
# libusb # libusb
[![Build Status](https://travis-ci.org/libusb/libusb.svg?branch=master)](https://travis-ci.org/libusb/libusb) [![Build Status](https://travis-ci.org/libusb/libusb.svg?branch=master)](https://travis-ci.org/libusb/libusb)
[![Build status](https://ci.appveyor.com/api/projects/status/xvrfam94jii4a6lw?svg=true)](https://ci.appveyor.com/project/LudovicRousseau/libusb) [![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) [![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, libusb is a library for USB device access from Linux, macOS,
Windows, OpenBSD/NetBSD and Haiku userspace. Windows, OpenBSD/NetBSD, Haiku and Solaris userspace.
It is written in C (Haiku backend in C++) and licensed under the GNU 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 Lesser General Public License version 2.1 or, at your option, any later
version (see [COPYING](COPYING)). version (see [COPYING](COPYING)).

View file

@ -17,45 +17,49 @@
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
// libusb does not follow C99 strict aliasing rules, so disable it. // Use GNU11 dialect.
GCC_STRICT_ALIASING = NO GCC_C_LANGUAGE_STANDARD = gnu11
// Use C99 dialect.
GCC_C_LANGUAGE_STANDARD = c99
// Don't search user paths with <> style #includes. // Don't search user paths with <> style #includes.
ALWAYS_SEARCH_USER_PATHS = NO ALWAYS_SEARCH_USER_PATHS = NO
// Enable weak references for Objective-C
CLANG_ENABLE_OBJC_WEAK = YES
// Compiler errors.
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES
// Compiler warnings. // Compiler warnings.
GCC_WARN_64_TO_32_BIT_CONVERSION = YES GCC_WARN_64_TO_32_BIT_CONVERSION = YES
GCC_WARN_ABOUT_RETURN_TYPE = YES
GCC_WARN_UNINITIALIZED_AUTOS = YES
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES
GCC_WARN_SHADOW = YES
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES
GCC_WARN_ABOUT_MISSING_NEWLINE = YES GCC_WARN_ABOUT_MISSING_NEWLINE = YES
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES
GCC_WARN_ABOUT_RETURN_TYPE = YES
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
GCC_WARN_SHADOW = YES
GCC_WARN_UNINITIALIZED_AUTOS = YES
GCC_WARN_UNKNOWN_PRAGMAS = YES GCC_WARN_UNKNOWN_PRAGMAS = YES
GCC_WARN_UNUSED_FUNCTION = YES GCC_WARN_UNUSED_FUNCTION = YES
GCC_WARN_UNUSED_LABEL = YES GCC_WARN_UNUSED_LABEL = YES
GCC_WARN_UNUSED_VARIABLE = YES
GCC_WARN_UNUSED_PARAMETER = YES GCC_WARN_UNUSED_PARAMETER = YES
CLANG_WARN_EMPTY_BODY = YES GCC_WARN_UNUSED_VARIABLE = YES
CLANG_WARN_CONSTANT_CONVERSION = YES
CLANG_WARN_ENUM_CONVERSION = YES
CLANG_WARN_INT_CONVERSION = YES
CLANG_WARN_DOCUMENTATION_COMMENTS = YES
CLANG_WARN_BOOL_CONVERSION = YES
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES
CLANG_WARN_FLOAT_CONVERSION = YES
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES
CLANG_WARN_INFINITE_RECURSION = YES
CLANG_WARN_ASSIGN_ENUM = YES CLANG_WARN_ASSIGN_ENUM = YES
CLANG_WARN_STRICT_PROTOTYPES = YES CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES
CLANG_WARN_BOOL_CONVERSION = YES
CLANG_WARN_COMMA = YES CLANG_WARN_COMMA = YES
CLANG_WARN_CONSTANT_CONVERSION = YES
CLANG_WARN_DOCUMENTATION_COMMENTS = YES
CLANG_WARN_EMPTY_BODY = YES
CLANG_WARN_ENUM_CONVERSION = YES
CLANG_WARN_FLOAT_CONVERSION = YES
CLANG_WARN_INFINITE_RECURSION = YES
CLANG_WARN_INT_CONVERSION = YES
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES
CLANG_WARN_STRICT_PROTOTYPES = YES
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES
// Static analyzer warnings. // Static analyzer warnings.
CLANG_ANALYZER_NONNULL = YES
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES

View file

@ -1,25 +1,37 @@
/* config.h. Manually generated for Xcode. */ /* config.h. Manually generated for Xcode. */
/* Default visibility */ #include <AvailabilityMacros.h>
#define DEFAULT_VISIBILITY /**/
/* Message logging */ /* Define to the attribute for default visibility. */
#define DEFAULT_VISIBILITY __attribute__ ((visibility ("default")))
/* Define to 1 to enable message logging. */
#define ENABLE_LOGGING 1 #define ENABLE_LOGGING 1
/* Define to 1 if you have the <poll.h> header file. */ /* On 10.12 and later, use newly available clock_*() functions */
#define HAVE_POLL_H 1 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
/* 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 the system has the type `nfds_t'. */
#define HAVE_NFDS_T 1
/* Define to 1 if you have the <sys/time.h> header file. */ /* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1 #define HAVE_SYS_TIME_H 1
/* Darwin backend */ /* Define to 1 if compiling for a POSIX platform. */
#define OS_DARWIN 1 #define PLATFORM_POSIX 1
/* type of second poll() argument */ /* Define to the attribute for enabling parameter checks on printf-like
#define POLL_NFDS_TYPE nfds_t functions. */
#define PRINTF_FORMAT(a, b) __attribute__ ((__format__ (__printf__, a, b)))
/* Use POSIX Threads */ /* Enable GNU extensions. */
#define THREADS_POSIX 1
/* Use GNU extensions */
#define _GNU_SOURCE 1 #define _GNU_SOURCE 1

File diff suppressed because it is too large Load diff

View file

@ -17,59 +17,39 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
/* Start with debug message logging enabled */ /* Define to the attribute for default visibility. */
/* #undef ENABLE_DEBUG_LOGGING */
/* Message logging */
#define ENABLE_LOGGING
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Linux backend */
#define OS_LINUX 1
/* Enable output to system log */
#define USE_SYSTEM_LOGGING_FACILITY 1
/* type of second poll() argument */
#define POLL_NFDS_TYPE nfds_t
/* Use POSIX Threads */
#define THREADS_POSIX 1
/* Default visibility */
#define DEFAULT_VISIBILITY __attribute__ ((visibility ("default"))) #define DEFAULT_VISIBILITY __attribute__ ((visibility ("default")))
/* Define to 1 if you have the <memory.h> header file. */ /* Define to 1 to start with debug message logging enabled. */
#define HAVE_MEMORY_H 1 /* #undef ENABLE_DEBUG_LOGGING */
/* Define to 1 if you have the <poll.h> header file. */ /* Define to 1 to enable message logging. */
#define HAVE_POLL_H 1 #define ENABLE_LOGGING 1
/* 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 you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the <linux/filter.h> header file. */
#define HAVE_LINUX_FILTER_H 1
/* Define to 1 if you have the <linux/netlink.h> header file. */
#define HAVE_LINUX_NETLINK_H 1
/* Define to 1 if you have the <asm/types.h> header file. */ /* Define to 1 if you have the <asm/types.h> header file. */
#define HAVE_ASM_TYPES_H 1 #define HAVE_ASM_TYPES_H 1
/* Define to 1 if you have the <sys/socket.h> header file. */ /* Define to 1 if you have the `clock_gettime' function. */
#define HAVE_SYS_SOCKET_H 1 #define HAVE_CLOCK_GETTIME 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. */
#define HAVE_PIPE2 1
/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define to 1 if compiling for a POSIX platform. */
#define PLATFORM_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
/* Enable GNU extensions. */
#define _GNU_SOURCE 1

View file

@ -18,6 +18,22 @@
APP_ABI := all APP_ABI := all
APP_CFLAGS := \
-std=gnu11 \
-Wall \
-Wextra \
-Wshadow \
-Wunused \
-Wwrite-strings \
-Werror=format-security \
-Werror=implicit-function-declaration \
-Werror=implicit-int \
-Werror=init-self \
-Werror=missing-prototypes \
-Werror=strict-prototypes \
-Werror=undef \
-Werror=uninitialized
# Workaround for MIPS toolchain linker being unable to find liblog dependency # Workaround for MIPS toolchain linker being unable to find liblog dependency
# of shared object in NDK versions at least up to r9. # of shared object in NDK versions at least up to r9.
# #

View file

@ -20,87 +20,6 @@ LOCAL_PATH:= $(call my-dir)
LIBUSB_ROOT_REL := ../.. LIBUSB_ROOT_REL := ../..
LIBUSB_ROOT_ABS := $(LOCAL_PATH)/../.. LIBUSB_ROOT_ABS := $(LOCAL_PATH)/../..
# listdevs
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/listdevs.c
LOCAL_C_INCLUDES += \
$(LIBUSB_ROOT_ABS)
LOCAL_SHARED_LIBRARIES += libusb1.0
LOCAL_MODULE:= listdevs
include $(BUILD_EXECUTABLE)
# xusb
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/xusb.c
LOCAL_C_INCLUDES += \
$(LIBUSB_ROOT_ABS)
LOCAL_SHARED_LIBRARIES += libusb1.0
LOCAL_MODULE:= xusb
include $(BUILD_EXECUTABLE)
# hotplugtest
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/hotplugtest.c
LOCAL_C_INCLUDES += \
$(LIBUSB_ROOT_ABS)
LOCAL_SHARED_LIBRARIES += libusb1.0
LOCAL_MODULE:= hotplugtest
include $(BUILD_EXECUTABLE)
# fxload
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/fxload.c \
$(LIBUSB_ROOT_REL)/examples/ezusb.c
LOCAL_C_INCLUDES += \
$(LIBUSB_ROOT_ABS)
LOCAL_SHARED_LIBRARIES += libusb1.0
LOCAL_MODULE:= fxload
include $(BUILD_EXECUTABLE)
# sam3u_benchmake
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/sam3u_benchmark.c
LOCAL_C_INCLUDES += \
$(LIBUSB_ROOT_ABS)
LOCAL_SHARED_LIBRARIES += libusb1.0
LOCAL_MODULE:= sam3u_benchmark
include $(BUILD_EXECUTABLE)
# dpfp # dpfp
include $(CLEAR_VARS) include $(CLEAR_VARS)
@ -109,6 +28,7 @@ LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/dpfp.c $(LIBUSB_ROOT_REL)/examples/dpfp.c
LOCAL_C_INCLUDES += \ LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/.. \
$(LIBUSB_ROOT_ABS) $(LIBUSB_ROOT_ABS)
LOCAL_SHARED_LIBRARIES += libusb1.0 LOCAL_SHARED_LIBRARIES += libusb1.0
@ -122,13 +42,102 @@ include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_SRC_FILES := \ LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/dpfp_threaded.c $(LIBUSB_ROOT_REL)/examples/dpfp.c
LOCAL_C_INCLUDES += \ LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/.. \
$(LIBUSB_ROOT_ABS) $(LIBUSB_ROOT_ABS)
LOCAL_CFLAGS := -DDPFP_THREADED -pthread
LOCAL_SHARED_LIBRARIES += libusb1.0 LOCAL_SHARED_LIBRARIES += libusb1.0
LOCAL_MODULE := dpfp_threaded LOCAL_MODULE := dpfp_threaded
include $(BUILD_EXECUTABLE) include $(BUILD_EXECUTABLE)
# fxload
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/ezusb.c \
$(LIBUSB_ROOT_REL)/examples/fxload.c
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/.. \
$(LIBUSB_ROOT_ABS)
LOCAL_SHARED_LIBRARIES += libusb1.0
LOCAL_MODULE := fxload
include $(BUILD_EXECUTABLE)
# hotplugtest
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/hotplugtest.c
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/.. \
$(LIBUSB_ROOT_ABS)
LOCAL_SHARED_LIBRARIES += libusb1.0
LOCAL_MODULE := hotplugtest
include $(BUILD_EXECUTABLE)
# listdevs
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/listdevs.c
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/.. \
$(LIBUSB_ROOT_ABS)
LOCAL_SHARED_LIBRARIES += libusb1.0
LOCAL_MODULE := listdevs
include $(BUILD_EXECUTABLE)
# sam3u_benchmark
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/sam3u_benchmark.c
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/.. \
$(LIBUSB_ROOT_ABS)
LOCAL_SHARED_LIBRARIES += libusb1.0
LOCAL_MODULE := sam3u_benchmark
include $(BUILD_EXECUTABLE)
# xusb
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/examples/xusb.c
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/.. \
$(LIBUSB_ROOT_ABS)
LOCAL_SHARED_LIBRARIES += libusb1.0
LOCAL_MODULE := xusb
include $(BUILD_EXECUTABLE)

View file

@ -24,9 +24,6 @@ LIBUSB_ROOT_ABS:= $(LOCAL_PATH)/../..
include $(CLEAR_VARS) include $(CLEAR_VARS)
LIBUSB_ROOT_REL:= ../..
LIBUSB_ROOT_ABS:= $(LOCAL_PATH)/../..
LOCAL_SRC_FILES := \ LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/libusb/core.c \ $(LIBUSB_ROOT_REL)/libusb/core.c \
$(LIBUSB_ROOT_REL)/libusb/descriptor.c \ $(LIBUSB_ROOT_REL)/libusb/descriptor.c \
@ -35,7 +32,7 @@ LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/libusb/sync.c \ $(LIBUSB_ROOT_REL)/libusb/sync.c \
$(LIBUSB_ROOT_REL)/libusb/strerror.c \ $(LIBUSB_ROOT_REL)/libusb/strerror.c \
$(LIBUSB_ROOT_REL)/libusb/os/linux_usbfs.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/threads_posix.c \
$(LIBUSB_ROOT_REL)/libusb/os/linux_netlink.c $(LIBUSB_ROOT_REL)/libusb/os/linux_netlink.c
@ -47,6 +44,8 @@ LOCAL_C_INCLUDES += \
LOCAL_EXPORT_C_INCLUDES := \ LOCAL_EXPORT_C_INCLUDES := \
$(LIBUSB_ROOT_ABS)/libusb $(LIBUSB_ROOT_ABS)/libusb
LOCAL_CFLAGS := -fvisibility=hidden -pthread
LOCAL_LDLIBS := -llog LOCAL_LDLIBS := -llog
LOCAL_MODULE := libusb1.0 LOCAL_MODULE := libusb1.0

View file

@ -20,36 +20,19 @@ LOCAL_PATH:= $(call my-dir)
LIBUSB_ROOT_REL := ../.. LIBUSB_ROOT_REL := ../..
LIBUSB_ROOT_ABS := $(LOCAL_PATH)/../.. LIBUSB_ROOT_ABS := $(LOCAL_PATH)/../..
# testlib
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/tests/testlib.c
LOCAL_C_INCLUDES += \
$(LIBUSB_ROOT_ABS)/tests
LOCAL_EXPORT_C_INCLUDES := \
$(LIBUSB_ROOT_ABS)/tests
LOCAL_MODULE := testlib
include $(BUILD_STATIC_LIBRARY)
# stress # stress
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_SRC_FILES := \ LOCAL_SRC_FILES := \
$(LIBUSB_ROOT_REL)/tests/stress.c $(LIBUSB_ROOT_REL)/tests/stress.c \
$(LIBUSB_ROOT_REL)/tests/testlib.c
LOCAL_C_INCLUDES += \ LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/.. \
$(LIBUSB_ROOT_ABS) $(LIBUSB_ROOT_ABS)
LOCAL_SHARED_LIBRARIES += libusb1.0 LOCAL_SHARED_LIBRARIES += libusb1.0
LOCAL_STATIC_LIBRARIES += testlib
LOCAL_MODULE := stress LOCAL_MODULE := stress

View file

@ -1,41 +1,72 @@
version: 1.0.{build} version: 1.0.{build}
image:
- Visual Studio 2013
- Visual Studio 2015
- Visual Studio 2017
- Visual Studio 2019
platform:
- Win32
- x64
configuration: configuration:
- Debug - Debug
- Release - Release
platform: clone_depth: 1
- x64 build:
- Win32 parallel: true
for:
-
matrix:
only:
- image: Visual Studio 2013
build: build:
project: msvc\libusb_2013.sln project: msvc\libusb_2013.sln
parallel: true
verbosity: detailed -
environment:
matrix: matrix:
- libusb_2015: msvc\libusb_2015.sln only:
libusb_2013: msvc\libusb_2013.sln - image: Visual Studio 2015
libusb_2012: msvc\libusb_2012.sln configuration: Debug
libusb_2010: msvc\libusb_2010.sln build:
project: msvc\libusb_2015.sln
-
matrix:
only:
- image: Visual Studio 2015
platform: Win32
configuration: Release
install: install:
- cmd: xcopy /S /I "%APPVEYOR_BUILD_FOLDER%" C:\msys64\home\appveyor\libusb
- cmd: >- - cmd: xcopy /S /I "%APPVEYOR_BUILD_FOLDER%" C:\cygwin\home\appveyor\libusb
rem Copying libusb to cygwin home directory
xcopy /S C:\projects\libusb C:\cygwin\home\appveyor\
rem Copying libusb to MinGW home directory
xcopy /S C:\projects\libusb C:\msys64\home\appveyor\
build_script: build_script:
- cmd: >- - cmd: msbuild "%APPVEYOR_BUILD_FOLDER%\msvc\libusb_2015.sln" /m /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
msbuild %libusb_2015% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" - cmd: C:\msys64\usr\bin\bash -l "%APPVEYOR_BUILD_FOLDER%\.private\appveyor_build.sh" MinGW
- cmd: C:\cygwin\bin\bash -l "%APPVEYOR_BUILD_FOLDER%\.private\appveyor_build.sh" cygwin
msbuild %libusb_2013% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" -
matrix:
only:
- image: Visual Studio 2015
platform: x64
configuration: Release
install:
- cmd: xcopy /S /I "%APPVEYOR_BUILD_FOLDER%" C:\msys64\home\appveyor\libusb
- cmd: xcopy /S /I "%APPVEYOR_BUILD_FOLDER%" C:\cygwin64\home\appveyor\libusb
build_script:
- cmd: msbuild "%APPVEYOR_BUILD_FOLDER%\msvc\libusb_2015.sln" /m /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
- cmd: C:\msys64\usr\bin\bash -l "%APPVEYOR_BUILD_FOLDER%\.private\appveyor_build.sh" MinGW
- cmd: C:\cygwin64\bin\bash -l "%APPVEYOR_BUILD_FOLDER%\.private\appveyor_build.sh" cygwin
msbuild %libusb_2012% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" -
matrix:
only:
- image: Visual Studio 2017
build:
project: msvc\libusb_2017.sln
msvc/appveyor.bat -
matrix:
appveyor_minGW.bat only:
- image: Visual Studio 2019
appveyor_cygwin.bat build:
project: msvc\libusb_2019.sln

View file

@ -3,6 +3,6 @@
set -e set -e
./bootstrap.sh ./bootstrap.sh
if test -z "$NOCONFIGURE"; then if [ -z "$NOCONFIGURE" ]; then
exec ./configure --enable-examples-build --enable-tests-build "$@" exec ./configure --enable-examples-build --enable-tests-build "$@"
fi fi

View file

@ -1,6 +1,8 @@
#!/bin/sh #!/bin/sh
if ! test -d m4 ; then set -e
if [ ! -d m4 ]; then
mkdir m4 mkdir m4
fi fi
autoreconf -ivf || exit 1 exec autoreconf -ivf

View file

@ -15,312 +15,365 @@ LU_DEFINE_VERSION_ATOM([LIBUSB_MINOR])
LU_DEFINE_VERSION_ATOM([LIBUSB_MICRO]) LU_DEFINE_VERSION_ATOM([LIBUSB_MICRO])
LU_DEFINE_VERSION_RC_ATOM([LIBUSB_RC]) LU_DEFINE_VERSION_RC_ATOM([LIBUSB_RC])
AC_INIT([libusb],[LIBUSB_MAJOR[.]LIBUSB_MINOR[.]LIBUSB_MICRO[]LIBUSB_RC],[libusb-devel@lists.sourceforge.net],[libusb],[http://libusb.info]) AC_PREREQ([2.69])
AC_INIT([libusb-1.0], [LIBUSB_MAJOR[.]LIBUSB_MINOR[.]LIBUSB_MICRO[]LIBUSB_RC], [libusb-devel@lists.sourceforge.net], [libusb-1.0], [http://libusb.info])
# Library versioning AC_CONFIG_HEADERS([config.h])
# These numbers should be tweaked on every release. Read carefully:
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
# http://sourceware.org/autobook/autobook/autobook_91.html
lt_current=2
lt_revision=0
lt_age=2
LTLDFLAGS="-version-info ${lt_current}:${lt_revision}:${lt_age}"
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([libusb/core.c]) AC_CONFIG_SRCDIR([libusb/core.c])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
AC_PREREQ([2.69])
AC_PROG_CC AC_PROG_CC
AC_PROG_CXX AC_PROG_CXX
AC_C_INLINE
AM_INIT_AUTOMAKE
LT_INIT LT_INIT
LT_LANG([Windows Resource]) LT_LANG([Windows Resource])
AC_C_INLINE
AM_PROG_CC_C_O
AC_DEFINE([_GNU_SOURCE], 1, [Use GNU extensions])
LTLDFLAGS="${LTLDFLAGS} -no-undefined" 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=3
lt_revision=0
lt_age=3
LT_LDFLAGS="-version-info ${lt_current}:${lt_revision}:${lt_age} -no-undefined"
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
EXTRA_CPPFLAGS=
EXTRA_CFLAGS=
dnl check for -std=gnu11 compiler support (optional)
dnl note that we don't just check if the compiler accepts '-std=x11'
dnl but also that it supports the _Thread_local keyword because some compilers
dnl (e.g. gcc 4.8) accept the command line option but do not implement TLS
saved_CFLAGS="${CFLAGS}"
CFLAGS="-std=gnu11"
AC_MSG_CHECKING([if $CC supports -std=gnu11])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([_Thread_local int x;], [x = 42;])],
[AC_MSG_RESULT([yes])
c_dialect=gnu],
[AC_MSG_RESULT([no])
c_dialect=])
if test "x$c_dialect" != xgnu; then
dnl fallback check for -std=c11 compiler support (required)
CFLAGS="-std=c11"
AC_MSG_CHECKING([if $CC supports -std=c11])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([_Thread_local int x;], [x = 42;])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
AC_MSG_ERROR([compiler with C11 support is required to build libusb])])
c_dialect=c
fi
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=
AC_MSG_CHECKING([operating system]) AC_MSG_CHECKING([operating system])
dnl on linux-android platform, some functions are in different places
case $host in case $host in
*-linux-android*)
AC_MSG_RESULT([This is a Linux-Android system])
is_backend_android=yes
;;
*)
is_backend_android=no
esac
case $host in
*-linux* | *-uclinux*)
AC_MSG_RESULT([Linux])
backend=linux
threads=posix
;;
*-darwin*) *-darwin*)
AC_MSG_RESULT([Darwin/Mac OS X]) AC_MSG_RESULT([Darwin/Mac OS X])
backend=darwin backend=darwin
threads=posix platform=posix
;;
*-openbsd*)
AC_MSG_RESULT([OpenBSD])
backend=openbsd
threads=posix
;;
*-netbsd*)
AC_MSG_RESULT([NetBSD])
backend=netbsd
threads=posix
;;
*-mingw* | *msys*)
AC_MSG_RESULT([Windows])
backend=windows
threads=windows
create_import_lib=yes
AM_CFLAGS="${AM_CFLAGS} -fno-omit-frame-pointer"
;;
*-cygwin*)
AC_MSG_RESULT([Cygwin (using Windows backend)])
backend=windows
threads=posix
;; ;;
*-haiku*) *-haiku*)
AC_MSG_RESULT([Haiku]) AC_MSG_RESULT([Haiku])
backend=haiku backend=haiku
threads=posix platform=posix
;;
*-linux* | *-uclinux*)
dnl on Android Linux, some functions are in different places
case $host in
*-linux-android*)
AC_MSG_RESULT([Android Linux])
is_android_linux=yes
;;
*)
AC_MSG_RESULT([Linux])
;;
esac
backend=linux
platform=posix
;;
*-netbsd*)
AC_MSG_RESULT([NetBSD])
backend=netbsd
platform=posix
;;
*-openbsd*)
AC_MSG_RESULT([OpenBSD])
backend=openbsd
platform=posix
;; ;;
*-solaris*) *-solaris*)
AC_MSG_RESULT([SunOS]) AC_MSG_RESULT([SunOS])
backend=sunos backend=sunos
threads=posix platform=posix
;;
*-cygwin*)
AC_MSG_RESULT([Windows (using Cygwin)])
backend=windows
platform=windows
EXTRA_CFLAGS="-mwin32"
;;
*-mingw* | *msys*)
AC_MSG_RESULT([Windows])
backend=windows
platform=windows
test "x$enable_shared" = xyes && create_import_lib=yes
EXTRA_CFLAGS="-mwin32 -fno-omit-frame-pointer"
;; ;;
*) *)
AC_MSG_ERROR([unsupported operating system $host]) 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
platform=posix
;;
esac esac
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])
dnl Some compilers do not support the '-pthread' option so check for it here
saved_CFLAGS="${CFLAGS}"
CFLAGS="-Wall -Werror -pthread"
AC_MSG_CHECKING([if $CC recognizes -pthread])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [])],
[AC_MSG_RESULT([yes])
AC_SUBST(THREAD_CFLAGS, [-pthread])],
[AC_MSG_RESULT([no])])
CFLAGS="${saved_CFLAGS}"
dnl Android Linux and Darwin provide pthread functions directly in libc
dnl glibc also provides some pthread functions directly, so search for a thread-specific function
AC_SEARCH_LIBS([pthread_create], [pthread],
[test "x$ac_cv_search_pthread_create" != "xnone required" && AC_SUBST(THREAD_LIBS, [-lpthread])],
[], [])
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 platform])
fi
case $backend in case $backend in
linux)
AC_DEFINE(OS_LINUX, 1, [Linux backend])
AC_SUBST(OS_LINUX)
AC_SEARCH_LIBS([clock_gettime], [rt], [], [], [-pthread])
AC_ARG_ENABLE([udev],
[AC_HELP_STRING([--enable-udev], [use udev for device enumeration and hotplug support (recommended) [default=yes]])],
[], [enable_udev=yes])
if test "x$enable_udev" = xyes ; then
# system has udev. use it or fail!
AC_CHECK_HEADERS([libudev.h], [], [AC_MSG_ERROR([udev support requested but libudev header not installed])])
AC_CHECK_LIB([udev], [udev_new], [], [AC_MSG_ERROR([udev support requested but libudev not installed])])
AC_DEFINE(USE_UDEV, 1, [Use udev for device enumeration/hotplug])
else
AC_CHECK_HEADERS([asm/types.h], [], [])
AC_CHECK_HEADERS([sys/socket.h linux/netlink.h], [], [AC_MSG_ERROR([Linux netlink headers not found])], [
#ifdef HAVE_ASM_TYPES_H
#include <asm/types.h>
#endif
#include <sys/socket.h>
])
fi
AC_SUBST(USE_UDEV)
if test "x$is_backend_android" != xyes; then
THREAD_CFLAGS="-pthread"
LIBS="${LIBS} -pthread"
fi
AC_CHECK_HEADERS([poll.h])
AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])
;;
darwin) darwin)
AC_DEFINE(OS_DARWIN, 1, [Darwin backend]) AC_CHECK_FUNCS([pthread_threadid_np])
AC_SUBST(OS_DARWIN) LIBS="${LIBS} -lobjc -Wl,-framework,IOKit -Wl,-framework,CoreFoundation"
LIBS="-lobjc -Wl,-framework,IOKit -Wl,-framework,CoreFoundation"
LTLDFLAGS="${LTLDFLAGS} -Wl,-prebind"
AC_CHECK_HEADERS([poll.h])
AC_CHECK_TYPE([nfds_t],
[AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])],
[AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[type of second poll() argument])],
[#include <poll.h>])
;;
openbsd)
AC_DEFINE(OS_OPENBSD, 1, [OpenBSD backend])
AC_SUBST(OS_OPENBSD)
THREAD_CFLAGS="-pthread"
LIBS="-pthread"
AC_CHECK_HEADERS([poll.h])
AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])
;;
sunos)
AC_DEFINE(OS_SUNOS, 1, [SunOS backend])
AC_SUBST(OS_SUNOS)
THREAD_CFLAGS="-pthread"
LIBS="-pthread -ldevinfo"
AC_CHECK_HEADERS([poll.h])
AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])
;;
netbsd)
AC_DEFINE(OS_NETBSD, 1, [NetBSD backend])
AC_SUBST(OS_NETBSD)
THREAD_CFLAGS="-pthread"
LIBS="-pthread"
AC_CHECK_HEADERS([poll.h])
AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])
;;
windows)
AC_DEFINE(OS_WINDOWS, 1, [Windows backend])
AC_SUBST(OS_WINDOWS)
LIBS=""
LTLDFLAGS="${LTLDFLAGS} -avoid-version -Wl,--add-stdcall-alias"
AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[type of second poll() argument])
AC_DEFINE([WINVER], 0x0501, [Oldest Windows version supported])
AC_DEFINE([_WIN32_WINNT], 0x0501, [Oldest Windows version supported])
;; ;;
haiku) haiku)
AC_DEFINE(OS_HAIKU, 1, [Haiku backend])
AC_SUBST(OS_HAIKU)
LIBS="${LIBS} -lbe" LIBS="${LIBS} -lbe"
AC_CHECK_HEADERS([poll.h]) ;;
AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument]) linux)
AC_SEARCH_LIBS([clock_gettime], [rt], [], [], [])
AC_CHECK_FUNCS([pthread_setname_np])
AC_ARG_ENABLE([udev],
[AC_HELP_STRING([--enable-udev], [use udev for device enumeration and hotplug support (recommended) [default=yes]])],
[use_udev=$enableval], [use_udev=yes])
if test "x$use_udev" = xyes; then
dnl system has udev. use it or fail!
AC_CHECK_HEADER([libudev.h], [], [AC_MSG_ERROR([udev support requested but libudev header not installed])])
AC_CHECK_LIB([udev], [udev_new], [], [AC_MSG_ERROR([udev support requested but libudev not installed])])
else
AC_CHECK_HEADERS([asm/types.h])
AC_CHECK_HEADER([linux/netlink.h], [], [AC_MSG_ERROR([Linux netlink header not found])])
AC_CHECK_HEADER([sys/socket.h], [], [AC_MSG_ERROR([Linux socket header not found])])
fi
;;
sunos)
LIBS="${LIBS} -ldevinfo"
;;
windows)
AC_CHECK_TYPES([struct timespec], [], [], [[#include <time.h>]])
AC_DEFINE([_WIN32_WINNT], [_WIN32_WINNT_VISTA], [Define to the oldest supported Windows version.])
LT_LDFLAGS="${LT_LDFLAGS} -avoid-version -Wl,--add-stdcall-alias"
;;
*)
dnl no special handling required
;; ;;
esac esac
AC_SUBST(LIBS) dnl headers not available on all platforms but required on others
AC_CHECK_HEADERS([sys/time.h])
AM_CONDITIONAL(OS_LINUX, test "x$backend" = xlinux) if test "x$platform" = xposix; then
AM_CONDITIONAL(OS_DARWIN, test "x$backend" = xdarwin) dnl the clock_gettime() function needs certain clock IDs defined
AM_CONDITIONAL(OS_OPENBSD, test "x$backend" = xopenbsd) AC_CHECK_FUNCS([clock_gettime], [have_clock_gettime=yes], [have_clock_gettime=])
AM_CONDITIONAL(OS_SUNOS, test "x$backend" = xsunos) if test "x$have_clock_gettime" = xyes; then
AM_CONDITIONAL(OS_NETBSD, test "x$backend" = xnetbsd) AC_CHECK_DECL([CLOCK_MONOTONIC], [], [AC_MSG_ERROR([C library headers missing definition for CLOCK_MONOTONIC])], [[#include <time.h>]])
AM_CONDITIONAL(OS_WINDOWS, test "x$backend" = xwindows) dnl use the monotonic clock for condition variable timed waits if possible
AM_CONDITIONAL(OS_HAIKU, test "x$backend" = xhaiku) AC_CHECK_FUNCS([pthread_condattr_setclock], [need_clock_realtime=], [need_clock_realtime=yes])
AM_CONDITIONAL(THREADS_POSIX, test "x$threads" = xposix) if test "x$need_clock_realtime" = xyes; then
AM_CONDITIONAL(CREATE_IMPORT_LIB, test "x$create_import_lib" = xyes) AC_CHECK_DECL([CLOCK_REALTIME], [], [AC_MSG_ERROR([C library headers missing definition for CLOCK_REALTIME])], [[#include <time.h>]])
AM_CONDITIONAL(USE_UDEV, test "x$enable_udev" = xyes) fi
if test "x$threads" = xposix; then elif test "x$backend" != xdarwin; then
AC_DEFINE(THREADS_POSIX, 1, [Use POSIX Threads]) AC_MSG_ERROR([clock_gettime() is required on this platform])
fi
fi fi
# timerfd dnl eventfd support
AC_CHECK_HEADER([sys/timerfd.h], [timerfd_h=1], [timerfd_h=0]) 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
if test "x$backend" = xlinux || test "x$backend" = xsunos; then
AC_ARG_ENABLE([timerfd], AC_ARG_ENABLE([timerfd],
[AS_HELP_STRING([--enable-timerfd], [AS_HELP_STRING([--enable-timerfd], [use timerfd for timing [default=auto]])],
[use timerfd for timing [default=auto]])], [use_timerfd=$enableval],
[use_timerfd=$enableval], [use_timerfd=auto]) [use_timerfd=auto])
if test "x$use_timerfd" != xno; then
if test "x$use_timerfd" = xyes -a "x$timerfd_h" = x0; then AC_CHECK_HEADER([sys/timerfd.h], [timerfd_h=yes], [timerfd_h=])
AC_MSG_ERROR([timerfd header not available; glibc 2.9+ required]) if test "x$timerfd_h" = xyes; then
AC_CHECK_DECLS([TFD_NONBLOCK, TFD_CLOEXEC], [timerfd_h_ok=yes], [timerfd_h_ok=], [[#include <sys/timerfd.h>]])
if test "x$timerfd_h_ok" = xyes; then
AC_CHECK_FUNC([timerfd_create], [timerfd_ok=yes], [timerfd_ok=])
if test "x$timerfd_ok" = xyes; then
AC_DEFINE([HAVE_TIMERFD], [1], [Define to 1 if the system has timerfd functionality.])
elif test "x$use_timerfd" = xyes; then
AC_MSG_ERROR([timerfd_create() function not found; glibc 2.9+ required])
fi fi
elif test "x$use_timerfd" = xyes; then
AC_CHECK_DECLS([TFD_NONBLOCK, TFD_CLOEXEC], [tfd_hdr_ok=yes], [tfd_hdr_ok=no], [#include <sys/timerfd.h>])
if test "x$use_timerfd" = xyes -a "x$tfd_hdr_ok" = xno; then
AC_MSG_ERROR([timerfd header not usable; glibc 2.9+ required]) AC_MSG_ERROR([timerfd header not usable; glibc 2.9+ required])
fi fi
elif test "x$use_timerfd" = xyes; then
AC_MSG_ERROR([timerfd header not available; glibc 2.9+ required])
fi
fi
AC_MSG_CHECKING([whether to use timerfd for timing]) AC_MSG_CHECKING([whether to use timerfd for timing])
if test "x$use_timerfd" = xno; then if test "x$use_timerfd" = xno; then
AC_MSG_RESULT([no (disabled by user)]) AC_MSG_RESULT([no (disabled by user)])
else elif test "x$timerfd_h" != xyes; then
if test "x$timerfd_h" = x1 -a "x$tfd_hdr_ok" = xyes; then
AC_MSG_RESULT([yes])
AC_DEFINE(USBI_TIMERFD_AVAILABLE, 1, [timerfd headers available])
else
AC_MSG_RESULT([no (header not available)]) AC_MSG_RESULT([no (header not available)])
elif test "x$timerfd_h_ok" != xyes; then
AC_MSG_RESULT([no (header not usable)])
elif test "x$timerfd_ok" != xyes; then
AC_MSG_RESULT([no (functions not available)])
else
AC_MSG_RESULT([yes])
fi fi
fi fi
AC_CHECK_FUNCS([pipe2]) dnl Message logging
AC_CHECK_TYPES([struct timespec]) AC_ARG_ENABLE([log],
[AS_HELP_STRING([--disable-log], [disable all logging])],
# Message logging
AC_ARG_ENABLE([log], [AS_HELP_STRING([--disable-log], [disable all logging])],
[log_enabled=$enableval], [log_enabled=$enableval],
[log_enabled=yes]) [log_enabled=yes])
if test "x$log_enabled" != xno; then if test "x$log_enabled" != xno; then
AC_DEFINE([ENABLE_LOGGING], 1, [Message logging]) AC_DEFINE([ENABLE_LOGGING], [1], [Define to 1 to enable message logging.])
fi fi
AC_ARG_ENABLE([debug-log], [AS_HELP_STRING([--enable-debug-log], AC_ARG_ENABLE([debug-log],
[start with debug message logging enabled [default=no]])], [AS_HELP_STRING([--enable-debug-log], [start with debug message logging enabled [default=no]])],
[debug_log_enabled=$enableval], [debug_log_enabled=$enableval],
[debug_log_enabled=no]) [debug_log_enabled=no])
if test "x$debug_log_enabled" != xno; then if test "x$debug_log_enabled" != xno; then
AC_DEFINE([ENABLE_DEBUG_LOGGING], 1, [Start with debug message logging enabled]) AC_DEFINE([ENABLE_DEBUG_LOGGING], [1], [Define to 1 to start with debug message logging enabled.])
fi fi
AC_ARG_ENABLE([system-log], [AS_HELP_STRING([--enable-system-log], AC_ARG_ENABLE([system-log],
[output logging messages to system wide log, if supported by the OS [default=no]])], [AS_HELP_STRING([--enable-system-log], [output logging messages to the systemwide log, if supported by the OS [default=no]])],
[system_log_enabled=$enableval], [system_log_enabled=$enableval],
[system_log_enabled=no]) [system_log_enabled=no])
if test "x$system_log_enabled" != xno; then if test "x$system_log_enabled" != xno; then
AC_DEFINE([USE_SYSTEM_LOGGING_FACILITY], 1, [Enable output to system log]) AC_DEFINE([USE_SYSTEM_LOGGING_FACILITY], [1], [Define to 1 to output logging messages to the systemwide log.])
if test "x$backend" != xwindows && test "x$is_android_linux" != xyes; then
# Check if syslog is available in standard C library dnl Check if syslog is available in standard C library
AC_CHECK_HEADERS(syslog.h) AC_CHECK_HEADER([syslog.h], [syslog_h=yes], [syslog_h=])
AC_CHECK_FUNC([syslog], [have_syslog=yes], [have_syslog=no]) if test "x$syslog_h" = xyes; then
if test "x$have_syslog" != xno; then AC_CHECK_FUNCS([syslog])
AC_DEFINE([HAVE_SYSLOG_FUNC], 1, [syslog() function available]) fi
fi fi
fi fi
# Examples build dnl Examples build
AC_ARG_ENABLE([examples-build], [AS_HELP_STRING([--enable-examples-build], AC_ARG_ENABLE([examples-build],
[build example applications [default=no]])], [AS_HELP_STRING([--enable-examples-build], [build example applications [default=no]])],
[build_examples=$enableval], [build_examples=$enableval],
[build_examples=no]) [build_examples=no])
AM_CONDITIONAL(BUILD_EXAMPLES, test "x$build_examples" != xno)
# Tests build dnl Tests build
AC_ARG_ENABLE([tests-build], [AS_HELP_STRING([--enable-tests-build], AC_ARG_ENABLE([tests-build],
[build test applications [default=no]])], [AS_HELP_STRING([--enable-tests-build], [build test applications [default=no]])],
[build_tests=$enableval], [build_tests=$enableval],
[build_tests=no]) [build_tests=no])
AM_CONDITIONAL(BUILD_TESTS, test "x$build_tests" != xno)
# headers not available on all platforms but required on others AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$build_examples" != xno])
AC_CHECK_HEADERS([sys/time.h]) AM_CONDITIONAL([BUILD_TESTS], [test "x$build_tests" != xno])
AM_CONDITIONAL([CREATE_IMPORT_LIB], [test "x$create_import_lib" = 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])
AM_CONDITIONAL([OS_NETBSD], [test "x$backend" = xnetbsd])
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([PLATFORM_POSIX], [test "x$platform" = xposix])
AM_CONDITIONAL([PLATFORM_WINDOWS], [test "x$platform" = xwindows])
AM_CONDITIONAL([USE_UDEV], [test "x$use_udev" = xyes])
# sigaction not available on MinGW dnl The -Wcast-function-type warning causes a flurry of warnings when compiling
AC_CHECK_FUNC([sigaction], [have_sigaction=yes], [have_sigaction=no]) dnl Windows with GCC 8 or later because of dynamically loaded functions
AM_CONDITIONAL(HAVE_SIGACTION, test "x$have_sigaction" = xyes) if test "x$backend" = xwindows; then
saved_CFLAGS="${CFLAGS}"
CFLAGS="-Werror -Wcast-function-type"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [])],
[EXTRA_CFLAGS="${EXTRA_CFLAGS} -Wno-cast-function-type"],
[])
CFLAGS="${saved_CFLAGS}"
fi
# check for -fvisibility=hidden compiler support (GCC >= 3.4) SHARED_CFLAGS="-Wall -Wextra -Wshadow -Wunused -Wwrite-strings -Werror=format-security -Werror=implicit-function-declaration -Werror=implicit-int -Werror=init-self -Werror=missing-prototypes -Werror=strict-prototypes -Werror=undef -Werror=uninitialized"
saved_cflags="$CFLAGS"
# -Werror required for cygwin
CFLAGS="$CFLAGS -Werror -fvisibility=hidden"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
[VISIBILITY_CFLAGS="-fvisibility=hidden"
AC_DEFINE([DEFAULT_VISIBILITY], [__attribute__((visibility("default")))], [Default visibility])],
[VISIBILITY_CFLAGS=""
AC_DEFINE([DEFAULT_VISIBILITY], [], [Default visibility])],
])
CFLAGS="$saved_cflags"
# check for -Wno-pointer-sign compiler support (GCC >= 4) AM_CPPFLAGS="${EXTRA_CPPFLAGS}"
saved_cflags="$CFLAGS" AC_SUBST(AM_CPPFLAGS)
CFLAGS="$CFLAGS -Wno-pointer-sign"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
nopointersign_cflags="-Wno-pointer-sign", nopointersign_cflags="")
CFLAGS="$saved_cflags"
# check for -std=gnu99 compiler support
saved_cflags="$CFLAGS"
CFLAGS="-std=gnu99"
AC_MSG_CHECKING([whether CC supports -std=gnu99])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_RESULT([yes])]
[AM_CFLAGS="${AM_CFLAGS} -std=gnu99"],
[AC_MSG_RESULT([no])]
)
CFLAGS="$saved_cflags"
AM_CFLAGS="${AM_CFLAGS} -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration $nopointersign_cflags -Wshadow ${THREAD_CFLAGS} ${VISIBILITY_CFLAGS}"
AM_CFLAGS="-std=${c_dialect}11 ${EXTRA_CFLAGS} ${SHARED_CFLAGS}"
AC_SUBST(AM_CFLAGS) AC_SUBST(AM_CFLAGS)
AC_SUBST(LTLDFLAGS)
AM_CXXFLAGS="-std=${c_dialect}++11 ${EXTRA_CFLAGS} ${SHARED_CFLAGS} -Wmissing-declarations"
AC_SUBST(AM_CXXFLAGS)
AC_SUBST(LT_LDFLAGS)
dnl set name of html output directory for doxygen
AC_SUBST(DOXYGEN_HTMLDIR, [api-1.0])
AC_CONFIG_FILES([libusb-1.0.pc]) AC_CONFIG_FILES([libusb-1.0.pc])
AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([Makefile])

22
externals/libusb/libusb/doc/Makefile.in vendored Executable file
View file

@ -0,0 +1,22 @@
LIBUSB_SRC_DIR = @top_srcdir@/libusb
EXCLUDED_FILES = hotplug.h libusbi.h version.h version_nano.h
LIBUSB_SRC = $(wildcard $(LIBUSB_SRC_DIR)/*.c) $(wildcard $(LIBUSB_SRC_DIR)/*.h)
LIBUSB_DOC_SRC = $(filter-out $(addprefix $(LIBUSB_SRC_DIR)/,$(EXCLUDED_FILES)),$(LIBUSB_SRC))
docs: @DOXYGEN_HTMLDIR@
@DOXYGEN_HTMLDIR@: doxygen.cfg @top_srcdir@/doc/libusb.png $(LIBUSB_DOC_SRC)
doxygen $<
sfurl = web.sourceforge.net:/home/project-web/libusb/htdocs
docs-upload: @DOXYGEN_HTMLDIR@
if [ -z "$$SF_USER" ]; then \
rsync -rv --delete $< $(sfurl); \
else \
rsync -rv --delete $< $$SF_USER@$(sfurl); \
fi
clean:
rm -rf @DOXYGEN_HTMLDIR@
.PHONY: clean docs docs-upload

File diff suppressed because it is too large Load diff

View file

@ -1,19 +1,12 @@
AM_CPPFLAGS = -I$(top_srcdir)/libusb AM_CPPFLAGS = -I$(top_srcdir)/libusb
LDADD = ../libusb/libusb-1.0.la LDADD = ../libusb/libusb-1.0.la
LIBS =
noinst_PROGRAMS = listdevs xusb fxload hotplugtest testlibusb noinst_PROGRAMS = dpfp dpfp_threaded fxload hotplugtest listdevs sam3u_benchmark testlibusb xusb
if HAVE_SIGACTION dpfp_threaded_CPPFLAGS = $(AM_CPPFLAGS) -DDPFP_THREADED
noinst_PROGRAMS += dpfp dpfp_threaded_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
dpfp_threaded_LDADD = $(LDADD) $(THREAD_LIBS)
if THREADS_POSIX dpfp_threaded_SOURCES = dpfp.c
dpfp_threaded_CFLAGS = $(AM_CFLAGS)
noinst_PROGRAMS += dpfp_threaded
endif
sam3u_benchmark_SOURCES = sam3u_benchmark.c
noinst_PROGRAMS += sam3u_benchmark
endif
fxload_SOURCES = ezusb.c ezusb.h fxload.c fxload_SOURCES = ezusb.c ezusb.h fxload.c
fxload_CFLAGS = $(THREAD_CFLAGS) $(AM_CFLAGS)

View file

@ -1,6 +1,8 @@
/* /*
* libusb example program to manipulate U.are.U 4000B fingerprint scanner. * libusb example program to manipulate U.are.U 4000B fingerprint scanner.
* Copyright © 2007 Daniel Drake <dsd@gentoo.org> * 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 * Basic image capture program only, does not consider the powerup quirks or
* the fact that image encryption may be enabled. Not expected to work * 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 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <config.h>
#include <errno.h> #include <errno.h>
#include <signal.h> #include <signal.h>
#include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "libusb.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_INTR (1 | LIBUSB_ENDPOINT_IN)
#define EP_DATA (2 | LIBUSB_ENDPOINT_IN) #define EP_DATA (2 | LIBUSB_ENDPOINT_IN)
#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN) #define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN)
@ -57,25 +166,65 @@ enum {
}; };
static int state = 0; 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 imgbuf[0x1b340];
static unsigned char irqbuf[INTR_LENGTH]; static unsigned char irqbuf[INTR_LENGTH];
static struct libusb_transfer *img_transfer = NULL; static struct libusb_transfer *img_transfer = NULL;
static struct libusb_transfer *irq_transfer = NULL; static struct libusb_transfer *irq_transfer = NULL;
static int img_idx = 0; 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) static int find_dpfp_device(void)
{ {
devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a); devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a);
return devh ? 0 : -EIO; return devh ? 0 : -ENODEV;
} }
static int print_f0_data(void) static int print_f0_data(void)
{ {
unsigned char data[0x10]; unsigned char data[0x10];
size_t i;
int r; int r;
unsigned int i;
r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0xf0, 0, data, r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0xf0, 0, data,
sizeof(data), 0); sizeof(data), 0);
@ -83,7 +232,7 @@ static int print_f0_data(void)
fprintf(stderr, "F0 error %d\n", r); fprintf(stderr, "F0 error %d\n", r);
return r; return r;
} }
if ((unsigned int) r < sizeof(data)) { if (r < (int)sizeof(data)) {
fprintf(stderr, "short read (%d)\n", r); fprintf(stderr, "short read (%d)\n", r);
return -1; return -1;
} }
@ -104,7 +253,7 @@ static int get_hwstat(unsigned char *status)
fprintf(stderr, "read hwstat error %d\n", r); fprintf(stderr, "read hwstat error %d\n", r);
return r; return r;
} }
if ((unsigned int) r < 1) { if (r < 1) {
fprintf(stderr, "short read (%d)\n", r); fprintf(stderr, "short read (%d)\n", r);
return -1; return -1;
} }
@ -123,8 +272,8 @@ static int set_hwstat(unsigned char data)
fprintf(stderr, "set hwstat error %d\n", r); fprintf(stderr, "set hwstat error %d\n", r);
return r; return r;
} }
if ((unsigned int) r < 1) { if (r < 1) {
fprintf(stderr, "short write (%d)", r); fprintf(stderr, "short write (%d)\n", r);
return -1; return -1;
} }
@ -134,15 +283,15 @@ static int set_hwstat(unsigned char data)
static int set_mode(unsigned char data) static int set_mode(unsigned char data)
{ {
int r; 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); r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x4e, 0, &data, 1, 0);
if (r < 0) { if (r < 0) {
fprintf(stderr, "set mode error %d\n", r); fprintf(stderr, "set mode error %d\n", r);
return r; return r;
} }
if ((unsigned int) r < 1) { if (r < 1) {
fprintf(stderr, "short write (%d)", r); fprintf(stderr, "short write (%d)\n", r);
return -1; return -1;
} }
@ -153,18 +302,18 @@ static void LIBUSB_CALL cb_mode_changed(struct libusb_transfer *transfer)
{ {
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fprintf(stderr, "mode change transfer not completed!\n"); 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", printf("async cb_mode_changed length=%d actual_length=%d\n",
transfer->length, transfer->actual_length); transfer->length, transfer->actual_length);
if (next_state() < 0) if (next_state() < 0)
do_exit = 2; request_exit(2);
} }
static int set_mode_async(unsigned char data) 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; struct libusb_transfer *transfer;
if (!buf) if (!buf)
@ -223,17 +372,17 @@ static int sync_intr(unsigned char type)
static int save_to_file(unsigned char *data) static int save_to_file(unsigned char *data)
{ {
FILE *fd; FILE *f;
char filename[64]; char filename[64];
snprintf(filename, sizeof(filename), "finger%d.pgm", img_idx++); snprintf(filename, sizeof(filename), "finger%d.pgm", img_idx++);
fd = fopen(filename, "w"); f = fopen(filename, "w");
if (!fd) if (!f)
return -1; return -1;
fputs("P5 384 289 255 ", fd); fputs("P5 384 289 255 ", f);
(void) fwrite(data + 64, 1, 384*289, fd); (void)fwrite(data + 64, 1, 384*289, f);
fclose(fd); fclose(f);
printf("saved image to %s\n", filename); printf("saved image to %s\n", filename);
return 0; return 0;
} }
@ -241,6 +390,7 @@ static int save_to_file(unsigned char *data)
static int next_state(void) static int next_state(void)
{ {
int r = 0; int r = 0;
printf("old state: %d\n", state); printf("old state: %d\n", state);
switch (state) { switch (state) {
case STATE_AWAIT_IRQ_FINGER_REMOVED: 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) { if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fprintf(stderr, "irq transfer status %d?\n", transfer->status); fprintf(stderr, "irq transfer status %d?\n", transfer->status);
do_exit = 2; goto err_free_transfer;
libusb_free_transfer(transfer);
irq_transfer = NULL;
return;
} }
printf("IRQ callback %02x\n", irqtype); printf("IRQ callback %02x\n", irqtype);
switch (state) { switch (state) {
case STATE_AWAIT_IRQ_FINGER_DETECTED: case STATE_AWAIT_IRQ_FINGER_DETECTED:
if (irqtype == 0x01) { if (irqtype == 0x01) {
if (next_state() < 0) { if (next_state() < 0)
do_exit = 2; goto err_free_transfer;
return;
}
} else { } else {
printf("finger-on-sensor detected in wrong state!\n"); printf("finger-on-sensor detected in wrong state!\n");
} }
break; break;
case STATE_AWAIT_IRQ_FINGER_REMOVED: case STATE_AWAIT_IRQ_FINGER_REMOVED:
if (irqtype == 0x02) { if (irqtype == 0x02) {
if (next_state() < 0) { if (next_state() < 0)
do_exit = 2; goto err_free_transfer;
return;
}
} else { } else {
printf("finger-on-sensor detected in wrong state!\n"); printf("finger-on-sensor detected in wrong state!\n");
} }
break; break;
} }
if (libusb_submit_transfer(irq_transfer) < 0) 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) static void LIBUSB_CALL cb_img(struct libusb_transfer *transfer)
{ {
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fprintf(stderr, "img transfer status %d?\n", transfer->status); fprintf(stderr, "img transfer status %d?\n", transfer->status);
do_exit = 2; goto err_free_transfer;
libusb_free_transfer(transfer);
img_transfer = NULL;
return;
} }
printf("Image callback\n"); printf("Image callback\n");
save_to_file(imgbuf); save_to_file(imgbuf);
if (next_state() < 0) { if (next_state() < 0)
do_exit = 2; goto err_free_transfer;
return;
}
if (libusb_submit_transfer(img_transfer) < 0) 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) static int init_capture(void)
@ -413,17 +566,33 @@ static void sighandler(int signum)
{ {
(void)signum; (void)signum;
do_exit = 1; request_exit(1);
}
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 main(void)
{ {
struct sigaction sigact;
int r; int r;
r = libusb_init(NULL); r = libusb_init(NULL);
if (r < 0) { 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); exit(1);
} }
@ -435,7 +604,7 @@ int main(void)
r = libusb_claim_interface(devh, 0); r = libusb_claim_interface(devh, 0);
if (r < 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; goto out;
} }
printf("claimed interface\n"); printf("claimed interface\n");
@ -449,45 +618,66 @@ int main(void)
goto out_deinit; goto out_deinit;
/* async from here onwards */ /* async from here onwards */
setup_signals();
r = alloc_transfers(); r = alloc_transfers();
if (r < 0) if (r < 0)
goto out_deinit; 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)
request_exit(2);
while (!do_exit)
semaphore_take(exit_semaphore);
#else
r = init_capture(); r = init_capture();
if (r < 0) if (r < 0)
goto out_deinit; goto out_deinit;
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) { while (!do_exit) {
r = libusb_handle_events(NULL); r = libusb_handle_events(NULL);
if (r < 0) if (r < 0)
goto out_deinit; request_exit(2);
} }
#endif
printf("shutting down...\n"); printf("shutting down...\n");
if (irq_transfer) { #if defined(DPFP_THREADED)
r = libusb_cancel_transfer(irq_transfer); thread_join(poll_thread);
if (r < 0) semaphore_destroy(exit_semaphore);
goto out_deinit; #endif
}
if (img_transfer) { if (img_transfer) {
r = libusb_cancel_transfer(img_transfer); r = libusb_cancel_transfer(img_transfer);
if (r < 0) 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) if (libusb_handle_events(NULL) < 0)
break; break;
}
if (do_exit == 1) if (do_exit == 1)
r = 0; r = 0;
@ -495,7 +685,9 @@ int main(void)
r = 1; r = 1;
out_deinit: out_deinit:
if (img_transfer)
libusb_free_transfer(img_transfer); libusb_free_transfer(img_transfer);
if (irq_transfer)
libusb_free_transfer(irq_transfer); libusb_free_transfer(irq_transfer);
set_mode(0); set_mode(0);
set_hwstat(0x80); set_hwstat(0x80);

View file

@ -20,6 +20,9 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
#include <config.h>
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
@ -29,9 +32,6 @@
#include "libusb.h" #include "libusb.h"
#include "ezusb.h" #include "ezusb.h"
extern void logerror(const char *format, ...)
__attribute__ ((format(printf, 1, 2)));
/* /*
* This file contains functions for uploading firmware into Cypress * This file contains functions for uploading firmware into Cypress
* EZ-USB microcontrollers. These chips use control endpoint 0 and vendor * EZ-USB microcontrollers. These chips use control endpoint 0 and vendor

View file

@ -20,23 +20,10 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
#if !defined(_MSC_VER)
#include <config.h>
#include <stdbool.h> #include <stdbool.h>
#else
#define __attribute__(x)
#if !defined(bool)
#define bool int
#endif
#if !defined(true)
#define true (1 == 1)
#endif
#if !defined(false)
#define false (!true)
#endif
#if defined(_PREFAST_)
#pragma warning(disable:28193)
#endif
#endif
#define FX_TYPE_UNDEFINED -1 #define FX_TYPE_UNDEFINED -1
#define FX_TYPE_AN21 0 /* Original AnchorChips parts */ #define FX_TYPE_AN21 0 /* Original AnchorChips parts */
@ -113,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 */ /* Verbosity level (default 1). Can be increased or decreased with options v/q */
extern int verbose; extern int verbose;
extern void logerror(const char *format, ...) PRINTF_FORMAT(1, 2);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -21,6 +21,8 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
#include <config.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -47,9 +49,6 @@ static bool dosyslog = false;
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif #endif
void logerror(const char *format, ...)
__attribute__ ((format (__printf__, 1, 2)));
void logerror(const char *format, ...) void logerror(const char *format, ...)
{ {
va_list ap; va_list ap;

View file

@ -95,7 +95,7 @@ int main(int argc, char *argv[])
} }
if (!libusb_has_capability (LIBUSB_CAP_HAS_HOTPLUG)) { 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); libusb_exit (NULL);
return EXIT_FAILURE; return EXIT_FAILURE;
} }

View file

@ -22,24 +22,54 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <unistd.h> #include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h> #include <errno.h>
#include <signal.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> #include "libusb.h"
#define EP_DATA_IN 0x82 #define EP_DATA_IN 0x82
#define EP_ISO_IN 0x86 #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 struct libusb_device_handle *devh = NULL;
static unsigned long num_bytes = 0, num_xfer = 0; static unsigned long num_bytes = 0, num_xfer = 0;
static struct timeval tv_start; 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) static void LIBUSB_CALL cb_xfr(struct libusb_transfer *xfr)
{ {
int i; int i;
@ -103,7 +133,7 @@ static int benchmark_in(uint8_t ep)
libusb_fill_bulk_transfer(xfr, devh, ep, buf, libusb_fill_bulk_transfer(xfr, devh, ep, buf,
sizeof(buf), cb_xfr, NULL, 0); sizeof(buf), cb_xfr, NULL, 0);
gettimeofday(&tv_start, NULL); get_timestamp(&tv_start);
/* NOTE: To reach maximum possible performance the program must /* NOTE: To reach maximum possible performance the program must
* submit *multiple* transfers here, not just one. * submit *multiple* transfers here, not just one.
@ -125,36 +155,39 @@ static int benchmark_in(uint8_t ep)
static void measure(void) static void measure(void)
{ {
struct timeval tv_stop; struct timeval tv_stop;
unsigned int diff_msec; unsigned long diff_msec;
gettimeofday(&tv_stop, NULL); get_timestamp(&tv_stop);
diff_msec = (tv_stop.tv_sec - tv_start.tv_sec)*1000; diff_msec = (tv_stop.tv_sec - tv_start.tv_sec) * 1000L;
diff_msec += (tv_stop.tv_usec - tv_start.tv_usec)/1000; diff_msec += (tv_stop.tv_usec - tv_start.tv_usec) / 1000L;
printf("%lu transfers (total %lu bytes) in %u 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*1000)/diff_msec); num_xfer, num_bytes, diff_msec, (num_bytes * 1000L) / diff_msec);
} }
static void sig_hdlr(int signum) static void sig_hdlr(int signum)
{ {
switch (signum) { (void)signum;
case SIGINT:
measure(); measure();
do_exit = 1; do_exit = 1;
break;
}
} }
int main(int argc, char **argv) int main(void)
{ {
int rc; int rc;
#if defined(PLATFORM_POSIX)
struct sigaction sigact; struct sigaction sigact;
sigact.sa_handler = sig_hdlr; sigact.sa_handler = sig_hdlr;
sigemptyset(&sigact.sa_mask); sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0; sigact.sa_flags = 0;
sigaction(SIGINT, &sigact, NULL); (void)sigaction(SIGINT, &sigact, NULL);
#else
(void)signal(SIGINT, sig_hdlr);
#endif
rc = libusb_init(NULL); rc = libusb_init(NULL);
if (rc < 0) { if (rc < 0) {
@ -184,7 +217,7 @@ int main(int argc, char **argv)
/* Measurement has already been done by the signal handler. */ /* Measurement has already been done by the signal handler. */
libusb_release_interface(devh, 0); libusb_release_interface(devh, 2);
out: out:
if (devh) if (devh)
libusb_close(devh); libusb_close(devh);

View file

@ -21,18 +21,14 @@
#include <string.h> #include <string.h>
#include "libusb.h" #include "libusb.h"
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define snprintf _snprintf
#endif
int verbose = 0; int verbose = 0;
static void print_endpoint_comp(const struct libusb_ss_endpoint_companion_descriptor *ep_comp) static void print_endpoint_comp(const struct libusb_ss_endpoint_companion_descriptor *ep_comp)
{ {
printf(" USB 3.0 Endpoint Companion:\n"); printf(" USB 3.0 Endpoint Companion:\n");
printf(" bMaxBurst: %d\n", ep_comp->bMaxBurst); printf(" bMaxBurst: %u\n", ep_comp->bMaxBurst);
printf(" bmAttributes: 0x%02x\n", ep_comp->bmAttributes); printf(" bmAttributes: %02xh\n", ep_comp->bmAttributes);
printf(" wBytesPerInterval: %d\n", ep_comp->wBytesPerInterval); printf(" wBytesPerInterval: %u\n", ep_comp->wBytesPerInterval);
} }
static void print_endpoint(const struct libusb_endpoint_descriptor *endpoint) static void print_endpoint(const struct libusb_endpoint_descriptor *endpoint)
@ -42,19 +38,18 @@ static void print_endpoint(const struct libusb_endpoint_descriptor *endpoint)
printf(" Endpoint:\n"); printf(" Endpoint:\n");
printf(" bEndpointAddress: %02xh\n", endpoint->bEndpointAddress); printf(" bEndpointAddress: %02xh\n", endpoint->bEndpointAddress);
printf(" bmAttributes: %02xh\n", endpoint->bmAttributes); printf(" bmAttributes: %02xh\n", endpoint->bmAttributes);
printf(" wMaxPacketSize: %d\n", endpoint->wMaxPacketSize); printf(" wMaxPacketSize: %u\n", endpoint->wMaxPacketSize);
printf(" bInterval: %d\n", endpoint->bInterval); printf(" bInterval: %u\n", endpoint->bInterval);
printf(" bRefresh: %d\n", endpoint->bRefresh); printf(" bRefresh: %u\n", endpoint->bRefresh);
printf(" bSynchAddress: %d\n", endpoint->bSynchAddress); printf(" bSynchAddress: %u\n", endpoint->bSynchAddress);
for (i = 0; i < endpoint->extra_length;) { for (i = 0; i < endpoint->extra_length;) {
if (LIBUSB_DT_SS_ENDPOINT_COMPANION == endpoint->extra[i + 1]) { if (LIBUSB_DT_SS_ENDPOINT_COMPANION == endpoint->extra[i + 1]) {
struct libusb_ss_endpoint_companion_descriptor *ep_comp; struct libusb_ss_endpoint_companion_descriptor *ep_comp;
ret = libusb_get_ss_endpoint_companion_descriptor(NULL, endpoint, &ep_comp); ret = libusb_get_ss_endpoint_companion_descriptor(NULL, endpoint, &ep_comp);
if (LIBUSB_SUCCESS != ret) { if (LIBUSB_SUCCESS != ret)
continue; continue;
}
print_endpoint_comp(ep_comp); print_endpoint_comp(ep_comp);
@ -70,13 +65,13 @@ static void print_altsetting(const struct libusb_interface_descriptor *interface
uint8_t i; uint8_t i;
printf(" Interface:\n"); printf(" Interface:\n");
printf(" bInterfaceNumber: %d\n", interface->bInterfaceNumber); printf(" bInterfaceNumber: %u\n", interface->bInterfaceNumber);
printf(" bAlternateSetting: %d\n", interface->bAlternateSetting); printf(" bAlternateSetting: %u\n", interface->bAlternateSetting);
printf(" bNumEndpoints: %d\n", interface->bNumEndpoints); printf(" bNumEndpoints: %u\n", interface->bNumEndpoints);
printf(" bInterfaceClass: %d\n", interface->bInterfaceClass); printf(" bInterfaceClass: %u\n", interface->bInterfaceClass);
printf(" bInterfaceSubClass: %d\n", interface->bInterfaceSubClass); printf(" bInterfaceSubClass: %u\n", interface->bInterfaceSubClass);
printf(" bInterfaceProtocol: %d\n", interface->bInterfaceProtocol); printf(" bInterfaceProtocol: %u\n", interface->bInterfaceProtocol);
printf(" iInterface: %d\n", interface->iInterface); printf(" iInterface: %u\n", interface->iInterface);
for (i = 0; i < interface->bNumEndpoints; i++) for (i = 0; i < interface->bNumEndpoints; i++)
print_endpoint(&interface->endpoint[i]); print_endpoint(&interface->endpoint[i]);
@ -85,57 +80,57 @@ static void print_altsetting(const struct libusb_interface_descriptor *interface
static void print_2_0_ext_cap(struct libusb_usb_2_0_extension_descriptor *usb_2_0_ext_cap) static void print_2_0_ext_cap(struct libusb_usb_2_0_extension_descriptor *usb_2_0_ext_cap)
{ {
printf(" USB 2.0 Extension Capabilities:\n"); printf(" USB 2.0 Extension Capabilities:\n");
printf(" bDevCapabilityType: %d\n", usb_2_0_ext_cap->bDevCapabilityType); printf(" bDevCapabilityType: %u\n", usb_2_0_ext_cap->bDevCapabilityType);
printf(" bmAttributes: 0x%x\n", usb_2_0_ext_cap->bmAttributes); printf(" bmAttributes: %08xh\n", usb_2_0_ext_cap->bmAttributes);
} }
static void print_ss_usb_cap(struct libusb_ss_usb_device_capability_descriptor *ss_usb_cap) static void print_ss_usb_cap(struct libusb_ss_usb_device_capability_descriptor *ss_usb_cap)
{ {
printf(" USB 3.0 Capabilities:\n"); printf(" USB 3.0 Capabilities:\n");
printf(" bDevCapabilityType: %d\n", ss_usb_cap->bDevCapabilityType); printf(" bDevCapabilityType: %u\n", ss_usb_cap->bDevCapabilityType);
printf(" bmAttributes: 0x%x\n", ss_usb_cap->bmAttributes); printf(" bmAttributes: %02xh\n", ss_usb_cap->bmAttributes);
printf(" wSpeedSupported: 0x%x\n", ss_usb_cap->wSpeedSupported); printf(" wSpeedSupported: %u\n", ss_usb_cap->wSpeedSupported);
printf(" bFunctionalitySupport: %d\n", ss_usb_cap->bFunctionalitySupport); printf(" bFunctionalitySupport: %u\n", ss_usb_cap->bFunctionalitySupport);
printf(" bU1devExitLat: %d\n", ss_usb_cap->bU1DevExitLat); printf(" bU1devExitLat: %u\n", ss_usb_cap->bU1DevExitLat);
printf(" bU2devExitLat: %d\n", ss_usb_cap->bU2DevExitLat); printf(" bU2devExitLat: %u\n", ss_usb_cap->bU2DevExitLat);
} }
static void print_bos(libusb_device_handle *handle) static void print_bos(libusb_device_handle *handle)
{ {
struct libusb_bos_descriptor *bos; struct libusb_bos_descriptor *bos;
uint8_t i;
int ret; int ret;
ret = libusb_get_bos_descriptor(handle, &bos); ret = libusb_get_bos_descriptor(handle, &bos);
if (0 > ret) { if (ret < 0)
return; return;
}
printf(" Binary Object Store (BOS):\n"); printf(" Binary Object Store (BOS):\n");
printf(" wTotalLength: %d\n", bos->wTotalLength); printf(" wTotalLength: %u\n", bos->wTotalLength);
printf(" bNumDeviceCaps: %d\n", bos->bNumDeviceCaps); printf(" bNumDeviceCaps: %u\n", bos->bNumDeviceCaps);
if(bos->dev_capability[0]->bDevCapabilityType == LIBUSB_BT_USB_2_0_EXTENSION) { for (i = 0; i < bos->bNumDeviceCaps; i++) {
struct libusb_bos_dev_capability_descriptor *dev_cap = bos->dev_capability[i];
if (dev_cap->bDevCapabilityType == LIBUSB_BT_USB_2_0_EXTENSION) {
struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension; struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension;
ret = libusb_get_usb_2_0_extension_descriptor(NULL, bos->dev_capability[0],&usb_2_0_extension);
if (0 > ret) { ret = libusb_get_usb_2_0_extension_descriptor(NULL, dev_cap, &usb_2_0_extension);
if (ret < 0)
return; return;
}
print_2_0_ext_cap(usb_2_0_extension); print_2_0_ext_cap(usb_2_0_extension);
libusb_free_usb_2_0_extension_descriptor(usb_2_0_extension); libusb_free_usb_2_0_extension_descriptor(usb_2_0_extension);
} } else if (dev_cap->bDevCapabilityType == LIBUSB_BT_SS_USB_DEVICE_CAPABILITY) {
struct libusb_ss_usb_device_capability_descriptor *ss_dev_cap;
if(bos->dev_capability[0]->bDevCapabilityType == LIBUSB_BT_SS_USB_DEVICE_CAPABILITY) { ret = libusb_get_ss_usb_device_capability_descriptor(NULL, dev_cap, &ss_dev_cap);
if (ret < 0)
struct libusb_ss_usb_device_capability_descriptor *dev_cap;
ret = libusb_get_ss_usb_device_capability_descriptor(NULL, bos->dev_capability[0],&dev_cap);
if (0 > ret) {
return; return;
}
print_ss_usb_cap(dev_cap); print_ss_usb_cap(ss_dev_cap);
libusb_free_ss_usb_device_capability_descriptor(dev_cap); libusb_free_ss_usb_device_capability_descriptor(ss_dev_cap);
}
} }
libusb_free_bos_descriptor(bos); libusb_free_bos_descriptor(bos);
@ -154,79 +149,71 @@ static void print_configuration(struct libusb_config_descriptor *config)
uint8_t i; uint8_t i;
printf(" Configuration:\n"); printf(" Configuration:\n");
printf(" wTotalLength: %d\n", config->wTotalLength); printf(" wTotalLength: %u\n", config->wTotalLength);
printf(" bNumInterfaces: %d\n", config->bNumInterfaces); printf(" bNumInterfaces: %u\n", config->bNumInterfaces);
printf(" bConfigurationValue: %d\n", config->bConfigurationValue); printf(" bConfigurationValue: %u\n", config->bConfigurationValue);
printf(" iConfiguration: %d\n", config->iConfiguration); printf(" iConfiguration: %u\n", config->iConfiguration);
printf(" bmAttributes: %02xh\n", config->bmAttributes); printf(" bmAttributes: %02xh\n", config->bmAttributes);
printf(" MaxPower: %d\n", config->MaxPower); printf(" MaxPower: %u\n", config->MaxPower);
for (i = 0; i < config->bNumInterfaces; i++) for (i = 0; i < config->bNumInterfaces; i++)
print_interface(&config->interface[i]); print_interface(&config->interface[i]);
} }
static int print_device(libusb_device *dev, int level) static void print_device(libusb_device *dev, libusb_device_handle *handle)
{ {
struct libusb_device_descriptor desc; struct libusb_device_descriptor desc;
libusb_device_handle *handle = NULL; unsigned char string[256];
char description[260]; const char *speed;
char string[256];
int ret; int ret;
uint8_t i; 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); ret = libusb_get_device_descriptor(dev, &desc);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "failed to get device descriptor"); fprintf(stderr, "failed to get device descriptor");
return -1; return;
} }
ret = libusb_open(dev, &handle); printf("Dev (bus %u, device %u): %04X - %04X speed: %s\n",
if (LIBUSB_SUCCESS == ret) { libusb_get_bus_number(dev), libusb_get_device_address(dev),
desc.idVendor, desc.idProduct, speed);
if (!handle)
libusb_open(dev, &handle);
if (handle) {
if (desc.iManufacturer) { if (desc.iManufacturer) {
ret = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, string, sizeof(string)); ret = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, string, sizeof(string));
if (ret > 0) if (ret > 0)
snprintf(description, sizeof(description), "%s - ", string); printf(" Manufacturer: %s\n", (char *)string);
else
snprintf(description, sizeof(description), "%04X - ",
desc.idVendor);
} }
else
snprintf(description, sizeof(description), "%04X - ",
desc.idVendor);
if (desc.iProduct) { if (desc.iProduct) {
ret = libusb_get_string_descriptor_ascii(handle, desc.iProduct, string, sizeof(string)); ret = libusb_get_string_descriptor_ascii(handle, desc.iProduct, string, sizeof(string));
if (ret > 0) if (ret > 0)
snprintf(description + strlen(description), sizeof(description) - printf(" Product: %s\n", (char *)string);
strlen(description), "%s", string);
else
snprintf(description + strlen(description), sizeof(description) -
strlen(description), "%04X", desc.idProduct);
}
else
snprintf(description + strlen(description), sizeof(description) -
strlen(description), "%04X", desc.idProduct);
}
else {
snprintf(description, sizeof(description), "%04X - %04X",
desc.idVendor, desc.idProduct);
} }
printf("%.*sDev (bus %d, device %d): %s\n", level * 2, " ", if (desc.iSerialNumber && verbose) {
libusb_get_bus_number(dev), libusb_get_device_address(dev), description);
if (handle && verbose) {
if (desc.iSerialNumber) {
ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, string, sizeof(string)); ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, string, sizeof(string));
if (ret > 0) if (ret > 0)
printf("%.*s - Serial Number: %s\n", level * 2, printf(" Serial Number: %s\n", (char *)string);
" ", string);
} }
} }
if (verbose) { if (verbose) {
for (i = 0; i < desc.bNumConfigurations; i++) { for (i = 0; i < desc.bNumConfigurations; i++) {
struct libusb_config_descriptor *config; struct libusb_config_descriptor *config;
ret = libusb_get_config_descriptor(dev, i, &config); ret = libusb_get_config_descriptor(dev, i, &config);
if (LIBUSB_SUCCESS != ret) { if (LIBUSB_SUCCESS != ret) {
printf(" Couldn't retrieve descriptors\n"); printf(" Couldn't retrieve descriptors\n");
@ -238,40 +225,87 @@ static int print_device(libusb_device *dev, int level)
libusb_free_config_descriptor(config); libusb_free_config_descriptor(config);
} }
if (handle && desc.bcdUSB >= 0x0201) { if (handle && desc.bcdUSB >= 0x0201)
print_bos(handle); print_bos(handle);
} }
}
if (handle) if (handle)
libusb_close(handle); 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; 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[]) int main(int argc, char *argv[])
{ {
const char *device_name = NULL;
libusb_device **devs; libusb_device **devs;
ssize_t cnt; ssize_t cnt;
int r, i; int r, i;
if (argc > 1 && !strcmp(argv[1], "-v")) for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-v")) {
verbose = 1; 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); r = libusb_init(NULL);
if (r < 0) if (r < 0)
return r; return r;
if (device_name) {
r = test_wrapped_device(device_name);
} else {
cnt = libusb_get_device_list(NULL, &devs); cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0) if (cnt < 0) {
return (int)cnt; libusb_exit(NULL);
return 1;
for (i = 0; devs[i]; ++i) {
print_device(devs[i], 0);
} }
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); libusb_exit(NULL);
return 0; return r;
} }

View file

@ -18,36 +18,21 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdarg.h> #include <time.h>
#include "libusb.h" #include "libusb.h"
#if defined(_WIN32)
#define msleep(msecs) Sleep(msecs)
#else
#include <time.h>
#define msleep(msecs) nanosleep(&(struct timespec){msecs / 1000, (msecs * 1000000) % 1000000000UL}, NULL);
#endif
#if defined(_MSC_VER) #if defined(_MSC_VER)
#define snprintf _snprintf #define snprintf _snprintf
#define putenv _putenv #define putenv _putenv
#endif #endif
#if !defined(bool)
#define bool int
#endif
#if !defined(true)
#define true (1 == 1)
#endif
#if !defined(false)
#define false (!true)
#endif
// Future versions of libusb will use usb_interface instead of interface // Future versions of libusb will use usb_interface instead of interface
// in libusb_config_descriptor => catter for that // in libusb_config_descriptor => catter for that
#define usb_interface interface #define usb_interface interface
@ -58,6 +43,16 @@ static bool extra_info = false;
static bool force_device_request = false; // For WCID descriptor queries static bool force_device_request = false; // For WCID descriptor queries
static const char* binary_name = NULL; static const char* binary_name = NULL;
static inline void msleep(int msecs)
{
#if defined(_WIN32)
Sleep(msecs);
#else
const struct timespec ts = { msecs / 1000, (msecs % 1000) * 1000000L };
nanosleep(&ts, NULL);
#endif
}
static void perr(char const *format, ...) static void perr(char const *format, ...)
{ {
va_list args; va_list args;
@ -976,6 +971,7 @@ static int test_device(uint16_t vid, uint16_t pid)
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
static char debug_env_str[] = "LIBUSB_DEBUG=4"; // LIBUSB_LOG_LEVEL_DEBUG
bool show_help = false; bool show_help = false;
bool debug_mode = false; bool debug_mode = false;
const struct libusb_version* version; const struct libusb_version* version;
@ -1103,7 +1099,7 @@ int main(int argc, char** argv)
// but since we can't call on libusb_set_option() before libusb_init(), we use the env variable method // but since we can't call on libusb_set_option() before libusb_init(), we use the env variable method
old_dbg_str = getenv("LIBUSB_DEBUG"); old_dbg_str = getenv("LIBUSB_DEBUG");
if (debug_mode) { if (debug_mode) {
if (putenv("LIBUSB_DEBUG=4") != 0) // LIBUSB_LOG_LEVEL_DEBUG if (putenv(debug_env_str) != 0)
printf("Unable to set debug level\n"); printf("Unable to set debug level\n");
} }

View file

@ -1,101 +1,88 @@
all: libusb-1.0.la libusb-1.0.dll
AUTOMAKE_OPTIONS = subdir-objects AUTOMAKE_OPTIONS = subdir-objects
AM_CFLAGS += -fvisibility=hidden $(THREAD_CFLAGS)
AM_CXXFLAGS += -fvisibility=hidden $(THREAD_CFLAGS)
lib_LTLIBRARIES = libusb-1.0.la lib_LTLIBRARIES = libusb-1.0.la
POSIX_POLL_SRC = os/poll_posix.h os/poll_posix.c POSIX_PLATFORM_SRC = os/events_posix.h os/events_posix.c \
POSIX_THREADS_SRC = os/threads_posix.h os/threads_posix.c os/threads_posix.h os/threads_posix.c
WINDOWS_POLL_SRC = os/poll_windows.h os/poll_windows.c WINDOWS_PLATFORM_SRC = os/events_windows.h os/events_windows.c \
WINDOWS_THREADS_SRC = os/threads_windows.h os/threads_windows.c os/threads_windows.h os/threads_windows.c
LINUX_USBFS_SRC = os/linux_usbfs.h os/linux_usbfs.c
DARWIN_USB_SRC = os/darwin_usb.h os/darwin_usb.c if PLATFORM_POSIX
OPENBSD_USB_SRC = os/openbsd_usb.c PLATFORM_SRC = $(POSIX_PLATFORM_SRC)
NETBSD_USB_SRC = os/netbsd_usb.c else
SUNOS_USB_SRC = os/sunos_usb.c os/sunos_usb.h PLATFORM_SRC = $(WINDOWS_PLATFORM_SRC)
WINDOWS_USB_SRC = libusb-1.0.def libusb-1.0.rc \ endif
os/windows_common.h \
os/windows_nt_common.h os/windows_nt_common.c \ OS_DARWIN_SRC = os/darwin_usb.h os/darwin_usb.c
os/windows_nt_shared_types.h \ OS_HAIKU_SRC = os/haiku_usb.h os/haiku_usb_backend.cpp \
os/haiku_pollfs.cpp os/haiku_usb_raw.h os/haiku_usb_raw.cpp
OS_LINUX_SRC = os/linux_usbfs.h os/linux_usbfs.c
OS_NETBSD_SRC = os/netbsd_usb.c
OS_NULL_SRC = os/null_usb.c
OS_OPENBSD_SRC = os/openbsd_usb.c
OS_SUNOS_SRC = os/sunos_usb.h os/sunos_usb.c
OS_WINDOWS_SRC = libusb-1.0.def libusb-1.0.rc \
os/windows_common.h os/windows_common.c \
os/windows_usbdk.h os/windows_usbdk.c \ os/windows_usbdk.h os/windows_usbdk.c \
os/windows_winusb.h os/windows_winusb.c os/windows_winusb.h os/windows_winusb.c
WINCE_USB_SRC = os/wince_usb.h os/wince_usb.c
HAIKU_USB_SRC = os/haiku_usb.h os/haiku_usb_backend.cpp \
os/haiku_usb_raw.h os/haiku_usb_raw.cpp os/haiku_pollfs.cpp
EXTRA_DIST = $(POSIX_POLL_SRC) $(POSIX_THREADS_SRC) \
$(WINDOWS_POLL_SRC) $(WINDOWS_THREADS_SRC) \
$(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) \
$(OPENBSD_USB_SRC) $(NETBSD_USB_SRC) \
$(WINDOWS_USB_SRC) $(WINCE_USB_SRC) \
$(HAIKU_USB_SRC) \
os/linux_udev.c os/linux_netlink.c
if OS_LINUX
if USE_UDEV
OS_SRC = $(LINUX_USBFS_SRC) os/linux_udev.c
else
OS_SRC = $(LINUX_USBFS_SRC) os/linux_netlink.c
endif
endif
if OS_DARWIN if OS_DARWIN
OS_SRC = $(DARWIN_USB_SRC) OS_SRC = $(OS_DARWIN_SRC)
AM_CFLAGS_EXT = -no-cpp-precomp
endif
if OS_OPENBSD
OS_SRC = $(OPENBSD_USB_SRC)
endif
if OS_NETBSD
OS_SRC = $(NETBSD_USB_SRC)
endif
if OS_SUNOS
OS_SRC = $(SUNOS_USB_SRC)
endif endif
if OS_HAIKU if OS_HAIKU
noinst_LTLIBRARIES = libusb_haiku.la noinst_LTLIBRARIES = libusb_haiku.la
libusb_haiku_la_SOURCES = $(HAIKU_USB_SRC) libusb_haiku_la_SOURCES = $(OS_HAIKU_SRC)
libusb_1_0_la_LIBADD = libusb_haiku.la libusb_1_0_la_LIBADD = libusb_haiku.la
endif endif
if OS_WINDOWS if OS_LINUX
OS_SRC = $(WINDOWS_USB_SRC) OS_SRC = $(OS_LINUX_SRC)
if USE_UDEV
.rc.lo: OS_SRC += os/linux_udev.c
$(AM_V_GEN)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --tag=RC --mode=compile $(RC) $(RCFLAGS) -i $< -o $@ else
OS_SRC += os/linux_netlink.c
libusb-1.0.rc: version.h version_nano.h endif
endif endif
libusb-1.0.dll: libusb-1.0.def libusb-1.0.la if OS_NETBSD
OS_SRC = $(OS_NETBSD_SRC)
endif
if OS_NULL
OS_SRC = $(OS_NULL_SRC)
endif
if OS_OPENBSD
OS_SRC = $(OS_OPENBSD_SRC)
endif
if OS_SUNOS
OS_SRC = $(OS_SUNOS_SRC)
endif
if OS_WINDOWS
OS_SRC = $(OS_WINDOWS_SRC)
include Makefile.am.extra
# Dependencies for compiling libusb-1.0.lo from libusb-1.0.rc
-include ./$(DEPDIR)/libusb-1.0.Plo
if CREATE_IMPORT_LIB if CREATE_IMPORT_LIB
all-local: .libs/libusb-1.0.dll.a
# Rebuild the import lib from the .def so that MS and MinGW DLLs can be interchanged # Rebuild the import lib from the .def so that MS and MinGW DLLs can be interchanged
$(AM_V_GEN)$(DLLTOOL) $(DLLTOOLFLAGS) --kill-at --input-def $(srcdir)/libusb-1.0.def --dllname $@ --output-lib .libs/$@.a .libs/libusb-1.0.dll.a: libusb-1.0.def libusb-1.0.la
$(AM_V_DLLTOOL)$(DLLTOOL) $(DLLTOOLFLAGS) --kill-at --input-def $< --dllname libusb-1.0.dll --output-lib $@
endif
endif endif
if OS_WINDOWS libusb_1_0_la_LDFLAGS = $(LT_LDFLAGS)
POLL_SRC = $(WINDOWS_POLL_SRC) libusb_1_0_la_SOURCES = libusbi.h version.h version_nano.h \
else
POLL_SRC = $(POSIX_POLL_SRC)
endif
if THREADS_POSIX
THREADS_SRC = $(POSIX_THREADS_SRC)
else
THREADS_SRC = $(WINDOWS_THREADS_SRC)
endif
libusb_1_0_la_CFLAGS = $(AM_CFLAGS)
libusb_1_0_la_LDFLAGS = $(LTLDFLAGS)
libusb_1_0_la_SOURCES = libusbi.h libusb.h version.h version_nano.h \
core.c descriptor.c hotplug.h hotplug.c io.c strerror.c sync.c \ core.c descriptor.c hotplug.h hotplug.c io.c strerror.c sync.c \
$(POLL_SRC) $(THREADS_SRC) $(OS_SRC) $(PLATFORM_SRC) $(OS_SRC)
hdrdir = $(includedir)/libusb-1.0 pkginclude_HEADERS = libusb.h
hdr_HEADERS = libusb.h

View file

@ -0,0 +1,26 @@
AM_V_DLLTOOL = $(am__v_DLLTOOL_$(V))
am__v_DLLTOOL_ = $(am__v_DLLTOOL_$(AM_DEFAULT_VERBOSITY))
am__v_DLLTOOL_0 = @echo " DLLTOOL " $@;
am__v_DLLTOOL_1 =
AM_V_RC = $(am__v_RC_$(V))
am__v_RC_ = $(am__v_RC_$(AM_DEFAULT_VERBOSITY))
am__v_RC_0 = @echo " RC " $@;
am__v_RC_1 =
LTRC = $(LIBTOOL) $(AM_V_lt) --tag=RC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(RC) $(AM_RCFLAGS) \
$(RCFLAGS)
RCPPARGS = \
--preprocessor-arg -MT \
--preprocessor-arg $@ \
--preprocessor-arg -MD \
--preprocessor-arg -MP \
--preprocessor-arg -MF \
--preprocessor-arg $$depbase.Tpo
.rc.lo:
$(AM_V_RC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
$(LTRC) $(RCPPARGS) -i $< -o $@ &&\
$(am__mv) $$depbase.Tpo $$depbase.Plo

View file

@ -20,39 +20,28 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "config.h" #include "libusbi.h"
#include "hotplug.h"
#include <errno.h> #include "version.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_SYSLOG_H
#include <syslog.h>
#endif
#ifdef __ANDROID__ #ifdef __ANDROID__
#include <android/log.h> #include <android/log.h>
#endif #endif
#include <stdio.h>
#include <string.h>
#ifdef HAVE_SYSLOG
#include <syslog.h>
#endif
#include "libusbi.h" struct libusb_context *usbi_default_context;
#include "hotplug.h"
struct libusb_context *usbi_default_context = NULL;
static const struct libusb_version libusb_version_internal = static const struct libusb_version libusb_version_internal =
{ LIBUSB_MAJOR, LIBUSB_MINOR, LIBUSB_MICRO, LIBUSB_NANO, { LIBUSB_MAJOR, LIBUSB_MINOR, LIBUSB_MICRO, LIBUSB_NANO,
LIBUSB_RC, "http://libusb.info" }; LIBUSB_RC, "http://libusb.info" };
static int default_context_refcnt = 0; static int default_context_refcnt;
static usbi_mutex_static_t default_context_lock = USBI_MUTEX_INITIALIZER; static usbi_mutex_static_t default_context_lock = USBI_MUTEX_INITIALIZER;
static struct timespec timestamp_origin = { 0, 0 }; static struct timespec timestamp_origin;
#ifndef USE_SYSTEM_LOGGING_FACILITY #if defined(ENABLE_LOGGING) && !defined(USE_SYSTEM_LOGGING_FACILITY)
static libusb_log_cb log_handler = NULL; static libusb_log_cb log_handler;
#endif #endif
usbi_mutex_static_t active_contexts_lock = USBI_MUTEX_INITIALIZER; usbi_mutex_static_t active_contexts_lock = USBI_MUTEX_INITIALIZER;
@ -168,6 +157,36 @@ struct list_head active_contexts_list;
/** /**
* \page libusb_caveats Caveats * \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 * \section fork Fork considerations
* *
* libusb is <em>not</em> designed to work across fork() calls. Depending on * libusb is <em>not</em> designed to work across fork() calls. Depending on
@ -442,6 +461,7 @@ if (cfg != desired)
* - libusb_unlock_event_waiters() * - libusb_unlock_event_waiters()
* - libusb_unref_device() * - libusb_unref_device()
* - libusb_wait_for_event() * - libusb_wait_for_event()
* - libusb_wrap_sys_device()
* *
* \section Structures * \section Structures
* - libusb_bos_descriptor * - libusb_bos_descriptor
@ -470,6 +490,7 @@ if (cfg != desired)
* - \ref libusb_class_code * - \ref libusb_class_code
* - \ref libusb_descriptor_type * - \ref libusb_descriptor_type
* - \ref libusb_endpoint_direction * - \ref libusb_endpoint_direction
* - \ref libusb_endpoint_transfer_type
* - \ref libusb_error * - \ref libusb_error
* - \ref libusb_iso_sync_type * - \ref libusb_iso_sync_type
* - \ref libusb_iso_usage_type * - \ref libusb_iso_usage_type
@ -678,17 +699,12 @@ struct libusb_device *usbi_alloc_device(struct libusb_context *ctx,
unsigned long session_id) unsigned long session_id)
{ {
size_t priv_size = usbi_backend.device_priv_size; size_t priv_size = usbi_backend.device_priv_size;
struct libusb_device *dev = calloc(1, sizeof(*dev) + priv_size); struct libusb_device *dev = calloc(1, PTR_ALIGN(sizeof(*dev)) + priv_size);
int r;
if (!dev) if (!dev)
return NULL; return NULL;
r = usbi_mutex_init(&dev->lock); usbi_mutex_init(&dev->lock);
if (r) {
free(dev);
return NULL;
}
dev->ctx = ctx; dev->ctx = ctx;
dev->refcnt = 1; dev->refcnt = 1;
@ -746,21 +762,22 @@ void usbi_disconnect_device(struct libusb_device *dev)
* to the discovered device list. */ * to the discovered device list. */
int usbi_sanitize_device(struct libusb_device *dev) int usbi_sanitize_device(struct libusb_device *dev)
{ {
int r;
uint8_t num_configurations; uint8_t num_configurations;
r = usbi_device_cache_descriptor(dev); if (dev->device_descriptor.bLength != LIBUSB_DT_DEVICE_SIZE ||
if (r < 0) dev->device_descriptor.bDescriptorType != LIBUSB_DT_DEVICE) {
return r; usbi_err(DEVICE_CTX(dev), "invalid device descriptor");
return LIBUSB_ERROR_IO;
}
num_configurations = dev->device_descriptor.bNumConfigurations; num_configurations = dev->device_descriptor.bNumConfigurations;
if (num_configurations > USB_MAXCONFIG) { if (num_configurations > USB_MAXCONFIG) {
usbi_err(DEVICE_CTX(dev), "too many configurations"); usbi_err(DEVICE_CTX(dev), "too many configurations");
return LIBUSB_ERROR_IO; return LIBUSB_ERROR_IO;
} else if (0 == num_configurations) } else if (0 == num_configurations) {
usbi_dbg("zero configurations, maybe an unauthorized device"); usbi_dbg("zero configurations, maybe an unauthorized device");
}
dev->num_configurations = num_configurations;
return 0; return 0;
} }
@ -774,11 +791,12 @@ struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx,
struct libusb_device *ret = NULL; struct libusb_device *ret = NULL;
usbi_mutex_lock(&ctx->usb_devs_lock); 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) { if (dev->session_data == session_id) {
ret = libusb_ref_device(dev); ret = libusb_ref_device(dev);
break; break;
} }
}
usbi_mutex_unlock(&ctx->usb_devs_lock); usbi_mutex_unlock(&ctx->usb_devs_lock);
return ret; return ret;
@ -811,12 +829,14 @@ ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx,
struct libusb_device **ret; struct libusb_device **ret;
int r = 0; int r = 0;
ssize_t i, len; ssize_t i, len;
USBI_GET_CONTEXT(ctx);
usbi_dbg(" "); usbi_dbg(" ");
if (!discdevs) if (!discdevs)
return LIBUSB_ERROR_NO_MEM; return LIBUSB_ERROR_NO_MEM;
ctx = usbi_get_context(ctx);
if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
/* backend provides hotplug support */ /* backend provides hotplug support */
struct libusb_device *dev; struct libusb_device *dev;
@ -825,7 +845,7 @@ ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx,
usbi_backend.hotplug_poll(); usbi_backend.hotplug_poll();
usbi_mutex_lock(&ctx->usb_devs_lock); 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); discdevs = discovered_devs_append(discdevs, dev);
if (!discdevs) { if (!discdevs) {
@ -952,7 +972,7 @@ int API_EXPORTED libusb_get_port_numbers(libusb_device *dev,
} }
/** \ingroup libusb_dev /** \ingroup libusb_dev
* Deprecated please use libusb_get_port_numbers instead. * \deprecated Please use \ref libusb_get_port_numbers() instead.
*/ */
int API_EXPORTED libusb_get_port_path(libusb_context *ctx, libusb_device *dev, int API_EXPORTED libusb_get_port_path(libusb_context *ctx, libusb_device *dev,
uint8_t *port_numbers, uint8_t port_numbers_len) uint8_t *port_numbers, uint8_t port_numbers_len)
@ -1102,7 +1122,7 @@ int API_EXPORTED libusb_get_max_iso_packet_size(libusb_device *dev,
struct libusb_config_descriptor *config; struct libusb_config_descriptor *config;
const struct libusb_endpoint_descriptor *ep; const struct libusb_endpoint_descriptor *ep;
struct libusb_ss_endpoint_companion_descriptor *ss_ep_cmp; struct libusb_ss_endpoint_companion_descriptor *ss_ep_cmp;
enum libusb_transfer_type ep_type; enum libusb_endpoint_transfer_type ep_type;
uint16_t val; uint16_t val;
int r; int r;
int speed; int speed;
@ -1121,7 +1141,7 @@ int API_EXPORTED libusb_get_max_iso_packet_size(libusb_device *dev,
} }
speed = libusb_get_device_speed(dev); speed = libusb_get_device_speed(dev);
if (speed == LIBUSB_SPEED_SUPER) { if (speed >= LIBUSB_SPEED_SUPER) {
r = libusb_get_ss_endpoint_companion_descriptor(dev->ctx, ep, &ss_ep_cmp); r = libusb_get_ss_endpoint_companion_descriptor(dev->ctx, ep, &ss_ep_cmp);
if (r == LIBUSB_SUCCESS) { if (r == LIBUSB_SUCCESS) {
r = ss_ep_cmp->wBytesPerInterval; r = ss_ep_cmp->wBytesPerInterval;
@ -1130,13 +1150,13 @@ int API_EXPORTED libusb_get_max_iso_packet_size(libusb_device *dev,
} }
/* If the device isn't a SuperSpeed device or retrieving the SS endpoint didn't worked. */ /* If the device isn't a SuperSpeed device or retrieving the SS endpoint didn't worked. */
if (speed != LIBUSB_SPEED_SUPER || r < 0) { if (speed < LIBUSB_SPEED_SUPER || r < 0) {
val = ep->wMaxPacketSize; val = ep->wMaxPacketSize;
ep_type = (enum libusb_transfer_type) (ep->bmAttributes & 0x3); ep_type = (enum libusb_endpoint_transfer_type) (ep->bmAttributes & 0x3);
r = val & 0x07ff; r = val & 0x07ff;
if (ep_type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS if (ep_type == LIBUSB_ENDPOINT_TRANSFER_TYPE_ISOCHRONOUS
|| ep_type == LIBUSB_TRANSFER_TYPE_INTERRUPT) || ep_type == LIBUSB_ENDPOINT_TRANSFER_TYPE_INTERRUPT)
r *= (1 + ((val >> 11) & 3)); r *= (1 + ((val >> 11) & 3));
} }
@ -1193,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 /** \ingroup libusb_dev
* Wrap a platform-specific system device handle and obtain a libusb device * 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 * handle for the underlying device. The handle allows you to use libusb to
* perform I/O on the device in question. * 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 Linux, the system device handle must be a valid file descriptor opened
* on the device node. * on the device node.
* *
@ -1265,31 +1250,23 @@ int API_EXPORTED libusb_wrap_sys_device(libusb_context *ctx, intptr_t sys_dev,
struct libusb_device_handle *_dev_handle; struct libusb_device_handle *_dev_handle;
size_t priv_size = usbi_backend.device_handle_priv_size; size_t priv_size = usbi_backend.device_handle_priv_size;
int r; int r;
usbi_dbg("wrap_sys_device %p", (void *)sys_dev);
USBI_GET_CONTEXT(ctx); usbi_dbg("wrap_sys_device 0x%" PRIxPTR, (uintptr_t)sys_dev);
ctx = usbi_get_context(ctx);
if (!usbi_backend.wrap_sys_device) if (!usbi_backend.wrap_sys_device)
return LIBUSB_ERROR_NOT_SUPPORTED; return LIBUSB_ERROR_NOT_SUPPORTED;
_dev_handle = malloc(sizeof(*_dev_handle) + priv_size); _dev_handle = calloc(1, PTR_ALIGN(sizeof(*_dev_handle)) + priv_size);
if (!_dev_handle) if (!_dev_handle)
return LIBUSB_ERROR_NO_MEM; return LIBUSB_ERROR_NO_MEM;
r = usbi_mutex_init(&_dev_handle->lock); usbi_mutex_init(&_dev_handle->lock);
if (r) {
free(_dev_handle);
return LIBUSB_ERROR_OTHER;
}
_dev_handle->dev = NULL;
_dev_handle->auto_detach_kernel_driver = 0;
_dev_handle->claimed_interfaces = 0;
memset(&_dev_handle->os_priv, 0, priv_size);
r = usbi_backend.wrap_sys_device(ctx, _dev_handle, sys_dev); r = usbi_backend.wrap_sys_device(ctx, _dev_handle, sys_dev);
if (r < 0) { 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); usbi_mutex_destroy(&_dev_handle->lock);
free(_dev_handle); free(_dev_handle);
return r; return r;
@ -1335,20 +1312,13 @@ int API_EXPORTED libusb_open(libusb_device *dev,
return LIBUSB_ERROR_NO_DEVICE; return LIBUSB_ERROR_NO_DEVICE;
} }
_dev_handle = malloc(sizeof(*_dev_handle) + priv_size); _dev_handle = calloc(1, PTR_ALIGN(sizeof(*_dev_handle)) + priv_size);
if (!_dev_handle) if (!_dev_handle)
return LIBUSB_ERROR_NO_MEM; return LIBUSB_ERROR_NO_MEM;
r = usbi_mutex_init(&_dev_handle->lock); usbi_mutex_init(&_dev_handle->lock);
if (r) {
free(_dev_handle);
return LIBUSB_ERROR_OTHER;
}
_dev_handle->dev = libusb_ref_device(dev); _dev_handle->dev = libusb_ref_device(dev);
_dev_handle->auto_detach_kernel_driver = 0;
_dev_handle->claimed_interfaces = 0;
memset(&_dev_handle->os_priv, 0, priv_size);
r = usbi_backend.open(_dev_handle); r = usbi_backend.open(_dev_handle);
if (r < 0) { if (r < 0) {
@ -1429,7 +1399,7 @@ static void do_close(struct libusb_context *ctx,
usbi_mutex_lock(&ctx->flying_transfers_lock); usbi_mutex_lock(&ctx->flying_transfers_lock);
/* safe iteration because transfers may be being deleted */ /* 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 = struct libusb_transfer *transfer =
USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
@ -1487,8 +1457,8 @@ static void do_close(struct libusb_context *ctx,
void API_EXPORTED libusb_close(libusb_device_handle *dev_handle) void API_EXPORTED libusb_close(libusb_device_handle *dev_handle)
{ {
struct libusb_context *ctx; struct libusb_context *ctx;
unsigned int event_flags;
int handling_events; int handling_events;
int pending_events;
if (!dev_handle) if (!dev_handle)
return; return;
@ -1509,10 +1479,11 @@ void API_EXPORTED libusb_close(libusb_device_handle *dev_handle)
/* Record that we are closing a device. /* Record that we are closing a device.
* Only signal an event if there are no prior pending events. */ * Only signal an event if there are no prior pending events. */
usbi_mutex_lock(&ctx->event_data_lock); usbi_mutex_lock(&ctx->event_data_lock);
pending_events = usbi_pending_events(ctx); event_flags = ctx->event_flags;
ctx->device_close++; if (!ctx->device_close++)
if (!pending_events) ctx->event_flags |= USBI_EVENT_DEVICE_CLOSE;
usbi_signal_event(ctx); if (!event_flags)
usbi_signal_event(&ctx->event);
usbi_mutex_unlock(&ctx->event_data_lock); usbi_mutex_unlock(&ctx->event_data_lock);
/* take event handling lock */ /* take event handling lock */
@ -1526,10 +1497,10 @@ void API_EXPORTED libusb_close(libusb_device_handle *dev_handle)
/* We're done with closing this device. /* We're done with closing this device.
* Clear the event pipe if there are no further pending events. */ * Clear the event pipe if there are no further pending events. */
usbi_mutex_lock(&ctx->event_data_lock); usbi_mutex_lock(&ctx->event_data_lock);
ctx->device_close--; if (!--ctx->device_close)
pending_events = usbi_pending_events(ctx); ctx->event_flags &= ~USBI_EVENT_DEVICE_CLOSE;
if (!pending_events) if (!ctx->event_flags)
usbi_clear_event(ctx); usbi_clear_event(&ctx->event);
usbi_mutex_unlock(&ctx->event_data_lock); usbi_mutex_unlock(&ctx->event_data_lock);
/* Release event handling lock and wake up event waiters */ /* Release event handling lock and wake up event waiters */
@ -1574,29 +1545,30 @@ int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev_handle,
int *config) int *config)
{ {
int r = LIBUSB_ERROR_NOT_SUPPORTED; int r = LIBUSB_ERROR_NOT_SUPPORTED;
uint8_t tmp = 0;
usbi_dbg(" "); usbi_dbg(" ");
if (usbi_backend.get_configuration) if (usbi_backend.get_configuration)
r = usbi_backend.get_configuration(dev_handle, config); r = usbi_backend.get_configuration(dev_handle, &tmp);
if (r == LIBUSB_ERROR_NOT_SUPPORTED) { if (r == LIBUSB_ERROR_NOT_SUPPORTED) {
uint8_t tmp = 0;
usbi_dbg("falling back to control message"); usbi_dbg("falling back to control message");
r = libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_IN, r = libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_IN,
LIBUSB_REQUEST_GET_CONFIGURATION, 0, 0, &tmp, 1, 1000); LIBUSB_REQUEST_GET_CONFIGURATION, 0, 0, &tmp, 1, 1000);
if (r == 0) { if (r == 1) {
r = 0;
} else if (r == 0) {
usbi_err(HANDLE_CTX(dev_handle), "zero bytes returned in ctrl transfer?"); usbi_err(HANDLE_CTX(dev_handle), "zero bytes returned in ctrl transfer?");
r = LIBUSB_ERROR_IO; r = LIBUSB_ERROR_IO;
} else if (r == 1) {
r = 0;
*config = tmp;
} else { } else {
usbi_dbg("control failed, error %d", r); usbi_dbg("control failed, error %d", r);
} }
} }
if (r == 0) if (r == 0) {
usbi_dbg("active config %d", *config); usbi_dbg("active config %u", tmp);
*config = (int)tmp;
}
return r; return r;
} }
@ -1615,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, * causing most USB-related device state to be reset (altsetting reset to zero,
* endpoint halts cleared, toggles reset). * 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 * You cannot change/reset configuration if your application has claimed
* interfaces. It is advised to set the desired configuration before claiming * interfaces. It is advised to set the desired configuration before claiming
* interfaces. * interfaces.
@ -1644,6 +1621,8 @@ int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev_handle,
* \returns 0 on success * \returns 0 on success
* \returns LIBUSB_ERROR_NOT_FOUND if the requested configuration does not exist * \returns LIBUSB_ERROR_NOT_FOUND if the requested configuration does not exist
* \returns LIBUSB_ERROR_BUSY if interfaces are currently claimed * \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 LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
* \returns another LIBUSB_ERROR code on other failure * \returns another LIBUSB_ERROR code on other failure
* \see libusb_set_auto_detach_kernel_driver() * \see libusb_set_auto_detach_kernel_driver()
@ -1652,6 +1631,8 @@ int API_EXPORTED libusb_set_configuration(libusb_device_handle *dev_handle,
int configuration) int configuration)
{ {
usbi_dbg("configuration %d", configuration); usbi_dbg("configuration %d", configuration);
if (configuration < -1 || configuration > (int)UINT8_MAX)
return LIBUSB_ERROR_INVALID_PARAM;
return usbi_backend.set_configuration(dev_handle, configuration); return usbi_backend.set_configuration(dev_handle, configuration);
} }
@ -1689,7 +1670,7 @@ int API_EXPORTED libusb_claim_interface(libusb_device_handle *dev_handle,
int r = 0; int r = 0;
usbi_dbg("interface %d", interface_number); usbi_dbg("interface %d", interface_number);
if (interface_number >= USB_MAXINTERFACES) if (interface_number < 0 || interface_number >= USB_MAXINTERFACES)
return LIBUSB_ERROR_INVALID_PARAM; return LIBUSB_ERROR_INVALID_PARAM;
if (!dev_handle->dev->attached) if (!dev_handle->dev->attached)
@ -1699,7 +1680,7 @@ int API_EXPORTED libusb_claim_interface(libusb_device_handle *dev_handle,
if (dev_handle->claimed_interfaces & (1U << interface_number)) if (dev_handle->claimed_interfaces & (1U << interface_number))
goto out; goto out;
r = usbi_backend.claim_interface(dev_handle, interface_number); r = usbi_backend.claim_interface(dev_handle, (uint8_t)interface_number);
if (r == 0) if (r == 0)
dev_handle->claimed_interfaces |= 1U << interface_number; dev_handle->claimed_interfaces |= 1U << interface_number;
@ -1733,7 +1714,7 @@ int API_EXPORTED libusb_release_interface(libusb_device_handle *dev_handle,
int r; int r;
usbi_dbg("interface %d", interface_number); usbi_dbg("interface %d", interface_number);
if (interface_number >= USB_MAXINTERFACES) if (interface_number < 0 || interface_number >= USB_MAXINTERFACES)
return LIBUSB_ERROR_INVALID_PARAM; return LIBUSB_ERROR_INVALID_PARAM;
usbi_mutex_lock(&dev_handle->lock); usbi_mutex_lock(&dev_handle->lock);
@ -1742,7 +1723,7 @@ int API_EXPORTED libusb_release_interface(libusb_device_handle *dev_handle,
goto out; goto out;
} }
r = usbi_backend.release_interface(dev_handle, interface_number); r = usbi_backend.release_interface(dev_handle, (uint8_t)interface_number);
if (r == 0) if (r == 0)
dev_handle->claimed_interfaces &= ~(1U << interface_number); dev_handle->claimed_interfaces &= ~(1U << interface_number);
@ -1777,7 +1758,9 @@ int API_EXPORTED libusb_set_interface_alt_setting(libusb_device_handle *dev_hand
{ {
usbi_dbg("interface %d altsetting %d", usbi_dbg("interface %d altsetting %d",
interface_number, alternate_setting); interface_number, alternate_setting);
if (interface_number >= USB_MAXINTERFACES) if (interface_number < 0 || interface_number >= USB_MAXINTERFACES)
return LIBUSB_ERROR_INVALID_PARAM;
if (alternate_setting < 0 || alternate_setting > (int)UINT8_MAX)
return LIBUSB_ERROR_INVALID_PARAM; return LIBUSB_ERROR_INVALID_PARAM;
usbi_mutex_lock(&dev_handle->lock); usbi_mutex_lock(&dev_handle->lock);
@ -1792,8 +1775,8 @@ int API_EXPORTED libusb_set_interface_alt_setting(libusb_device_handle *dev_hand
} }
usbi_mutex_unlock(&dev_handle->lock); usbi_mutex_unlock(&dev_handle->lock);
return usbi_backend.set_interface_altsetting(dev_handle, interface_number, return usbi_backend.set_interface_altsetting(dev_handle,
alternate_setting); (uint8_t)interface_number, (uint8_t)alternate_setting);
} }
/** \ingroup libusb_dev /** \ingroup libusb_dev
@ -1847,7 +1830,10 @@ int API_EXPORTED libusb_reset_device(libusb_device_handle *dev_handle)
if (!dev_handle->dev->attached) if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE; return LIBUSB_ERROR_NO_DEVICE;
if (usbi_backend.reset_device)
return usbi_backend.reset_device(dev_handle); return usbi_backend.reset_device(dev_handle);
else
return LIBUSB_ERROR_NOT_SUPPORTED;
} }
/** \ingroup libusb_asyncio /** \ingroup libusb_asyncio
@ -1876,6 +1862,9 @@ int API_EXPORTED libusb_alloc_streams(libusb_device_handle *dev_handle,
{ {
usbi_dbg("streams %u eps %d", (unsigned)num_streams, num_endpoints); usbi_dbg("streams %u eps %d", (unsigned)num_streams, num_endpoints);
if (!num_streams || !endpoints || num_endpoints <= 0)
return LIBUSB_ERROR_INVALID_PARAM;
if (!dev_handle->dev->attached) if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE; return LIBUSB_ERROR_NO_DEVICE;
@ -1903,6 +1892,9 @@ int API_EXPORTED libusb_free_streams(libusb_device_handle *dev_handle,
{ {
usbi_dbg("eps %d", num_endpoints); usbi_dbg("eps %d", num_endpoints);
if (!endpoints || num_endpoints <= 0)
return LIBUSB_ERROR_INVALID_PARAM;
if (!dev_handle->dev->attached) if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE; return LIBUSB_ERROR_NO_DEVICE;
@ -1925,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 * 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. * 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 * and will always return NULL. Memory allocated with this function must be
* freed with \ref libusb_dev_mem_free. Specifically, this means that the * 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 * flag \ref LIBUSB_TRANSFER_FREE_BUFFER cannot be used to free memory allocated
@ -1989,11 +1981,14 @@ int API_EXPORTED libusb_kernel_driver_active(libusb_device_handle *dev_handle,
{ {
usbi_dbg("interface %d", interface_number); usbi_dbg("interface %d", interface_number);
if (interface_number < 0 || interface_number >= USB_MAXINTERFACES)
return LIBUSB_ERROR_INVALID_PARAM;
if (!dev_handle->dev->attached) if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE; return LIBUSB_ERROR_NO_DEVICE;
if (usbi_backend.kernel_driver_active) if (usbi_backend.kernel_driver_active)
return usbi_backend.kernel_driver_active(dev_handle, interface_number); return usbi_backend.kernel_driver_active(dev_handle, (uint8_t)interface_number);
else else
return LIBUSB_ERROR_NOT_SUPPORTED; return LIBUSB_ERROR_NOT_SUPPORTED;
} }
@ -2024,11 +2019,14 @@ int API_EXPORTED libusb_detach_kernel_driver(libusb_device_handle *dev_handle,
{ {
usbi_dbg("interface %d", interface_number); usbi_dbg("interface %d", interface_number);
if (interface_number < 0 || interface_number >= USB_MAXINTERFACES)
return LIBUSB_ERROR_INVALID_PARAM;
if (!dev_handle->dev->attached) if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE; return LIBUSB_ERROR_NO_DEVICE;
if (usbi_backend.detach_kernel_driver) if (usbi_backend.detach_kernel_driver)
return usbi_backend.detach_kernel_driver(dev_handle, interface_number); return usbi_backend.detach_kernel_driver(dev_handle, (uint8_t)interface_number);
else else
return LIBUSB_ERROR_NOT_SUPPORTED; return LIBUSB_ERROR_NOT_SUPPORTED;
} }
@ -2058,11 +2056,14 @@ int API_EXPORTED libusb_attach_kernel_driver(libusb_device_handle *dev_handle,
{ {
usbi_dbg("interface %d", interface_number); usbi_dbg("interface %d", interface_number);
if (interface_number < 0 || interface_number >= USB_MAXINTERFACES)
return LIBUSB_ERROR_INVALID_PARAM;
if (!dev_handle->dev->attached) if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE; return LIBUSB_ERROR_NO_DEVICE;
if (usbi_backend.attach_kernel_driver) if (usbi_backend.attach_kernel_driver)
return usbi_backend.attach_kernel_driver(dev_handle, interface_number); return usbi_backend.attach_kernel_driver(dev_handle, (uint8_t)interface_number);
else else
return LIBUSB_ERROR_NOT_SUPPORTED; return LIBUSB_ERROR_NOT_SUPPORTED;
} }
@ -2106,7 +2107,7 @@ int API_EXPORTED libusb_set_auto_detach_kernel_driver(
void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level) void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level)
{ {
#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING) #if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING)
USBI_GET_CONTEXT(ctx); ctx = usbi_get_context(ctx);
if (!ctx->debug_fixed) { if (!ctx->debug_fixed) {
level = CLAMP(level, LIBUSB_LOG_LEVEL_NONE, LIBUSB_LOG_LEVEL_DEBUG); level = CLAMP(level, LIBUSB_LOG_LEVEL_NONE, LIBUSB_LOG_LEVEL_DEBUG);
ctx->debug = (enum libusb_log_level)level; ctx->debug = (enum libusb_log_level)level;
@ -2141,23 +2142,24 @@ void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level)
void API_EXPORTED libusb_set_log_cb(libusb_context *ctx, libusb_log_cb cb, void API_EXPORTED libusb_set_log_cb(libusb_context *ctx, libusb_log_cb cb,
int mode) int mode)
{ {
#if defined(ENABLE_LOGGING) && (!defined(ENABLE_DEBUG_LOGGING) || !defined(USE_SYSTEM_LOGGING_FACILITY))
#if !defined(USE_SYSTEM_LOGGING_FACILITY) #if !defined(USE_SYSTEM_LOGGING_FACILITY)
if (mode & LIBUSB_LOG_CB_GLOBAL) { if (mode & LIBUSB_LOG_CB_GLOBAL)
log_handler = cb; log_handler = cb;
}
#endif #endif
#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING) #if !defined(ENABLE_DEBUG_LOGGING)
if (mode & LIBUSB_LOG_CB_CONTEXT) { if (mode & LIBUSB_LOG_CB_CONTEXT) {
USBI_GET_CONTEXT(ctx); ctx = usbi_get_context(ctx);
ctx->log_handler = cb; ctx->log_handler = cb;
} }
#else #else
UNUSED(ctx); UNUSED(ctx);
#if defined(USE_SYSTEM_LOGGING_FACILITY) #endif
#else
UNUSED(ctx);
UNUSED(cb); UNUSED(cb);
UNUSED(mode); UNUSED(mode);
#endif #endif
#endif
} }
/** \ingroup libusb_lib /** \ingroup libusb_lib
@ -2178,6 +2180,7 @@ void API_EXPORTED libusb_set_log_cb(libusb_context *ctx, libusb_log_cb cb,
* \returns LIBUSB_ERROR_INVALID_PARAM if the option or arguments are invalid * \returns LIBUSB_ERROR_INVALID_PARAM if the option or arguments are invalid
* \returns LIBUSB_ERROR_NOT_SUPPORTED if the option is valid but not supported * \returns LIBUSB_ERROR_NOT_SUPPORTED if the option is valid but not supported
* on this platform * on this platform
* \returns LIBUSB_ERROR_NOT_FOUND if LIBUSB_OPTION_USE_USBDK is valid on this platform but UsbDk is not available
*/ */
int API_EXPORTED libusb_set_option(libusb_context *ctx, int API_EXPORTED libusb_set_option(libusb_context *ctx,
enum libusb_option option, ...) enum libusb_option option, ...)
@ -2185,7 +2188,7 @@ int API_EXPORTED libusb_set_option(libusb_context *ctx,
int arg, r = LIBUSB_SUCCESS; int arg, r = LIBUSB_SUCCESS;
va_list ap; va_list ap;
USBI_GET_CONTEXT(ctx); ctx = usbi_get_context(ctx);
va_start(ap, option); va_start(ap, option);
switch (option) { switch (option) {
@ -2203,6 +2206,7 @@ int API_EXPORTED libusb_set_option(libusb_context *ctx,
/* Handle all backend-specific options here */ /* Handle all backend-specific options here */
case LIBUSB_OPTION_USE_USBDK: case LIBUSB_OPTION_USE_USBDK:
case LIBUSB_OPTION_WEAK_AUTHORITY:
if (usbi_backend.set_option) if (usbi_backend.set_option)
r = usbi_backend.set_option(ctx, option, ap); r = usbi_backend.set_option(ctx, option, ap);
else else
@ -2260,9 +2264,8 @@ int API_EXPORTED libusb_init(libusb_context **context)
usbi_mutex_static_lock(&default_context_lock); usbi_mutex_static_lock(&default_context_lock);
if (!timestamp_origin.tv_sec) { if (!timestamp_origin.tv_sec)
usbi_backend.clock_gettime(USBI_CLOCK_REALTIME, &timestamp_origin); usbi_get_monotonic_time(&timestamp_origin);
}
if (!context && usbi_default_context) { if (!context && usbi_default_context) {
usbi_dbg("reusing default context"); usbi_dbg("reusing default context");
@ -2271,7 +2274,7 @@ int API_EXPORTED libusb_init(libusb_context **context)
return 0; return 0;
} }
ctx = calloc(1, sizeof(*ctx) + priv_size); ctx = calloc(1, PTR_ALIGN(sizeof(*ctx)) + priv_size);
if (!ctx) { if (!ctx) {
r = LIBUSB_ERROR_NO_MEM; r = LIBUSB_ERROR_NO_MEM;
goto err_unlock; goto err_unlock;
@ -2340,7 +2343,7 @@ err_free_ctx:
usbi_mutex_static_unlock(&active_contexts_lock); usbi_mutex_static_unlock(&active_contexts_lock);
usbi_mutex_lock(&ctx->usb_devs_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); list_del(&dev->list);
libusb_unref_device(dev); libusb_unref_device(dev);
} }
@ -2361,19 +2364,26 @@ err_unlock:
* before your application terminates. * before your application terminates.
* \param ctx the context to deinitialize, or NULL for the default context * \param ctx the context to deinitialize, or NULL for the default context
*/ */
void API_EXPORTED libusb_exit(struct libusb_context *ctx) void API_EXPORTED libusb_exit(libusb_context *ctx)
{ {
struct libusb_device *dev, *next; struct libusb_device *dev, *next;
struct timeval tv = { 0, 0 }; struct timeval tv = { 0, 0 };
int destroying_default_context = 0; int destroying_default_context = 0;
usbi_dbg(" "); usbi_dbg(" ");
USBI_GET_CONTEXT(ctx);
ctx = usbi_get_context(ctx);
/* if working with default context, only actually do the deinitialization /* if working with default context, only actually do the deinitialization
* if we're the last user */ * if we're the last user */
usbi_mutex_static_lock(&default_context_lock); usbi_mutex_static_lock(&default_context_lock);
if (ctx == usbi_default_context) { if (ctx == usbi_default_context) {
if (!usbi_default_context) {
usbi_dbg("no default context, not initialized?");
usbi_mutex_static_unlock(&default_context_lock);
return;
}
if (--default_context_refcnt > 0) { if (--default_context_refcnt > 0) {
usbi_dbg("not destroying default context"); usbi_dbg("not destroying default context");
usbi_mutex_static_unlock(&default_context_lock); usbi_mutex_static_unlock(&default_context_lock);
@ -2389,7 +2399,7 @@ void API_EXPORTED libusb_exit(struct libusb_context *ctx)
*/ */
destroying_default_context = 1; destroying_default_context = 1;
} else { } else {
// Unlock default context, as we're not modifying it. /* Unlock default context, as we're not modifying it. */
usbi_mutex_static_unlock(&default_context_lock); usbi_mutex_static_unlock(&default_context_lock);
} }
@ -2413,7 +2423,7 @@ void API_EXPORTED libusb_exit(struct libusb_context *ctx)
libusb_handle_events_timeout(ctx, &tv); libusb_handle_events_timeout(ctx, &tv);
usbi_mutex_lock(&ctx->usb_devs_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); list_del(&dev->list);
libusb_unref_device(dev); libusb_unref_device(dev);
} }
@ -2471,94 +2481,90 @@ int API_EXPORTED libusb_has_capability(uint32_t capability)
#ifdef LIBUSB_PRINTF_WIN32 #ifdef LIBUSB_PRINTF_WIN32
/* /*
* Prior to VS2015, Microsoft did not provide the snprintf() function and * 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 * Microsoft did provide a _snprintf() function, but again it did not
* guarantee NULL-terminated output. * guarantee NULL-terminated output.
* *
* The below implementations guarantee NULL-terminated output and are * The below implementations guarantee NUL-terminated output and are
* C99 compliant. * C99 compliant.
*/ */
int usbi_snprintf(char *str, size_t size, const char *format, ...) int usbi_snprintf(char *str, size_t size, const char *format, ...)
{ {
va_list ap; va_list args;
int ret; int ret;
va_start(ap, format); va_start(args, format);
ret = usbi_vsnprintf(str, size, format, ap); ret = usbi_vsnprintf(str, size, format, args);
va_end(ap); va_end(args);
return ret; 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; int ret;
ret = _vsnprintf(str, size, format, ap); ret = _vsnprintf(str, size, format, args);
if (ret < 0 || ret == (int)size) { 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. */ * determine how many characters would have been written. */
str[size - 1] = '\0'; str[size - 1] = '\0';
if (ret < 0) if (ret < 0)
ret = _vsnprintf(NULL, 0, format, ap); ret = _vsnprintf(NULL, 0, format, args);
} }
return ret; return ret;
} }
#endif /* LIBUSB_PRINTF_WIN32 */ #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(USE_SYSTEM_LOGGING_FACILITY)
#if defined(OS_WINDOWS) || defined(OS_WINCE) #if defined(__ANDROID__)
#if !defined(UNICODE) int priority;
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;
switch (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: priority = ANDROID_LOG_ERROR; break; case LIBUSB_LOG_LEVEL_ERROR: priority = ANDROID_LOG_ERROR; break;
case LIBUSB_LOG_LEVEL_WARNING: priority = ANDROID_LOG_WARN; 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_INFO: priority = ANDROID_LOG_INFO; break;
case LIBUSB_LOG_LEVEL_DEBUG: priority = ANDROID_LOG_DEBUG; break; case LIBUSB_LOG_LEVEL_DEBUG: priority = ANDROID_LOG_DEBUG; break;
default: priority = ANDROID_LOG_UNKNOWN;
} }
__android_log_write(priority, "libusb", str); __android_log_write(priority, "libusb", str);
#elif defined(HAVE_SYSLOG_FUNC) #elif defined(_WIN32)
int syslog_level = LOG_INFO; UNUSED(level);
OutputDebugStringA(str);
#elif defined(HAVE_SYSLOG)
int syslog_level;
switch (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_ERROR: syslog_level = LOG_ERR; break;
case LIBUSB_LOG_LEVEL_WARNING: syslog_level = LOG_WARNING; 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_INFO: syslog_level = LOG_INFO; break;
case LIBUSB_LOG_LEVEL_DEBUG: syslog_level = LOG_DEBUG; break; case LIBUSB_LOG_LEVEL_DEBUG: syslog_level = LOG_DEBUG; break;
default: syslog_level = LOG_INFO;
} }
syslog(syslog_level, "%s", str); syslog(syslog_level, "%s", str);
#else /* All of gcc, Clang, Xcode seem to use #warning */ #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. #warning System logging is not supported on this platform. Logging to stderr will be used instead.
UNUSED(level);
fputs(str, stderr); fputs(str, stderr);
#endif #endif
#else #else
/* Global log handler */ /* Global log handler */
if (log_handler != NULL) if (log_handler)
log_handler(NULL, level, str); log_handler(NULL, level, str);
else else
fputs(str, stderr); fputs(str, stderr);
#endif /* USE_SYSTEM_LOGGING_FACILITY */ #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 *function, const char *format, va_list args)
{ {
const char *prefix; const char *prefix;
char buf[USBI_MAX_LOG_LEN]; char buf[USBI_MAX_LOG_LEN];
struct timespec now;
int global_debug, header_len, text_len; int global_debug, header_len, text_len;
static int has_debug_header_been_displayed = 0; static int has_debug_header_been_displayed = 0;
@ -2566,41 +2572,22 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
global_debug = 1; global_debug = 1;
UNUSED(ctx); UNUSED(ctx);
#else #else
enum libusb_log_level ctx_level = LIBUSB_LOG_LEVEL_NONE; enum libusb_log_level ctx_level;
USBI_GET_CONTEXT(ctx); ctx = usbi_get_context(ctx);
if (ctx) if (ctx)
ctx_level = ctx->debug; ctx_level = ctx->debug;
else else
ctx_level = get_env_debug_level(); ctx_level = get_env_debug_level();
if (ctx_level == LIBUSB_LOG_LEVEL_NONE) if (ctx_level < level)
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)
return; return;
global_debug = (ctx_level == LIBUSB_LOG_LEVEL_DEBUG); global_debug = (ctx_level == LIBUSB_LOG_LEVEL_DEBUG);
#endif #endif
usbi_backend.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) { switch (level) {
case LIBUSB_LOG_LEVEL_NONE: case LIBUSB_LOG_LEVEL_NONE: /* Impossible, but keeps compiler happy */
return; return;
case LIBUSB_LOG_LEVEL_ERROR: case LIBUSB_LOG_LEVEL_ERROR:
prefix = "error"; prefix = "error";
@ -2620,21 +2607,31 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
} }
if (global_debug) { 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), header_len = snprintf(buf, sizeof(buf),
"[%2ld.%06ld] [%08x] libusb: %s [%s] ", "[%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 { } else {
header_len = snprintf(buf, sizeof(buf), header_len = snprintf(buf, sizeof(buf),
"libusb: %s [%s] ", prefix, function); "libusb: %s [%s] ", prefix, function);
} }
if (header_len < 0 || header_len >= (int)sizeof(buf)) { 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. */ * remove the header so something useful is output. */
header_len = 0; 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, text_len = vsnprintf(buf + header_len, sizeof(buf) - (size_t)header_len,
format, args); format, args);
if (text_len < 0 || text_len + header_len >= (int)sizeof(buf)) { if (text_len < 0 || text_len + header_len >= (int)sizeof(buf)) {
@ -2648,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); 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 #ifndef ENABLE_DEBUG_LOGGING
if (ctx && ctx->log_handler) if (ctx && ctx->log_handler)
ctx->log_handler(ctx, level, buf); ctx->log_handler(ctx, level, buf);
@ -2663,7 +2660,7 @@ void usbi_log(struct libusb_context *ctx, enum libusb_log_level level,
va_list args; va_list args;
va_start(args, format); va_start(args, format);
usbi_log_v(ctx, level, function, format, args); log_v(ctx, level, function, format, args);
va_end(args); va_end(args);
} }

File diff suppressed because it is too large Load diff

View file

@ -19,17 +19,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <assert.h>
#include "libusbi.h" #include "libusbi.h"
#include "hotplug.h" #include "hotplug.h"
@ -61,8 +50,8 @@
* expecting additional events. Returning 0 will rearm the callback and 1 will cause * 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 * the callback to be deregistered. Note that when callbacks are called from
* libusb_hotplug_register_callback() because of the \ref LIBUSB_HOTPLUG_ENUMERATE * libusb_hotplug_register_callback() because of the \ref LIBUSB_HOTPLUG_ENUMERATE
* flag, the callback return value is ignored, iow you cannot cause a callback * flag, the callback return value is ignored. In other words, you cannot cause a
* to be deregistered by returning 1 when it is called from * callback to be deregistered by returning 1 when it is called from
* libusb_hotplug_register_callback(). * libusb_hotplug_register_callback().
* *
* Callbacks for a particular context are automatically deregistered by libusb_exit(). * Callbacks for a particular context are automatically deregistered by libusb_exit().
@ -154,6 +143,13 @@ int main (void) {
\endcode \endcode
*/ */
#define VALID_HOTPLUG_EVENTS \
(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | \
LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
#define VALID_HOTPLUG_FLAGS \
(LIBUSB_HOTPLUG_ENUMERATE)
static int usbi_hotplug_match_cb(struct libusb_context *ctx, static int usbi_hotplug_match_cb(struct libusb_context *ctx,
struct libusb_device *dev, libusb_hotplug_event event, struct libusb_device *dev, libusb_hotplug_event event,
struct libusb_hotplug_callback *hotplug_cb) struct libusb_hotplug_callback *hotplug_cb)
@ -188,7 +184,7 @@ void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
usbi_mutex_lock(&ctx->hotplug_cbs_lock); 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) { if (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE) {
/* process deregistration in usbi_hotplug_deregister() */ /* process deregistration in usbi_hotplug_deregister() */
continue; continue;
@ -210,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, void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev,
libusb_hotplug_event event) libusb_hotplug_event event)
{ {
int pending_events;
struct libusb_hotplug_message *message = calloc(1, sizeof(*message)); struct libusb_hotplug_message *message = calloc(1, sizeof(*message));
unsigned int event_flags;
if (!message) { if (!message) {
usbi_err(ctx, "error allocating hotplug message"); usbi_err(ctx, "error allocating hotplug message");
@ -224,15 +220,16 @@ void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device
/* Take the event data lock and add this message to the list. /* Take the event data lock and add this message to the list.
* Only signal an event if there are no prior pending events. */ * Only signal an event if there are no prior pending events. */
usbi_mutex_lock(&ctx->event_data_lock); 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); list_add_tail(&message->list, &ctx->hotplug_msgs);
if (!pending_events) if (!event_flags)
usbi_signal_event(ctx); usbi_signal_event(&ctx->event);
usbi_mutex_unlock(&ctx->event_data_lock); usbi_mutex_unlock(&ctx->event_data_lock);
} }
int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx, int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
libusb_hotplug_event events, libusb_hotplug_flag flags, int events, int flags,
int vendor_id, int product_id, int dev_class, int vendor_id, int product_id, int dev_class,
libusb_hotplug_callback_fn cb_fn, void *user_data, libusb_hotplug_callback_fn cb_fn, void *user_data,
libusb_hotplug_callback_handle *callback_handle) libusb_hotplug_callback_handle *callback_handle)
@ -240,8 +237,8 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
struct libusb_hotplug_callback *new_callback; struct libusb_hotplug_callback *new_callback;
/* check for sane values */ /* check for sane values */
if ((!events || (~(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) & events)) || if ((!events || (~VALID_HOTPLUG_EVENTS & events)) ||
(flags && (~LIBUSB_HOTPLUG_ENUMERATE & flags)) || (~VALID_HOTPLUG_FLAGS & flags) ||
(LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) || (LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) ||
(LIBUSB_HOTPLUG_MATCH_ANY != product_id && (~0xffff & product_id)) || (LIBUSB_HOTPLUG_MATCH_ANY != product_id && (~0xffff & product_id)) ||
(LIBUSB_HOTPLUG_MATCH_ANY != dev_class && (~0xff & dev_class)) || (LIBUSB_HOTPLUG_MATCH_ANY != dev_class && (~0xff & dev_class)) ||
@ -254,7 +251,7 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
return LIBUSB_ERROR_NOT_SUPPORTED; return LIBUSB_ERROR_NOT_SUPPORTED;
} }
USBI_GET_CONTEXT(ctx); ctx = usbi_get_context(ctx);
new_callback = calloc(1, sizeof(*new_callback)); new_callback = calloc(1, sizeof(*new_callback));
if (!new_callback) { if (!new_callback) {
@ -319,7 +316,7 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
void API_EXPORTED libusb_hotplug_deregister_callback(struct libusb_context *ctx, void API_EXPORTED libusb_hotplug_deregister_callback(libusb_context *ctx,
libusb_hotplug_callback_handle callback_handle) libusb_hotplug_callback_handle callback_handle)
{ {
struct libusb_hotplug_callback *hotplug_cb; struct libusb_hotplug_callback *hotplug_cb;
@ -330,12 +327,12 @@ void API_EXPORTED libusb_hotplug_deregister_callback(struct libusb_context *ctx,
return; return;
} }
USBI_GET_CONTEXT(ctx);
usbi_dbg("deregister hotplug cb %d", callback_handle); usbi_dbg("deregister hotplug cb %d", callback_handle);
ctx = usbi_get_context(ctx);
usbi_mutex_lock(&ctx->hotplug_cbs_lock); 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) { if (callback_handle == hotplug_cb->handle) {
/* Mark this callback for deregistration */ /* Mark this callback for deregistration */
hotplug_cb->flags |= USBI_HOTPLUG_NEEDS_FREE; hotplug_cb->flags |= USBI_HOTPLUG_NEEDS_FREE;
@ -345,23 +342,50 @@ void API_EXPORTED libusb_hotplug_deregister_callback(struct libusb_context *ctx,
usbi_mutex_unlock(&ctx->hotplug_cbs_lock); usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
if (deregistered) { if (deregistered) {
int pending_events; unsigned int event_flags;
usbi_mutex_lock(&ctx->event_data_lock); 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; ctx->event_flags |= USBI_EVENT_HOTPLUG_CB_DEREGISTERED;
if (!pending_events) if (!event_flags)
usbi_signal_event(ctx); usbi_signal_event(&ctx->event);
usbi_mutex_unlock(&ctx->event_data_lock); usbi_mutex_unlock(&ctx->event_data_lock);
} }
} }
DEFAULT_VISIBILITY
void * LIBUSB_CALL libusb_hotplug_get_user_data(libusb_context *ctx,
libusb_hotplug_callback_handle callback_handle)
{
struct libusb_hotplug_callback *hotplug_cb;
void *user_data = NULL;
/* check for hotplug support */
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
return NULL;
}
usbi_dbg("get hotplug user data %d", callback_handle);
ctx = usbi_get_context(ctx);
usbi_mutex_lock(&ctx->hotplug_cbs_lock);
for_each_hotplug_cb(ctx, hotplug_cb) {
if (callback_handle == hotplug_cb->handle) {
user_data = hotplug_cb->user_data;
}
}
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
return user_data;
}
void usbi_hotplug_deregister(struct libusb_context *ctx, int forced) void usbi_hotplug_deregister(struct libusb_context *ctx, int forced)
{ {
struct libusb_hotplug_callback *hotplug_cb, *next; struct libusb_hotplug_callback *hotplug_cb, *next;
usbi_mutex_lock(&ctx->hotplug_cbs_lock); 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)) { if (forced || (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE)) {
usbi_dbg("freeing hotplug cb %p with handle %d", hotplug_cb, usbi_dbg("freeing hotplug cb %p with handle %d", hotplug_cb,
hotplug_cb->handle); hotplug_cb->handle);

View file

@ -90,6 +90,12 @@ struct libusb_hotplug_message {
struct list_head list; 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_deregister(struct libusb_context *ctx, int forced);
void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev, void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
libusb_hotplug_event event); libusb_hotplug_event event);

File diff suppressed because it is too large Load diff

View file

@ -116,6 +116,8 @@ EXPORTS
libusb_has_capability@4 = libusb_has_capability libusb_has_capability@4 = libusb_has_capability
libusb_hotplug_deregister_callback libusb_hotplug_deregister_callback
libusb_hotplug_deregister_callback@8 = libusb_hotplug_deregister_callback libusb_hotplug_deregister_callback@8 = libusb_hotplug_deregister_callback
libusb_hotplug_get_user_data
libusb_hotplug_get_user_data@8 = libusb_hotplug_get_user_data
libusb_hotplug_register_callback libusb_hotplug_register_callback
libusb_hotplug_register_callback@36 = libusb_hotplug_register_callback libusb_hotplug_register_callback@36 = libusb_hotplug_register_callback
libusb_init libusb_init
@ -176,3 +178,5 @@ EXPORTS
libusb_unref_device@4 = libusb_unref_device libusb_unref_device@4 = libusb_unref_device
libusb_wait_for_event libusb_wait_for_event
libusb_wait_for_event@8 = 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

View file

@ -1,27 +1,19 @@
/* /*
* 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 * .res file. This is then embedded in the resultant library (like any other
* compilation object). * compilation object).
* The information can then be queried using standard APIs and can also be * The information can then be queried using standard APIs and can also be
* viewed with utilities such as Windows Explorer. * viewed with utilities such as Windows Explorer.
*/ */
#ifndef _WIN32_WCE
#include "winresrc.h" #include "winresrc.h"
#endif
#include "version.h" #include "version.h"
#ifndef LIBUSB_VERSIONSTRING #ifndef LIBUSB_VERSIONSTRING
#define LU_STR(s) #s #define LU_STR(s) #s
#define LU_XSTR(s) LU_STR(s) #define LU_XSTR(s) LU_STR(s)
#if LIBUSB_NANO > 0
#define LIBUSB_VERSIONSTRING \ #define LIBUSB_VERSIONSTRING \
LU_XSTR(LIBUSB_MAJOR) "." LU_XSTR(LIBUSB_MINOR) "." \ LU_XSTR(LIBUSB_MAJOR) "." LU_XSTR(LIBUSB_MINOR) "." \
LU_XSTR(LIBUSB_MICRO) "." LU_XSTR(LIBUSB_NANO) LIBUSB_RC "\0" LU_XSTR(LIBUSB_MICRO) "." LU_XSTR(LIBUSB_NANO) LIBUSB_RC "\0"
#else
#define LIBUSB_VERSIONSTRING \
LU_XSTR(LIBUSB_MAJOR) "." LU_XSTR(LIBUSB_MINOR) "." \
LU_XSTR(LIBUSB_MICRO) LIBUSB_RC "\0"
#endif
#endif #endif
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO

View file

@ -4,6 +4,7 @@
* Copyright © 2007-2008 Daniel Drake <dsd@gentoo.org> * Copyright © 2007-2008 Daniel Drake <dsd@gentoo.org>
* Copyright © 2012 Pete Batard <pete@akeo.ie> * Copyright © 2012 Pete Batard <pete@akeo.ie>
* Copyright © 2012-2018 Nathan Hjelm <hjelmn@cs.unm.edu> * Copyright © 2012-2018 Nathan Hjelm <hjelmn@cs.unm.edu>
* Copyright © 2014-2020 Chris Dickens <christopher.a.dickens@gmail.com>
* For more information, please visit: http://libusb.info * For more information, please visit: http://libusb.info
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
@ -24,55 +25,36 @@
#ifndef LIBUSB_H #ifndef LIBUSB_H
#define LIBUSB_H #define LIBUSB_H
#ifdef _MSC_VER #if defined(_MSC_VER)
/* on MS environments, the inline keyword is available in C++ only */ /* on MS environments, the inline keyword is available in C++ only */
#if !defined(__cplusplus) #if !defined(__cplusplus)
#define inline __inline #define inline __inline
#endif #endif
/* ssize_t is also not available (copy/paste from MinGW) */ /* ssize_t is also not available */
#ifndef _SSIZE_T_DEFINED #include <basetsd.h>
#define _SSIZE_T_DEFINED typedef SSIZE_T ssize_t;
#undef ssize_t
#ifdef _WIN64
typedef __int64 ssize_t;
#else
typedef int ssize_t;
#endif /* _WIN64 */
#endif /* _SSIZE_T_DEFINED */
#endif /* _MSC_VER */ #endif /* _MSC_VER */
/* stdint.h is not available on older MSVC */ #include <limits.h>
#if defined(_MSC_VER) && (_MSC_VER < 1600) && (!defined(_STDINT)) && (!defined(_STDINT_H))
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
#else
#include <stdint.h> #include <stdint.h>
#endif
#if !defined(_WIN32_WCE)
#include <sys/types.h> #include <sys/types.h>
#endif #if !defined(_MSC_VER)
#if defined(__linux__) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__HAIKU__)
#include <sys/time.h> #include <sys/time.h>
#endif #endif
#include <time.h> #include <time.h>
#include <limits.h>
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
#define ZERO_SIZED_ARRAY /* [] - valid C99 code */ #define ZERO_SIZED_ARRAY /* [] - valid C99 code */
#else #else
#define ZERO_SIZED_ARRAY 0 /* [0] - non-standard, but usually working code */ #define ZERO_SIZED_ARRAY 0 /* [0] - non-standard, but usually working code */
#endif #endif /* __STDC_VERSION__ */
/* 'interface' might be defined as a macro on Windows, so we need to /* 'interface' might be defined as a macro on Windows, so we need to
* undefine it so as not to break the current libusb API, because * undefine it so as not to break the current libusb API, because
* libusb_config_descriptor has an 'interface' member * libusb_config_descriptor has an 'interface' member
* As this can be problematic if you include windows.h after libusb.h * As this can be problematic if you include windows.h after libusb.h
* in your sources, we force windows.h to be included first. */ * in your sources, we force windows.h to be included first. */
#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) #if defined(_WIN32) || defined(__CYGWIN__)
#include <windows.h> #include <windows.h>
#if defined(interface) #if defined(interface)
#undef interface #undef interface
@ -80,17 +62,22 @@ typedef unsigned __int32 uint32_t;
#if !defined(__CYGWIN__) #if !defined(__CYGWIN__)
#include <winsock.h> #include <winsock.h>
#endif #endif
#endif #endif /* _WIN32 || __CYGWIN__ */
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
#define LIBUSB_DEPRECATED_FOR(f) \ #define LIBUSB_DEPRECATED_FOR(f) __attribute__ ((deprecated ("Use " #f " instead")))
__attribute__((deprecated("Use " #f " instead"))) #elif defined(__GNUC__) && (__GNUC__ >= 3)
#elif __GNUC__ >= 3
#define LIBUSB_DEPRECATED_FOR(f) __attribute__ ((deprecated)) #define LIBUSB_DEPRECATED_FOR(f) __attribute__ ((deprecated))
#else #else
#define LIBUSB_DEPRECATED_FOR(f) #define LIBUSB_DEPRECATED_FOR(f)
#endif /* __GNUC__ */ #endif /* __GNUC__ */
#if defined(__GNUC__)
#define LIBUSB_PACKED __attribute__ ((packed))
#else
#define LIBUSB_PACKED
#endif /* __GNUC__ */
/** \def LIBUSB_CALL /** \def LIBUSB_CALL
* \ingroup libusb_misc * \ingroup libusb_misc
* libusb's Windows calling convention. * libusb's Windows calling convention.
@ -123,11 +110,11 @@ typedef unsigned __int32 uint32_t;
* return type, before the function name. See internal documentation for * return type, before the function name. See internal documentation for
* API_EXPORTED. * API_EXPORTED.
*/ */
#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) #if defined(_WIN32) || defined(__CYGWIN__)
#define LIBUSB_CALL WINAPI #define LIBUSB_CALL WINAPI
#else #else
#define LIBUSB_CALL #define LIBUSB_CALL
#endif #endif /* _WIN32 || __CYGWIN__ */
/** \def LIBUSB_API_VERSION /** \def LIBUSB_API_VERSION
* \ingroup libusb_misc * \ingroup libusb_misc
@ -149,12 +136,12 @@ typedef unsigned __int32 uint32_t;
* Internally, LIBUSB_API_VERSION is defined as follows: * Internally, LIBUSB_API_VERSION is defined as follows:
* (libusb major << 24) | (libusb minor << 16) | (16 bit incremental) * (libusb major << 24) | (libusb minor << 16) | (16 bit incremental)
*/ */
#define LIBUSB_API_VERSION 0x01000107 #define LIBUSB_API_VERSION 0x01000108
/* The following is kept for compatibility, but will be deprecated in the future */ /* The following is kept for compatibility, but will be deprecated in the future */
#define LIBUSBX_API_VERSION LIBUSB_API_VERSION #define LIBUSBX_API_VERSION LIBUSB_API_VERSION
#ifdef __cplusplus #if defined(__cplusplus)
extern "C" { extern "C" {
#endif #endif
@ -196,35 +183,35 @@ enum libusb_class_code {
* this bDeviceClass value indicates that each interface specifies its * this bDeviceClass value indicates that each interface specifies its
* own class information and all interfaces operate independently. * own class information and all interfaces operate independently.
*/ */
LIBUSB_CLASS_PER_INTERFACE = 0, LIBUSB_CLASS_PER_INTERFACE = 0x00,
/** Audio class */ /** Audio class */
LIBUSB_CLASS_AUDIO = 1, LIBUSB_CLASS_AUDIO = 0x01,
/** Communications class */ /** Communications class */
LIBUSB_CLASS_COMM = 2, LIBUSB_CLASS_COMM = 0x02,
/** Human Interface Device class */ /** Human Interface Device class */
LIBUSB_CLASS_HID = 3, LIBUSB_CLASS_HID = 0x03,
/** Physical */ /** Physical */
LIBUSB_CLASS_PHYSICAL = 5, LIBUSB_CLASS_PHYSICAL = 0x05,
/** Printer class */
LIBUSB_CLASS_PRINTER = 7,
/** Image class */ /** Image class */
LIBUSB_CLASS_PTP = 6, /* legacy name from libusb-0.1 usb.h */ LIBUSB_CLASS_IMAGE = 0x06,
LIBUSB_CLASS_IMAGE = 6, LIBUSB_CLASS_PTP = 0x06, /* legacy name from libusb-0.1 usb.h */
/** Printer class */
LIBUSB_CLASS_PRINTER = 0x07,
/** Mass storage class */ /** Mass storage class */
LIBUSB_CLASS_MASS_STORAGE = 8, LIBUSB_CLASS_MASS_STORAGE = 0x08,
/** Hub class */ /** Hub class */
LIBUSB_CLASS_HUB = 9, LIBUSB_CLASS_HUB = 0x09,
/** Data class */ /** Data class */
LIBUSB_CLASS_DATA = 10, LIBUSB_CLASS_DATA = 0x0a,
/** Smart Card */ /** Smart Card */
LIBUSB_CLASS_SMART_CARD = 0x0b, LIBUSB_CLASS_SMART_CARD = 0x0b,
@ -244,6 +231,9 @@ enum libusb_class_code {
/** Wireless class */ /** Wireless class */
LIBUSB_CLASS_WIRELESS = 0xe0, LIBUSB_CLASS_WIRELESS = 0xe0,
/** Miscellaneous class */
LIBUSB_CLASS_MISCELLANEOUS = 0xef,
/** Application class */ /** Application class */
LIBUSB_CLASS_APPLICATION = 0xfe, LIBUSB_CLASS_APPLICATION = 0xfe,
@ -311,10 +301,11 @@ enum libusb_descriptor_type {
#define LIBUSB_BT_CONTAINER_ID_SIZE 20 #define LIBUSB_BT_CONTAINER_ID_SIZE 20
/* We unwrap the BOS => define its max size */ /* We unwrap the BOS => define its max size */
#define LIBUSB_DT_BOS_MAX_SIZE ((LIBUSB_DT_BOS_SIZE) +\ #define LIBUSB_DT_BOS_MAX_SIZE \
(LIBUSB_BT_USB_2_0_EXTENSION_SIZE) +\ (LIBUSB_DT_BOS_SIZE + \
(LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) +\ LIBUSB_BT_USB_2_0_EXTENSION_SIZE + \
(LIBUSB_BT_CONTAINER_ID_SIZE)) LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE + \
LIBUSB_BT_CONTAINER_ID_SIZE)
#define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */ #define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */
#define LIBUSB_ENDPOINT_DIR_MASK 0x80 #define LIBUSB_ENDPOINT_DIR_MASK 0x80
@ -324,11 +315,11 @@ enum libusb_descriptor_type {
* \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme. * \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme.
*/ */
enum libusb_endpoint_direction { enum libusb_endpoint_direction {
/** In: device-to-host */
LIBUSB_ENDPOINT_IN = 0x80,
/** Out: host-to-device */ /** Out: host-to-device */
LIBUSB_ENDPOINT_OUT = 0x00 LIBUSB_ENDPOINT_OUT = 0x00,
/** In: device-to-host */
LIBUSB_ENDPOINT_IN = 0x80
}; };
#define LIBUSB_TRANSFER_TYPE_MASK 0x03 /* in bmAttributes */ #define LIBUSB_TRANSFER_TYPE_MASK 0x03 /* in bmAttributes */
@ -337,21 +328,18 @@ enum libusb_endpoint_direction {
* Endpoint transfer type. Values for bits 0:1 of the * Endpoint transfer type. Values for bits 0:1 of the
* \ref libusb_endpoint_descriptor::bmAttributes "endpoint attributes" field. * \ref libusb_endpoint_descriptor::bmAttributes "endpoint attributes" field.
*/ */
enum libusb_transfer_type { enum libusb_endpoint_transfer_type {
/** Control endpoint */ /** Control endpoint */
LIBUSB_TRANSFER_TYPE_CONTROL = 0, LIBUSB_ENDPOINT_TRANSFER_TYPE_CONTROL = 0x0,
/** Isochronous endpoint */ /** Isochronous endpoint */
LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1, LIBUSB_ENDPOINT_TRANSFER_TYPE_ISOCHRONOUS = 0x1,
/** Bulk endpoint */ /** Bulk endpoint */
LIBUSB_TRANSFER_TYPE_BULK = 2, LIBUSB_ENDPOINT_TRANSFER_TYPE_BULK = 0x2,
/** Interrupt endpoint */ /** Interrupt endpoint */
LIBUSB_TRANSFER_TYPE_INTERRUPT = 3, LIBUSB_ENDPOINT_TRANSFER_TYPE_INTERRUPT = 0x3
/** Stream endpoint */
LIBUSB_TRANSFER_TYPE_BULK_STREAM = 4,
}; };
/** \ingroup libusb_misc /** \ingroup libusb_misc
@ -386,20 +374,20 @@ enum libusb_standard_request {
LIBUSB_REQUEST_SET_CONFIGURATION = 0x09, LIBUSB_REQUEST_SET_CONFIGURATION = 0x09,
/** Return the selected alternate setting for the specified interface */ /** Return the selected alternate setting for the specified interface */
LIBUSB_REQUEST_GET_INTERFACE = 0x0A, LIBUSB_REQUEST_GET_INTERFACE = 0x0a,
/** Select an alternate interface for the specified interface */ /** Select an alternate interface for the specified interface */
LIBUSB_REQUEST_SET_INTERFACE = 0x0B, LIBUSB_REQUEST_SET_INTERFACE = 0x0b,
/** Set then report an endpoint's synchronization frame */ /** Set then report an endpoint's synchronization frame */
LIBUSB_REQUEST_SYNCH_FRAME = 0x0C, LIBUSB_REQUEST_SYNCH_FRAME = 0x0c,
/** Sets both the U1 and U2 Exit Latency */ /** Sets both the U1 and U2 Exit Latency */
LIBUSB_REQUEST_SET_SEL = 0x30, LIBUSB_REQUEST_SET_SEL = 0x30,
/** Delay from the time a host transmits a packet to the time it is /** Delay from the time a host transmits a packet to the time it is
* received by the device. */ * received by the device. */
LIBUSB_SET_ISOCH_DELAY = 0x31, LIBUSB_SET_ISOCH_DELAY = 0x31
}; };
/** \ingroup libusb_misc /** \ingroup libusb_misc
@ -435,10 +423,10 @@ enum libusb_request_recipient {
LIBUSB_RECIPIENT_ENDPOINT = 0x02, LIBUSB_RECIPIENT_ENDPOINT = 0x02,
/** Other */ /** Other */
LIBUSB_RECIPIENT_OTHER = 0x03, LIBUSB_RECIPIENT_OTHER = 0x03
}; };
#define LIBUSB_ISO_SYNC_TYPE_MASK 0x0C #define LIBUSB_ISO_SYNC_TYPE_MASK 0x0c
/** \ingroup libusb_desc /** \ingroup libusb_desc
* Synchronization type for isochronous endpoints. Values for bits 2:3 of the * Synchronization type for isochronous endpoints. Values for bits 2:3 of the
@ -447,16 +435,16 @@ enum libusb_request_recipient {
*/ */
enum libusb_iso_sync_type { enum libusb_iso_sync_type {
/** No synchronization */ /** No synchronization */
LIBUSB_ISO_SYNC_TYPE_NONE = 0, LIBUSB_ISO_SYNC_TYPE_NONE = 0x0,
/** Asynchronous */ /** Asynchronous */
LIBUSB_ISO_SYNC_TYPE_ASYNC = 1, LIBUSB_ISO_SYNC_TYPE_ASYNC = 0x1,
/** Adaptive */ /** Adaptive */
LIBUSB_ISO_SYNC_TYPE_ADAPTIVE = 2, LIBUSB_ISO_SYNC_TYPE_ADAPTIVE = 0x2,
/** Synchronous */ /** Synchronous */
LIBUSB_ISO_SYNC_TYPE_SYNC = 3 LIBUSB_ISO_SYNC_TYPE_SYNC = 0x3
}; };
#define LIBUSB_ISO_USAGE_TYPE_MASK 0x30 #define LIBUSB_ISO_USAGE_TYPE_MASK 0x30
@ -468,13 +456,68 @@ enum libusb_iso_sync_type {
*/ */
enum libusb_iso_usage_type { enum libusb_iso_usage_type {
/** Data endpoint */ /** Data endpoint */
LIBUSB_ISO_USAGE_TYPE_DATA = 0, LIBUSB_ISO_USAGE_TYPE_DATA = 0x0,
/** Feedback endpoint */ /** Feedback endpoint */
LIBUSB_ISO_USAGE_TYPE_FEEDBACK = 1, LIBUSB_ISO_USAGE_TYPE_FEEDBACK = 0x1,
/** Implicit feedback Data endpoint */ /** Implicit feedback Data endpoint */
LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 2, LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 0x2
};
/** \ingroup libusb_desc
* Supported speeds (wSpeedSupported) bitfield. Indicates what
* speeds the device supports.
*/
enum libusb_supported_speed {
/** Low speed operation supported (1.5MBit/s). */
LIBUSB_LOW_SPEED_OPERATION = (1 << 0),
/** Full speed operation supported (12MBit/s). */
LIBUSB_FULL_SPEED_OPERATION = (1 << 1),
/** High speed operation supported (480MBit/s). */
LIBUSB_HIGH_SPEED_OPERATION = (1 << 2),
/** Superspeed operation supported (5000MBit/s). */
LIBUSB_SUPER_SPEED_OPERATION = (1 << 3)
};
/** \ingroup libusb_desc
* Masks for the bits of the
* \ref libusb_usb_2_0_extension_descriptor::bmAttributes "bmAttributes" field
* of the USB 2.0 Extension descriptor.
*/
enum libusb_usb_2_0_extension_attributes {
/** Supports Link Power Management (LPM) */
LIBUSB_BM_LPM_SUPPORT = (1 << 1)
};
/** \ingroup libusb_desc
* Masks for the bits of the
* \ref libusb_ss_usb_device_capability_descriptor::bmAttributes "bmAttributes" field
* field of the SuperSpeed USB Device Capability descriptor.
*/
enum libusb_ss_usb_device_capability_attributes {
/** Supports Latency Tolerance Messages (LTM) */
LIBUSB_BM_LTM_SUPPORT = (1 << 1)
};
/** \ingroup libusb_desc
* USB capability types
*/
enum libusb_bos_type {
/** Wireless USB device capability */
LIBUSB_BT_WIRELESS_USB_DEVICE_CAPABILITY = 0x01,
/** USB 2.0 extensions */
LIBUSB_BT_USB_2_0_EXTENSION = 0x02,
/** SuperSpeed USB device capability */
LIBUSB_BT_SS_USB_DEVICE_CAPABILITY = 0x03,
/** Container ID type */
LIBUSB_BT_CONTAINER_ID = 0x04
}; };
/** \ingroup libusb_desc /** \ingroup libusb_desc
@ -547,17 +590,15 @@ struct libusb_endpoint_descriptor {
/** The address of the endpoint described by this descriptor. Bits 0:3 are /** The address of the endpoint described by this descriptor. Bits 0:3 are
* the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction, * the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction,
* see \ref libusb_endpoint_direction. * see \ref libusb_endpoint_direction. */
*/
uint8_t bEndpointAddress; uint8_t bEndpointAddress;
/** Attributes which apply to the endpoint when it is configured using /** Attributes which apply to the endpoint when it is configured using
* the bConfigurationValue. Bits 0:1 determine the transfer type and * the bConfigurationValue. Bits 0:1 determine the transfer type and
* correspond to \ref libusb_transfer_type. Bits 2:3 are only used for * correspond to \ref libusb_endpoint_transfer_type. Bits 2:3 are only used
* isochronous endpoints and correspond to \ref libusb_iso_sync_type. * for isochronous endpoints and correspond to \ref libusb_iso_sync_type.
* Bits 4:5 are also only used for isochronous endpoints and correspond to * Bits 4:5 are also only used for isochronous endpoints and correspond to
* \ref libusb_iso_usage_type. Bits 6:7 are reserved. * \ref libusb_iso_usage_type. Bits 6:7 are reserved. */
*/
uint8_t bmAttributes; uint8_t bmAttributes;
/** Maximum packet size this endpoint is capable of sending/receiving. */ /** Maximum packet size this endpoint is capable of sending/receiving. */
@ -698,7 +739,6 @@ struct libusb_config_descriptor {
* host-endian format. * host-endian format.
*/ */
struct libusb_ss_endpoint_companion_descriptor { struct libusb_ss_endpoint_companion_descriptor {
/** Size of this descriptor (in bytes) */ /** Size of this descriptor (in bytes) */
uint8_t bLength; uint8_t bLength;
@ -707,7 +747,6 @@ struct libusb_ss_endpoint_companion_descriptor {
* this context. */ * this context. */
uint8_t bDescriptorType; uint8_t bDescriptorType;
/** The maximum number of packets the endpoint can send or /** The maximum number of packets the endpoint can send or
* receive as part of a burst. */ * receive as part of a burst. */
uint8_t bMaxBurst; uint8_t bMaxBurst;
@ -719,7 +758,7 @@ struct libusb_ss_endpoint_companion_descriptor {
uint8_t bmAttributes; uint8_t bmAttributes;
/** The total number of bytes this EP will transfer every /** The total number of bytes this EP will transfer every
* service interval. valid only for periodic EPs. */ * service interval. Valid only for periodic EPs. */
uint16_t wBytesPerInterval; uint16_t wBytesPerInterval;
}; };
@ -731,12 +770,15 @@ struct libusb_ss_endpoint_companion_descriptor {
struct libusb_bos_dev_capability_descriptor { struct libusb_bos_dev_capability_descriptor {
/** Size of this descriptor (in bytes) */ /** Size of this descriptor (in bytes) */
uint8_t bLength; uint8_t bLength;
/** Descriptor type. Will have value /** Descriptor type. Will have value
* \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
* LIBUSB_DT_DEVICE_CAPABILITY in this context. */ * LIBUSB_DT_DEVICE_CAPABILITY in this context. */
uint8_t bDescriptorType; uint8_t bDescriptorType;
/** Device Capability type */ /** Device Capability type */
uint8_t bDevCapabilityType; uint8_t bDevCapabilityType;
/** Device Capability data (bLength - 3 bytes) */ /** Device Capability data (bLength - 3 bytes) */
uint8_t dev_capability_data[ZERO_SIZED_ARRAY]; uint8_t dev_capability_data[ZERO_SIZED_ARRAY];
}; };
@ -862,6 +904,9 @@ struct libusb_container_id_descriptor {
/** \ingroup libusb_asyncio /** \ingroup libusb_asyncio
* Setup packet for control transfers. */ * Setup packet for control transfers. */
#if defined(_MSC_VER)
#pragma pack(push, 1)
#endif
struct libusb_control_setup { struct libusb_control_setup {
/** Request type. Bits 0:4 determine recipient, see /** Request type. Bits 0:4 determine recipient, see
* \ref libusb_request_recipient. Bits 5:6 determine type, see * \ref libusb_request_recipient. Bits 5:6 determine type, see
@ -886,7 +931,10 @@ struct libusb_control_setup {
/** Number of bytes to transfer */ /** Number of bytes to transfer */
uint16_t wLength; uint16_t wLength;
}; } LIBUSB_PACKED;
#if defined(_MSC_VER)
#pragma pack(pop)
#endif
#define LIBUSB_CONTROL_SETUP_SIZE (sizeof(struct libusb_control_setup)) #define LIBUSB_CONTROL_SETUP_SIZE (sizeof(struct libusb_control_setup))
@ -986,62 +1034,7 @@ enum libusb_speed {
LIBUSB_SPEED_SUPER = 4, LIBUSB_SPEED_SUPER = 4,
/** The device is operating at super speed plus (10000MBit/s). */ /** The device is operating at super speed plus (10000MBit/s). */
LIBUSB_SPEED_SUPER_PLUS = 5, LIBUSB_SPEED_SUPER_PLUS = 5
};
/** \ingroup libusb_dev
* Supported speeds (wSpeedSupported) bitfield. Indicates what
* speeds the device supports.
*/
enum libusb_supported_speed {
/** Low speed operation supported (1.5MBit/s). */
LIBUSB_LOW_SPEED_OPERATION = 1,
/** Full speed operation supported (12MBit/s). */
LIBUSB_FULL_SPEED_OPERATION = 2,
/** High speed operation supported (480MBit/s). */
LIBUSB_HIGH_SPEED_OPERATION = 4,
/** Superspeed operation supported (5000MBit/s). */
LIBUSB_SUPER_SPEED_OPERATION = 8,
};
/** \ingroup libusb_dev
* Masks for the bits of the
* \ref libusb_usb_2_0_extension_descriptor::bmAttributes "bmAttributes" field
* of the USB 2.0 Extension descriptor.
*/
enum libusb_usb_2_0_extension_attributes {
/** Supports Link Power Management (LPM) */
LIBUSB_BM_LPM_SUPPORT = 2,
};
/** \ingroup libusb_dev
* Masks for the bits of the
* \ref libusb_ss_usb_device_capability_descriptor::bmAttributes "bmAttributes" field
* field of the SuperSpeed USB Device Capability descriptor.
*/
enum libusb_ss_usb_device_capability_attributes {
/** Supports Latency Tolerance Messages (LTM) */
LIBUSB_BM_LTM_SUPPORT = 2,
};
/** \ingroup libusb_dev
* USB capability types
*/
enum libusb_bos_type {
/** Wireless USB device capability */
LIBUSB_BT_WIRELESS_USB_DEVICE_CAPABILITY = 1,
/** USB 2.0 extensions */
LIBUSB_BT_USB_2_0_EXTENSION = 2,
/** SuperSpeed USB device capability */
LIBUSB_BT_SS_USB_DEVICE_CAPABILITY = 3,
/** Container ID type */
LIBUSB_BT_CONTAINER_ID = 4,
}; };
/** \ingroup libusb_misc /** \ingroup libusb_misc
@ -1095,12 +1088,31 @@ enum libusb_error {
message strings in strerror.c when adding new error codes here. */ message strings in strerror.c when adding new error codes here. */
/** Other error */ /** Other error */
LIBUSB_ERROR_OTHER = -99, LIBUSB_ERROR_OTHER = -99
}; };
/* Total number of error codes in enum libusb_error */ /* Total number of error codes in enum libusb_error */
#define LIBUSB_ERROR_COUNT 14 #define LIBUSB_ERROR_COUNT 14
/** \ingroup libusb_asyncio
* Transfer type */
enum libusb_transfer_type {
/** Control transfer */
LIBUSB_TRANSFER_TYPE_CONTROL = 0U,
/** Isochronous transfer */
LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1U,
/** Bulk transfer */
LIBUSB_TRANSFER_TYPE_BULK = 2U,
/** Interrupt transfer */
LIBUSB_TRANSFER_TYPE_INTERRUPT = 3U,
/** Bulk stream transfer */
LIBUSB_TRANSFER_TYPE_BULK_STREAM = 4U
};
/** \ingroup libusb_asyncio /** \ingroup libusb_asyncio
* Transfer status codes */ * Transfer status codes */
enum libusb_transfer_status { enum libusb_transfer_status {
@ -1125,7 +1137,7 @@ enum libusb_transfer_status {
LIBUSB_TRANSFER_NO_DEVICE, LIBUSB_TRANSFER_NO_DEVICE,
/** Device sent more data than requested */ /** Device sent more data than requested */
LIBUSB_TRANSFER_OVERFLOW, LIBUSB_TRANSFER_OVERFLOW
/* NB! Remember to update libusb_error_name() /* NB! Remember to update libusb_error_name()
when adding new status codes here. */ when adding new status codes here. */
@ -1135,19 +1147,19 @@ enum libusb_transfer_status {
* libusb_transfer.flags values */ * libusb_transfer.flags values */
enum libusb_transfer_flags { enum libusb_transfer_flags {
/** Report short frames as errors */ /** Report short frames as errors */
LIBUSB_TRANSFER_SHORT_NOT_OK = 1U << 0, LIBUSB_TRANSFER_SHORT_NOT_OK = (1U << 0),
/** Automatically free() transfer buffer during libusb_free_transfer(). /** Automatically free() transfer buffer during libusb_free_transfer().
* Note that buffers allocated with libusb_dev_mem_alloc() should not * Note that buffers allocated with libusb_dev_mem_alloc() should not
* be attempted freed in this way, since free() is not an appropriate * be attempted freed in this way, since free() is not an appropriate
* way to release such memory. */ * way to release such memory. */
LIBUSB_TRANSFER_FREE_BUFFER = 1U << 1, LIBUSB_TRANSFER_FREE_BUFFER = (1U << 1),
/** Automatically call libusb_free_transfer() after callback returns. /** Automatically call libusb_free_transfer() after callback returns.
* If this flag is set, it is illegal to call libusb_free_transfer() * If this flag is set, it is illegal to call libusb_free_transfer()
* from your transfer callback, as this will result in a double-free * from your transfer callback, as this will result in a double-free
* when this flag is acted upon. */ * when this flag is acted upon. */
LIBUSB_TRANSFER_FREE_TRANSFER = 1U << 2, LIBUSB_TRANSFER_FREE_TRANSFER = (1U << 2),
/** Terminate transfers that are a multiple of the endpoint's /** Terminate transfers that are a multiple of the endpoint's
* wMaxPacketSize with an extra zero length packet. This is useful * wMaxPacketSize with an extra zero length packet. This is useful
@ -1172,7 +1184,7 @@ enum libusb_transfer_flags {
* *
* Available since libusb-1.0.9. * Available since libusb-1.0.9.
*/ */
LIBUSB_TRANSFER_ADD_ZERO_PACKET = 1U << 3, LIBUSB_TRANSFER_ADD_ZERO_PACKET = (1U << 3)
}; };
/** \ingroup libusb_asyncio /** \ingroup libusb_asyncio
@ -1217,7 +1229,7 @@ struct libusb_transfer {
/** Address of the endpoint where this transfer will be sent. */ /** Address of the endpoint where this transfer will be sent. */
unsigned char endpoint; unsigned char endpoint;
/** Type of the endpoint from \ref libusb_transfer_type */ /** Type of the transfer from \ref libusb_transfer_type */
unsigned char type; unsigned char type;
/** Timeout for this transfer in milliseconds. A value of 0 indicates no /** Timeout for this transfer in milliseconds. A value of 0 indicates no
@ -1245,7 +1257,16 @@ struct libusb_transfer {
* fails, or is cancelled. */ * fails, or is cancelled. */
libusb_transfer_cb_fn callback; 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; void *user_data;
/** Data buffer */ /** Data buffer */
@ -1266,33 +1287,40 @@ struct libusb_transfer {
*/ */
enum libusb_capability { enum libusb_capability {
/** The libusb_has_capability() API is available. */ /** The libusb_has_capability() API is available. */
LIBUSB_CAP_HAS_CAPABILITY = 0x0000, LIBUSB_CAP_HAS_CAPABILITY = 0x0000U,
/** Hotplug support is available on this platform. */ /** Hotplug support is available on this platform. */
LIBUSB_CAP_HAS_HOTPLUG = 0x0001, LIBUSB_CAP_HAS_HOTPLUG = 0x0001U,
/** The library can access HID devices without requiring user intervention. /** The library can access HID devices without requiring user intervention.
* Note that before being able to actually access an HID device, you may * Note that before being able to actually access an HID device, you may
* still have to call additional libusb functions such as * still have to call additional libusb functions such as
* \ref libusb_detach_kernel_driver(). */ * \ref libusb_detach_kernel_driver(). */
LIBUSB_CAP_HAS_HID_ACCESS = 0x0100, LIBUSB_CAP_HAS_HID_ACCESS = 0x0100U,
/** The library supports detaching of the default USB driver, using /** The library supports detaching of the default USB driver, using
* \ref libusb_detach_kernel_driver(), if one is set by the OS kernel */ * \ref libusb_detach_kernel_driver(), if one is set by the OS kernel */
LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER = 0x0101 LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER = 0x0101U
}; };
/** \ingroup libusb_lib /** \ingroup libusb_lib
* Log message levels. * Log message levels.
* - LIBUSB_LOG_LEVEL_NONE (0) : no messages ever printed by the library (default)
* - LIBUSB_LOG_LEVEL_ERROR (1) : error messages are printed to stderr
* - LIBUSB_LOG_LEVEL_WARNING (2) : warning and error messages are printed to stderr
* - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to stderr
* - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are printed to stderr
*/ */
enum libusb_log_level { enum libusb_log_level {
/** (0) : No messages ever emitted by the library (default) */
LIBUSB_LOG_LEVEL_NONE = 0, LIBUSB_LOG_LEVEL_NONE = 0,
/** (1) : Error messages are emitted */
LIBUSB_LOG_LEVEL_ERROR = 1, LIBUSB_LOG_LEVEL_ERROR = 1,
/** (2) : Warning and error messages are emitted */
LIBUSB_LOG_LEVEL_WARNING = 2, LIBUSB_LOG_LEVEL_WARNING = 2,
/** (3) : Informational, warning and error messages are emitted */
LIBUSB_LOG_LEVEL_INFO = 3, LIBUSB_LOG_LEVEL_INFO = 3,
LIBUSB_LOG_LEVEL_DEBUG = 4,
/** (4) : All messages are emitted */
LIBUSB_LOG_LEVEL_DEBUG = 4
}; };
/** \ingroup libusb_lib /** \ingroup libusb_lib
@ -1300,12 +1328,11 @@ enum libusb_log_level {
* \see libusb_set_log_cb() * \see libusb_set_log_cb()
*/ */
enum libusb_log_cb_mode { enum libusb_log_cb_mode {
/** Callback function handling all log messages. */
LIBUSB_LOG_CB_GLOBAL = (1 << 0),
/** Callback function handling all log mesages. */ /** Callback function handling context related log messages. */
LIBUSB_LOG_CB_GLOBAL = 1 << 0, LIBUSB_LOG_CB_CONTEXT = (1 << 1)
/** Callback function handling context related log mesages. */
LIBUSB_LOG_CB_CONTEXT = 1 << 1
}; };
/** \ingroup libusb_lib /** \ingroup libusb_lib
@ -1328,7 +1355,7 @@ const struct libusb_version * LIBUSB_CALL libusb_get_version(void);
int LIBUSB_CALL libusb_has_capability(uint32_t capability); int LIBUSB_CALL libusb_has_capability(uint32_t capability);
const char * LIBUSB_CALL libusb_error_name(int errcode); const char * LIBUSB_CALL libusb_error_name(int errcode);
int LIBUSB_CALL libusb_setlocale(const char *locale); int LIBUSB_CALL libusb_setlocale(const char *locale);
const char * LIBUSB_CALL libusb_strerror(enum libusb_error errcode); const char * LIBUSB_CALL libusb_strerror(int errcode);
ssize_t LIBUSB_CALL libusb_get_device_list(libusb_context *ctx, ssize_t LIBUSB_CALL libusb_get_device_list(libusb_context *ctx,
libusb_device ***list); libusb_device ***list);
@ -1350,7 +1377,7 @@ int LIBUSB_CALL libusb_get_config_descriptor_by_value(libusb_device *dev,
void LIBUSB_CALL libusb_free_config_descriptor( void LIBUSB_CALL libusb_free_config_descriptor(
struct libusb_config_descriptor *config); struct libusb_config_descriptor *config);
int LIBUSB_CALL libusb_get_ss_endpoint_companion_descriptor( int LIBUSB_CALL libusb_get_ss_endpoint_companion_descriptor(
struct libusb_context *ctx, libusb_context *ctx,
const struct libusb_endpoint_descriptor *endpoint, const struct libusb_endpoint_descriptor *endpoint,
struct libusb_ss_endpoint_companion_descriptor **ep_comp); struct libusb_ss_endpoint_companion_descriptor **ep_comp);
void LIBUSB_CALL libusb_free_ss_endpoint_companion_descriptor( void LIBUSB_CALL libusb_free_ss_endpoint_companion_descriptor(
@ -1359,18 +1386,18 @@ int LIBUSB_CALL libusb_get_bos_descriptor(libusb_device_handle *dev_handle,
struct libusb_bos_descriptor **bos); struct libusb_bos_descriptor **bos);
void LIBUSB_CALL libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos); void LIBUSB_CALL libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos);
int LIBUSB_CALL libusb_get_usb_2_0_extension_descriptor( int LIBUSB_CALL libusb_get_usb_2_0_extension_descriptor(
struct libusb_context *ctx, libusb_context *ctx,
struct libusb_bos_dev_capability_descriptor *dev_cap, struct libusb_bos_dev_capability_descriptor *dev_cap,
struct libusb_usb_2_0_extension_descriptor **usb_2_0_extension); struct libusb_usb_2_0_extension_descriptor **usb_2_0_extension);
void LIBUSB_CALL libusb_free_usb_2_0_extension_descriptor( void LIBUSB_CALL libusb_free_usb_2_0_extension_descriptor(
struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension); struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension);
int LIBUSB_CALL libusb_get_ss_usb_device_capability_descriptor( int LIBUSB_CALL libusb_get_ss_usb_device_capability_descriptor(
struct libusb_context *ctx, libusb_context *ctx,
struct libusb_bos_dev_capability_descriptor *dev_cap, struct libusb_bos_dev_capability_descriptor *dev_cap,
struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_cap); struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_cap);
void LIBUSB_CALL libusb_free_ss_usb_device_capability_descriptor( void LIBUSB_CALL libusb_free_ss_usb_device_capability_descriptor(
struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_cap); struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_cap);
int LIBUSB_CALL libusb_get_container_id_descriptor(struct libusb_context *ctx, int LIBUSB_CALL libusb_get_container_id_descriptor(libusb_context *ctx,
struct libusb_bos_dev_capability_descriptor *dev_cap, struct libusb_bos_dev_capability_descriptor *dev_cap,
struct libusb_container_id_descriptor **container_id); struct libusb_container_id_descriptor **container_id);
void LIBUSB_CALL libusb_free_container_id_descriptor( void LIBUSB_CALL libusb_free_container_id_descriptor(
@ -1682,6 +1709,7 @@ static inline void libusb_set_iso_packet_lengths(
struct libusb_transfer *transfer, unsigned int length) struct libusb_transfer *transfer, unsigned int length)
{ {
int i; int i;
for (i = 0; i < transfer->num_iso_packets; i++) for (i = 0; i < transfer->num_iso_packets; i++)
transfer->iso_packet_desc[i].length = length; transfer->iso_packet_desc[i].length = length;
} }
@ -1896,7 +1924,7 @@ void LIBUSB_CALL libusb_set_pollfd_notifiers(libusb_context *ctx,
* Callbacks handles are generated by libusb_hotplug_register_callback() * Callbacks handles are generated by libusb_hotplug_register_callback()
* and can be used to deregister callbacks. Callback handles are unique * and can be used to deregister callbacks. Callback handles are unique
* per libusb_context and it is safe to call libusb_hotplug_deregister_callback() * 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 * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
* *
@ -1908,29 +1936,30 @@ typedef int libusb_hotplug_callback_handle;
* *
* Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
* *
* Flags for hotplug events */ * Hotplug events */
typedef enum { typedef enum {
/** Default value when not using any flags. */ /** A device has been plugged in and is ready to use */
LIBUSB_HOTPLUG_NO_FLAGS = 0U, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED = (1 << 0),
/** Arm the callback and fire it for all matching currently attached devices. */ /** A device has left and is no longer available.
LIBUSB_HOTPLUG_ENUMERATE = 1U << 0, * It is the user's responsibility to call libusb_close on any handle associated with a disconnected device.
} libusb_hotplug_flag; * It is safe to call libusb_get_device_descriptor on a device that has left */
LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT = (1 << 1)
} libusb_hotplug_event;
/** \ingroup libusb_hotplug /** \ingroup libusb_hotplug
* *
* Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
* *
* Hotplug events */ * Hotplug flags */
typedef enum { typedef enum {
/** A device has been plugged in and is ready to use */ /** Arm the callback and fire it for all matching currently attached devices. */
LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED = 0x01U, LIBUSB_HOTPLUG_ENUMERATE = (1 << 0)
} libusb_hotplug_flag;
/** A device has left and is no longer available. /** \ingroup libusb_hotplug
* It is the user's responsibility to call libusb_close on any handle associated with a disconnected device. * Convenience macro when not using any flags */
* It is safe to call libusb_get_device_descriptor on a device that has left */ #define LIBUSB_HOTPLUG_NO_FLAGS 0
LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT = 0x02U,
} libusb_hotplug_event;
/** \ingroup libusb_hotplug /** \ingroup libusb_hotplug
* Wildcard matching for hotplug events */ * Wildcard matching for hotplug events */
@ -1959,9 +1988,7 @@ typedef enum {
* returning 1 will cause this callback to be deregistered * returning 1 will cause this callback to be deregistered
*/ */
typedef int (LIBUSB_CALL *libusb_hotplug_callback_fn)(libusb_context *ctx, typedef int (LIBUSB_CALL *libusb_hotplug_callback_fn)(libusb_context *ctx,
libusb_device *device, libusb_device *device, libusb_hotplug_event event, void *user_data);
libusb_hotplug_event event,
void *user_data);
/** \ingroup libusb_hotplug /** \ingroup libusb_hotplug
* Register a hotplug callback function * Register a hotplug callback function
@ -1986,9 +2013,10 @@ typedef int (LIBUSB_CALL *libusb_hotplug_callback_fn)(libusb_context *ctx,
* Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
* *
* \param[in] ctx context to register this callback with * \param[in] ctx context to register this callback with
* \param[in] events bitwise or of events that will trigger this callback. See \ref * \param[in] events bitwise or of hotplug events that will trigger this callback.
* libusb_hotplug_event * See \ref libusb_hotplug_event
* \param[in] flags hotplug callback flags. See \ref libusb_hotplug_flag * \param[in] flags bitwise or of hotplug flags that affect registration.
* See \ref libusb_hotplug_flag
* \param[in] vendor_id the vendor id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY * \param[in] vendor_id the vendor id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
* \param[in] product_id the product id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY * \param[in] product_id the product id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
* \param[in] dev_class the device class to match or \ref LIBUSB_HOTPLUG_MATCH_ANY * \param[in] dev_class the device class to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
@ -1998,12 +2026,9 @@ typedef int (LIBUSB_CALL *libusb_hotplug_callback_fn)(libusb_context *ctx,
* \returns LIBUSB_SUCCESS on success LIBUSB_ERROR code on failure * \returns LIBUSB_SUCCESS on success LIBUSB_ERROR code on failure
*/ */
int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context *ctx, int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context *ctx,
libusb_hotplug_event events, int events, int flags,
libusb_hotplug_flag flags, int vendor_id, int product_id, int dev_class,
int vendor_id, int product_id, libusb_hotplug_callback_fn cb_fn, void *user_data,
int dev_class,
libusb_hotplug_callback_fn cb_fn,
void *user_data,
libusb_hotplug_callback_handle *callback_handle); libusb_hotplug_callback_handle *callback_handle);
/** \ingroup libusb_hotplug /** \ingroup libusb_hotplug
@ -2020,6 +2045,17 @@ int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context *ctx,
void LIBUSB_CALL libusb_hotplug_deregister_callback(libusb_context *ctx, void LIBUSB_CALL libusb_hotplug_deregister_callback(libusb_context *ctx,
libusb_hotplug_callback_handle callback_handle); libusb_hotplug_callback_handle callback_handle);
/** \ingroup libusb_hotplug
* Gets the user_data associated with a hotplug callback.
*
* Since version v1.0.24 \ref LIBUSB_API_VERSION >= 0x01000108
*
* \param[in] ctx context this callback is registered with
* \param[in] callback_handle the handle of the callback to get the user_data of
*/
void * LIBUSB_CALL libusb_hotplug_get_user_data(libusb_context *ctx,
libusb_hotplug_callback_handle callback_handle);
/** \ingroup libusb_lib /** \ingroup libusb_lib
* Available option values for libusb_set_option(). * Available option values for libusb_set_option().
*/ */
@ -2045,7 +2081,7 @@ enum libusb_option {
* If libusb was compiled with verbose debug message logging, this function * If libusb was compiled with verbose debug message logging, this function
* does nothing: you'll always get messages from all levels. * does nothing: you'll always get messages from all levels.
*/ */
LIBUSB_OPTION_LOG_LEVEL, LIBUSB_OPTION_LOG_LEVEL = 0,
/** Use the UsbDk backend for a specific context, if available. /** Use the UsbDk backend for a specific context, if available.
* *
@ -2054,12 +2090,23 @@ enum libusb_option {
* *
* Only valid on Windows. * Only valid on Windows.
*/ */
LIBUSB_OPTION_USE_USBDK, 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, ...); int LIBUSB_CALL libusb_set_option(libusb_context *ctx, enum libusb_option option, ...);
#ifdef __cplusplus #if defined(__cplusplus)
} }
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
/* -*- Mode: C; indent-tabs-mode:nil -*- */ /* -*- Mode: C; indent-tabs-mode:nil -*- */
/* /*
* darwin backend for libusb 1.0 * darwin backend for libusb 1.0
* Copyright © 2008-2019 Nathan Hjelm <hjelmn@users.sourceforge.net> * Copyright © 2008-2020 Nathan Hjelm <hjelmn@cs.unm.edu>
* Copyright © 2019 Google LLC. All rights reserved. * Copyright © 2019-2020 Google LLC. All rights reserved.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -19,11 +19,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "config.h" #include <config.h>
#include <assert.h> #include <assert.h>
#include <time.h> #include <time.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h>
#include <pthread.h> #include <pthread.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -47,56 +46,37 @@
#include <objc/objc-auto.h> #include <objc/objc-auto.h>
#endif #endif
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
/* Apple deprecated the darwin atomics in 10.12 in favor of C11 atomics */
#include <stdatomic.h>
#define libusb_darwin_atomic_fetch_add(x, y) atomic_fetch_add(x, y)
_Atomic int32_t initCount = ATOMIC_VAR_INIT(0);
#else
/* use darwin atomics if the target is older than 10.12 */
#include <libkern/OSAtomic.h>
/* OSAtomicAdd32Barrier returns the new value */
#define libusb_darwin_atomic_fetch_add(x, y) (OSAtomicAdd32Barrier(y, x) - y)
static volatile int32_t initCount = 0;
#endif
/* On 10.12 and later, use newly available clock_*() functions */
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
#define OSX_USE_CLOCK_GETTIME 1
#else
#define OSX_USE_CLOCK_GETTIME 0
#endif
#include "darwin_usb.h" #include "darwin_usb.h"
static pthread_mutex_t libusb_darwin_init_mutex = PTHREAD_MUTEX_INITIALIZER;
static int init_count = 0;
/* async event thread */ /* async event thread */
static pthread_mutex_t libusb_darwin_at_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t libusb_darwin_at_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t libusb_darwin_at_cond = PTHREAD_COND_INITIALIZER; static pthread_cond_t libusb_darwin_at_cond = PTHREAD_COND_INITIALIZER;
#if !OSX_USE_CLOCK_GETTIME #if !defined(HAVE_CLOCK_GETTIME)
static clock_serv_t clock_realtime; static clock_serv_t clock_realtime;
static clock_serv_t clock_monotonic; static clock_serv_t clock_monotonic;
#endif #endif
#define LIBUSB_DARWIN_STARTUP_FAILURE ((CFRunLoopRef) -1)
static CFRunLoopRef libusb_darwin_acfl = NULL; /* event cf loop */ static CFRunLoopRef libusb_darwin_acfl = NULL; /* event cf loop */
static CFRunLoopSourceRef libusb_darwin_acfls = NULL; /* shutdown signal for event cf loop */ static CFRunLoopSourceRef libusb_darwin_acfls = NULL; /* shutdown signal for event cf loop */
static usbi_mutex_t darwin_cached_devices_lock = PTHREAD_MUTEX_INITIALIZER; static usbi_mutex_t darwin_cached_devices_lock = PTHREAD_MUTEX_INITIALIZER;
static struct list_head darwin_cached_devices = {&darwin_cached_devices, &darwin_cached_devices}; static struct list_head darwin_cached_devices;
static const char *darwin_device_class = kIOUSBDeviceClassName; static const char *darwin_device_class = "IOUSBDevice";
#define DARWIN_CACHED_DEVICE(a) ((struct darwin_cached_device *) (((struct darwin_device_priv *)((a)->os_priv))->dev)) #define DARWIN_CACHED_DEVICE(a) (((struct darwin_device_priv *)usbi_get_device_priv((a)))->dev)
/* async event thread */ /* async event thread */
static pthread_t libusb_darwin_at; static pthread_t libusb_darwin_at;
static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian); static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, void *buffer, size_t len);
static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int iface); static int darwin_claim_interface(struct libusb_device_handle *dev_handle, uint8_t iface);
static int darwin_release_interface(struct libusb_device_handle *dev_handle, int iface); static int darwin_release_interface(struct libusb_device_handle *dev_handle, uint8_t iface);
static int darwin_reset_device(struct libusb_device_handle *dev_handle); static int darwin_reset_device(struct libusb_device_handle *dev_handle);
static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0); static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0);
@ -141,6 +121,8 @@ static const char *darwin_error_str (IOReturn result) {
return "out of resources"; return "out of resources";
case kIOUSBHighSpeedSplitError: case kIOUSBHighSpeedSplitError:
return "high speed split error"; return "high speed split error";
case kIOUSBUnknownPipeErr:
return "pipe ref not recognized";
default: default:
snprintf(string_buffer, sizeof(string_buffer), "unknown error (0x%x)", result); snprintf(string_buffer, sizeof(string_buffer), "unknown error (0x%x)", result);
return string_buffer; return string_buffer;
@ -168,6 +150,7 @@ static enum libusb_error darwin_to_libusb (IOReturn result) {
case kIOReturnAborted: case kIOReturnAborted:
case kIOReturnError: case kIOReturnError:
case kIOUSBNoAsyncPortErr: case kIOUSBNoAsyncPortErr:
case kIOUSBUnknownPipeErr:
default: default:
return LIBUSB_ERROR_OTHER; return LIBUSB_ERROR_OTHER;
} }
@ -193,7 +176,7 @@ static void darwin_ref_cached_device(struct darwin_cached_device *cached_dev) {
} }
static int ep_to_pipeRef(struct libusb_device_handle *dev_handle, uint8_t ep, uint8_t *pipep, uint8_t *ifcp, struct darwin_interface **interface_out) { static int ep_to_pipeRef(struct libusb_device_handle *dev_handle, uint8_t ep, uint8_t *pipep, uint8_t *ifcp, struct darwin_interface **interface_out) {
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
/* current interface */ /* current interface */
struct darwin_interface *cInterface; struct darwin_interface *cInterface;
@ -353,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 */ /* 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); process_new_device (ctx, cached_device, old_session_id);
} }
@ -397,7 +380,7 @@ static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) {
if (old_device->in_reenumerate) { if (old_device->in_reenumerate) {
/* device is re-enumerating. do not dereference the device at this time. libusb_reset_device() /* device is re-enumerating. do not dereference the device at this time. libusb_reset_device()
* will deref if needed. */ * 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 */ /* the device object is no longer usable so go ahead and release it */
if (old_device->device) { if (old_device->device) {
@ -419,7 +402,7 @@ static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) {
continue; 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); usbi_dbg ("notifying context %p of device disconnect", ctx);
dev = usbi_get_device_by_session_id(ctx, (unsigned long) session); dev = usbi_get_device_by_session_id(ctx, (unsigned long) session);
@ -453,10 +436,20 @@ static void darwin_clear_iterator (io_iterator_t iter) {
IOObjectRelease (device); IOObjectRelease (device);
} }
static void darwin_fail_startup(void) {
pthread_mutex_lock (&libusb_darwin_at_mutex);
libusb_darwin_acfl = LIBUSB_DARWIN_STARTUP_FAILURE;
pthread_cond_signal (&libusb_darwin_at_cond);
pthread_mutex_unlock (&libusb_darwin_at_mutex);
pthread_exit (NULL);
}
static void *darwin_event_thread_main (void *arg0) { static void *darwin_event_thread_main (void *arg0) {
IOReturn kresult; IOReturn kresult;
struct libusb_context *ctx = (struct libusb_context *)arg0; struct libusb_context *ctx = (struct libusb_context *)arg0;
CFRunLoopRef runloop; CFRunLoopRef runloop;
CFRunLoopSourceRef libusb_shutdown_cfsource;
CFRunLoopSourceContext libusb_shutdown_cfsourcectx;
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
/* Set this thread's name, so it can be seen in the debugger /* Set this thread's name, so it can be seen in the debugger
@ -475,7 +468,6 @@ static void *darwin_event_thread_main (void *arg0) {
#endif #endif
/* hotplug (device arrival/removal) sources */ /* hotplug (device arrival/removal) sources */
CFRunLoopSourceContext libusb_shutdown_cfsourcectx;
CFRunLoopSourceRef libusb_notification_cfsource; CFRunLoopSourceRef libusb_notification_cfsource;
io_notification_port_t libusb_notification_port; io_notification_port_t libusb_notification_port;
io_iterator_t libusb_rem_device_iterator; io_iterator_t libusb_rem_device_iterator;
@ -490,8 +482,8 @@ static void *darwin_event_thread_main (void *arg0) {
memset(&libusb_shutdown_cfsourcectx, 0, sizeof(libusb_shutdown_cfsourcectx)); memset(&libusb_shutdown_cfsourcectx, 0, sizeof(libusb_shutdown_cfsourcectx));
libusb_shutdown_cfsourcectx.info = runloop; libusb_shutdown_cfsourcectx.info = runloop;
libusb_shutdown_cfsourcectx.perform = (void (*)(void *))CFRunLoopStop; libusb_shutdown_cfsourcectx.perform = (void (*)(void *))CFRunLoopStop;
libusb_darwin_acfls = CFRunLoopSourceCreate(NULL, 0, &libusb_shutdown_cfsourcectx); libusb_shutdown_cfsource = CFRunLoopSourceCreate(NULL, 0, &libusb_shutdown_cfsourcectx);
CFRunLoopAddSource(runloop, libusb_darwin_acfls, kCFRunLoopDefaultMode); CFRunLoopAddSource(runloop, libusb_shutdown_cfsource, kCFRunLoopDefaultMode);
/* add the notification port to the run loop */ /* add the notification port to the run loop */
libusb_notification_port = IONotificationPortCreate (kIOMasterPortDefault); libusb_notification_port = IONotificationPortCreate (kIOMasterPortDefault);
@ -506,8 +498,9 @@ static void *darwin_event_thread_main (void *arg0) {
if (kresult != kIOReturnSuccess) { if (kresult != kIOReturnSuccess) {
usbi_err (ctx, "could not add hotplug event source: %s", darwin_error_str (kresult)); usbi_err (ctx, "could not add hotplug event source: %s", darwin_error_str (kresult));
CFRelease (libusb_shutdown_cfsource);
pthread_exit (NULL); CFRelease (runloop);
darwin_fail_startup ();
} }
/* create notifications for attached devices */ /* create notifications for attached devices */
@ -518,8 +511,9 @@ static void *darwin_event_thread_main (void *arg0) {
if (kresult != kIOReturnSuccess) { if (kresult != kIOReturnSuccess) {
usbi_err (ctx, "could not add hotplug event source: %s", darwin_error_str (kresult)); usbi_err (ctx, "could not add hotplug event source: %s", darwin_error_str (kresult));
CFRelease (libusb_shutdown_cfsource);
pthread_exit (NULL); CFRelease (runloop);
darwin_fail_startup ();
} }
/* arm notifiers */ /* arm notifiers */
@ -531,6 +525,7 @@ static void *darwin_event_thread_main (void *arg0) {
/* signal the main thread that the hotplug runloop has been created. */ /* signal the main thread that the hotplug runloop has been created. */
pthread_mutex_lock (&libusb_darwin_at_mutex); pthread_mutex_lock (&libusb_darwin_at_mutex);
libusb_darwin_acfl = runloop; libusb_darwin_acfl = runloop;
libusb_darwin_acfls = libusb_shutdown_cfsource;
pthread_cond_signal (&libusb_darwin_at_cond); pthread_cond_signal (&libusb_darwin_at_cond);
pthread_mutex_unlock (&libusb_darwin_at_mutex); pthread_mutex_unlock (&libusb_darwin_at_mutex);
@ -539,11 +534,18 @@ static void *darwin_event_thread_main (void *arg0) {
usbi_dbg ("darwin event thread exiting"); usbi_dbg ("darwin event thread exiting");
/* signal the main thread that the hotplug runloop has finished. */
pthread_mutex_lock (&libusb_darwin_at_mutex);
libusb_darwin_acfls = NULL;
libusb_darwin_acfl = NULL;
pthread_cond_signal (&libusb_darwin_at_cond);
pthread_mutex_unlock (&libusb_darwin_at_mutex);
/* remove the notification cfsource */ /* remove the notification cfsource */
CFRunLoopRemoveSource(runloop, libusb_notification_cfsource, kCFRunLoopDefaultMode); CFRunLoopRemoveSource(runloop, libusb_notification_cfsource, kCFRunLoopDefaultMode);
/* remove the shutdown cfsource */ /* remove the shutdown cfsource */
CFRunLoopRemoveSource(runloop, libusb_darwin_acfls, kCFRunLoopDefaultMode); CFRunLoopRemoveSource(runloop, libusb_shutdown_cfsource, kCFRunLoopDefaultMode);
/* delete notification port */ /* delete notification port */
IONotificationPortDestroy (libusb_notification_port); IONotificationPortDestroy (libusb_notification_port);
@ -552,36 +554,37 @@ static void *darwin_event_thread_main (void *arg0) {
IOObjectRelease (libusb_rem_device_iterator); IOObjectRelease (libusb_rem_device_iterator);
IOObjectRelease (libusb_add_device_iterator); IOObjectRelease (libusb_add_device_iterator);
CFRelease (libusb_darwin_acfls); CFRelease (libusb_shutdown_cfsource);
CFRelease (runloop); CFRelease (runloop);
libusb_darwin_acfls = NULL;
libusb_darwin_acfl = NULL;
pthread_exit (NULL); pthread_exit (NULL);
} }
/* cleanup function to destroy cached devices */ /* cleanup function to destroy cached devices */
static void __attribute__((destructor)) _darwin_finalize(void) { static void darwin_cleanup_devices(void) {
struct darwin_cached_device *dev, *next; struct darwin_cached_device *dev, *next;
usbi_mutex_lock(&darwin_cached_devices_lock);
list_for_each_entry_safe(dev, next, &darwin_cached_devices, list, struct darwin_cached_device) { list_for_each_entry_safe(dev, next, &darwin_cached_devices, list, struct darwin_cached_device) {
darwin_deref_cached_device(dev); darwin_deref_cached_device(dev);
} }
usbi_mutex_unlock(&darwin_cached_devices_lock);
darwin_cached_devices.prev = darwin_cached_devices.next = NULL;
} }
static int darwin_init(struct libusb_context *ctx) { static int darwin_init(struct libusb_context *ctx) {
bool first_init;
int rc; int rc;
rc = darwin_scan_devices (ctx); pthread_mutex_lock (&libusb_darwin_init_mutex);
if (LIBUSB_SUCCESS != rc) {
return rc;
}
if (libusb_darwin_atomic_fetch_add (&initCount, 1) == 0) { first_init = (1 == ++init_count);
#if !OSX_USE_CLOCK_GETTIME
do {
if (first_init) {
assert (NULL == darwin_cached_devices.next);
list_init (&darwin_cached_devices);
#if !defined(HAVE_CLOCK_GETTIME)
/* create the clocks that will be used if clock_gettime() is not available */ /* create the clocks that will be used if clock_gettime() is not available */
host_name_port_t host_self; host_name_port_t host_self;
@ -590,45 +593,77 @@ static int darwin_init(struct libusb_context *ctx) {
host_get_clock_service(host_self, SYSTEM_CLOCK, &clock_monotonic); host_get_clock_service(host_self, SYSTEM_CLOCK, &clock_monotonic);
mach_port_deallocate(mach_task_self(), host_self); mach_port_deallocate(mach_task_self(), host_self);
#endif #endif
}
pthread_create (&libusb_darwin_at, NULL, darwin_event_thread_main, ctx); rc = darwin_scan_devices (ctx);
if (LIBUSB_SUCCESS != rc)
break;
if (first_init) {
rc = pthread_create (&libusb_darwin_at, NULL, darwin_event_thread_main, ctx);
if (0 != rc) {
usbi_err (ctx, "could not create event thread, error %d", rc);
rc = LIBUSB_ERROR_OTHER;
break;
}
pthread_mutex_lock (&libusb_darwin_at_mutex); pthread_mutex_lock (&libusb_darwin_at_mutex);
while (!libusb_darwin_acfl) while (!libusb_darwin_acfl)
pthread_cond_wait (&libusb_darwin_at_cond, &libusb_darwin_at_mutex); pthread_cond_wait (&libusb_darwin_at_cond, &libusb_darwin_at_mutex);
pthread_mutex_unlock (&libusb_darwin_at_mutex); if (libusb_darwin_acfl == LIBUSB_DARWIN_STARTUP_FAILURE) {
libusb_darwin_acfl = NULL;
rc = LIBUSB_ERROR_OTHER;
} }
pthread_mutex_unlock (&libusb_darwin_at_mutex);
if (0 != rc)
pthread_join (libusb_darwin_at, NULL);
}
} while (0);
if (LIBUSB_SUCCESS != rc) {
if (first_init) {
darwin_cleanup_devices ();
#if !defined(HAVE_CLOCK_GETTIME)
mach_port_deallocate(mach_task_self(), clock_realtime);
mach_port_deallocate(mach_task_self(), clock_monotonic);
#endif
}
--init_count;
}
pthread_mutex_unlock (&libusb_darwin_init_mutex);
return rc; return rc;
} }
static void darwin_exit (struct libusb_context *ctx) { static void darwin_exit (struct libusb_context *ctx) {
UNUSED(ctx); UNUSED(ctx);
if (libusb_darwin_atomic_fetch_add (&initCount, -1) == 1) {
#if !OSX_USE_CLOCK_GETTIME pthread_mutex_lock (&libusb_darwin_init_mutex);
if (0 == --init_count) {
/* stop the event runloop and wait for the thread to terminate. */
pthread_mutex_lock (&libusb_darwin_at_mutex);
CFRunLoopSourceSignal (libusb_darwin_acfls);
CFRunLoopWakeUp (libusb_darwin_acfl);
while (libusb_darwin_acfl)
pthread_cond_wait (&libusb_darwin_at_cond, &libusb_darwin_at_mutex);
pthread_mutex_unlock (&libusb_darwin_at_mutex);
pthread_join (libusb_darwin_at, NULL);
darwin_cleanup_devices ();
#if !defined(HAVE_CLOCK_GETTIME)
mach_port_deallocate(mach_task_self(), clock_realtime); mach_port_deallocate(mach_task_self(), clock_realtime);
mach_port_deallocate(mach_task_self(), clock_monotonic); mach_port_deallocate(mach_task_self(), clock_monotonic);
#endif #endif
/* stop the event runloop and wait for the thread to terminate. */
CFRunLoopSourceSignal(libusb_darwin_acfls);
CFRunLoopWakeUp (libusb_darwin_acfl);
pthread_join (libusb_darwin_at, NULL);
}
} }
static int darwin_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian) { pthread_mutex_unlock (&libusb_darwin_init_mutex);
struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev);
/* return cached copy */
memmove (buffer, &(priv->dev_descriptor), DEVICE_DESC_LENGTH);
*host_endian = 0;
return LIBUSB_SUCCESS;
} }
static int get_configuration_index (struct libusb_device *dev, int config_value) { static int get_configuration_index (struct libusb_device *dev, UInt8 config_value) {
struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev); struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev);
UInt8 i, numConfig; UInt8 i, numConfig;
IOUSBConfigurationDescriptorPtr desc; IOUSBConfigurationDescriptorPtr desc;
@ -650,7 +685,7 @@ static int get_configuration_index (struct libusb_device *dev, int config_value)
return LIBUSB_ERROR_NOT_FOUND; return LIBUSB_ERROR_NOT_FOUND;
} }
static int darwin_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian) { static int darwin_get_active_config_descriptor(struct libusb_device *dev, void *buffer, size_t len) {
struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev); struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev);
int config_index; int config_index;
@ -662,10 +697,10 @@ static int darwin_get_active_config_descriptor(struct libusb_device *dev, unsign
return config_index; return config_index;
assert(config_index >= 0 && config_index <= UINT8_MAX); assert(config_index >= 0 && config_index <= UINT8_MAX);
return darwin_get_config_descriptor (dev, (UInt8)config_index, buffer, len, host_endian); return darwin_get_config_descriptor (dev, (UInt8)config_index, buffer, len);
} }
static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) { static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, void *buffer, size_t len) {
struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev); struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev);
IOUSBConfigurationDescriptorPtr desc; IOUSBConfigurationDescriptorPtr desc;
IOReturn kresult; IOReturn kresult;
@ -681,9 +716,6 @@ static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t confi
len = libusb_le16_to_cpu(desc->wTotalLength); len = libusb_le16_to_cpu(desc->wTotalLength);
memmove (buffer, desc, len); memmove (buffer, desc, len);
/* GetConfigurationDescriptorPtr returns the descriptor in USB bus order */
*host_endian = 0;
} }
ret = darwin_to_libusb (kresult); ret = darwin_to_libusb (kresult);
@ -710,7 +742,8 @@ static enum libusb_error darwin_check_configuration (struct libusb_context *ctx,
/* checking the configuration of a root hub simulation takes ~1 s in 10.11. the device is /* checking the configuration of a root hub simulation takes ~1 s in 10.11. the device is
not usable anyway */ not usable anyway */
if (0x05ac == dev->dev_descriptor.idVendor && 0x8005 == dev->dev_descriptor.idProduct) { if (0x05ac == libusb_le16_to_cpu (dev->dev_descriptor.idVendor) &&
0x8005 == libusb_le16_to_cpu (dev->dev_descriptor.idProduct)) {
usbi_dbg ("ignoring configuration on root hub simulation"); usbi_dbg ("ignoring configuration on root hub simulation");
dev->active_config = 0; dev->active_config = 0;
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
@ -891,14 +924,14 @@ static enum libusb_error darwin_cache_device_descriptor (struct darwin_cached_de
usbi_dbg ("cached device descriptor:"); usbi_dbg ("cached device descriptor:");
usbi_dbg (" bDescriptorType: 0x%02x", dev->dev_descriptor.bDescriptorType); usbi_dbg (" bDescriptorType: 0x%02x", dev->dev_descriptor.bDescriptorType);
usbi_dbg (" bcdUSB: 0x%04x", dev->dev_descriptor.bcdUSB); usbi_dbg (" bcdUSB: 0x%04x", libusb_le16_to_cpu (dev->dev_descriptor.bcdUSB));
usbi_dbg (" bDeviceClass: 0x%02x", dev->dev_descriptor.bDeviceClass); usbi_dbg (" bDeviceClass: 0x%02x", dev->dev_descriptor.bDeviceClass);
usbi_dbg (" bDeviceSubClass: 0x%02x", dev->dev_descriptor.bDeviceSubClass); usbi_dbg (" bDeviceSubClass: 0x%02x", dev->dev_descriptor.bDeviceSubClass);
usbi_dbg (" bDeviceProtocol: 0x%02x", dev->dev_descriptor.bDeviceProtocol); usbi_dbg (" bDeviceProtocol: 0x%02x", dev->dev_descriptor.bDeviceProtocol);
usbi_dbg (" bMaxPacketSize0: 0x%02x", dev->dev_descriptor.bMaxPacketSize0); usbi_dbg (" bMaxPacketSize0: 0x%02x", dev->dev_descriptor.bMaxPacketSize0);
usbi_dbg (" idVendor: 0x%04x", dev->dev_descriptor.idVendor); usbi_dbg (" idVendor: 0x%04x", libusb_le16_to_cpu (dev->dev_descriptor.idVendor));
usbi_dbg (" idProduct: 0x%04x", dev->dev_descriptor.idProduct); usbi_dbg (" idProduct: 0x%04x", libusb_le16_to_cpu (dev->dev_descriptor.idProduct));
usbi_dbg (" bcdDevice: 0x%04x", dev->dev_descriptor.bcdDevice); usbi_dbg (" bcdDevice: 0x%04x", libusb_le16_to_cpu (dev->dev_descriptor.bcdDevice));
usbi_dbg (" iManufacturer: 0x%02x", dev->dev_descriptor.iManufacturer); usbi_dbg (" iManufacturer: 0x%02x", dev->dev_descriptor.iManufacturer);
usbi_dbg (" iProduct: 0x%02x", dev->dev_descriptor.iProduct); usbi_dbg (" iProduct: 0x%02x", dev->dev_descriptor.iProduct);
usbi_dbg (" iSerialNumber: 0x%02x", dev->dev_descriptor.iSerialNumber); usbi_dbg (" iSerialNumber: 0x%02x", dev->dev_descriptor.iSerialNumber);
@ -1035,7 +1068,8 @@ static enum libusb_error darwin_get_cached_device(io_service_t service, struct d
if (new_device->can_enumerate) { if (new_device->can_enumerate) {
snprintf(new_device->sys_path, 20, "%03i-%04x-%04x-%02x-%02x", new_device->address, snprintf(new_device->sys_path, 20, "%03i-%04x-%04x-%02x-%02x", new_device->address,
new_device->dev_descriptor.idVendor, new_device->dev_descriptor.idProduct, libusb_le16_to_cpu (new_device->dev_descriptor.idVendor),
libusb_le16_to_cpu (new_device->dev_descriptor.idProduct),
new_device->dev_descriptor.bDeviceClass, new_device->dev_descriptor.bDeviceSubClass); new_device->dev_descriptor.bDeviceClass, new_device->dev_descriptor.bDeviceSubClass);
} }
} while (0); } while (0);
@ -1075,7 +1109,7 @@ static enum libusb_error process_new_device (struct libusb_context *ctx, struct
return LIBUSB_ERROR_NO_MEM; return LIBUSB_ERROR_NO_MEM;
} }
priv = (struct darwin_device_priv *)dev->os_priv; priv = usbi_get_device_priv(dev);
priv->dev = cached_device; priv->dev = cached_device;
darwin_ref_cached_device (priv->dev); darwin_ref_cached_device (priv->dev);
@ -1084,9 +1118,15 @@ static enum libusb_error process_new_device (struct libusb_context *ctx, struct
assert(cached_device->address <= UINT8_MAX); assert(cached_device->address <= UINT8_MAX);
dev->device_address = (uint8_t)cached_device->address; dev->device_address = (uint8_t)cached_device->address;
} else { } else {
priv = (struct darwin_device_priv *)dev->os_priv; priv = usbi_get_device_priv(dev);
} }
static_assert(sizeof(dev->device_descriptor) == sizeof(cached_device->dev_descriptor),
"mismatch between libusb and IOKit device descriptor sizes");
memcpy(&dev->device_descriptor, &cached_device->dev_descriptor, LIBUSB_DT_DEVICE_SIZE);
usbi_localize_device_descriptor(&dev->device_descriptor);
dev->session_data = cached_device->session;
if (cached_device->parent_session > 0) { if (cached_device->parent_session > 0) {
dev->parent_dev = usbi_get_device_by_session_id (ctx, (unsigned long) cached_device->parent_session); dev->parent_dev = usbi_get_device_by_session_id (ctx, (unsigned long) cached_device->parent_session);
} else { } else {
@ -1156,7 +1196,7 @@ static enum libusb_error darwin_scan_devices(struct libusb_context *ctx) {
} }
static int darwin_open (struct libusb_device_handle *dev_handle) { static int darwin_open (struct libusb_device_handle *dev_handle) {
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
IOReturn kresult; IOReturn kresult;
@ -1205,7 +1245,7 @@ static int darwin_open (struct libusb_device_handle *dev_handle) {
} }
static void darwin_close (struct libusb_device_handle *dev_handle) { static void darwin_close (struct libusb_device_handle *dev_handle) {
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
IOReturn kresult; IOReturn kresult;
int i; int i;
@ -1244,10 +1284,10 @@ static void darwin_close (struct libusb_device_handle *dev_handle) {
} }
} }
static int darwin_get_configuration(struct libusb_device_handle *dev_handle, int *config) { static int darwin_get_configuration(struct libusb_device_handle *dev_handle, uint8_t *config) {
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
*config = (int) dpriv->active_config; *config = dpriv->active_config;
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
@ -1255,9 +1295,10 @@ static int darwin_get_configuration(struct libusb_device_handle *dev_handle, int
static enum libusb_error darwin_set_configuration(struct libusb_device_handle *dev_handle, int config) { static enum libusb_error darwin_set_configuration(struct libusb_device_handle *dev_handle, int config) {
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
IOReturn kresult; IOReturn kresult;
int i; uint8_t i;
assert(config >= 0 && config <= UINT8_MAX); if (config == -1)
config = 0;
/* Setting configuration will invalidate the interface, so we need /* Setting configuration will invalidate the interface, so we need
to reclaim it. First, dispose of existing interfaces, if any. */ to reclaim it. First, dispose of existing interfaces, if any. */
@ -1279,7 +1320,7 @@ static enum libusb_error darwin_set_configuration(struct libusb_device_handle *d
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
static IOReturn darwin_get_interface (usb_device_t **darwin_device, int ifc, io_service_t *usbInterfacep) { static IOReturn darwin_get_interface (usb_device_t **darwin_device, uint8_t ifc, io_service_t *usbInterfacep) {
IOUSBFindInterfaceRequest request; IOUSBFindInterfaceRequest request;
IOReturn kresult; IOReturn kresult;
io_iterator_t interface_iterator; io_iterator_t interface_iterator;
@ -1316,8 +1357,8 @@ static IOReturn darwin_get_interface (usb_device_t **darwin_device, int ifc, io_
return kIOReturnSuccess; return kIOReturnSuccess;
} }
static enum libusb_error get_endpoints (struct libusb_device_handle *dev_handle, int iface) { static enum libusb_error get_endpoints (struct libusb_device_handle *dev_handle, uint8_t iface) {
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
/* current interface */ /* current interface */
struct darwin_interface *cInterface = &priv->interfaces[iface]; struct darwin_interface *cInterface = &priv->interfaces[iface];
@ -1376,21 +1417,19 @@ static enum libusb_error get_endpoints (struct libusb_device_handle *dev_handle,
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int iface) { static int darwin_claim_interface(struct libusb_device_handle *dev_handle, uint8_t iface) {
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
io_service_t usbInterface = IO_OBJECT_NULL; io_service_t usbInterface = IO_OBJECT_NULL;
IOReturn kresult; IOReturn kresult;
enum libusb_error ret; enum libusb_error ret;
IOCFPlugInInterface **plugInInterface = NULL; IOCFPlugInInterface **plugInInterface = NULL;
SInt32 score; SInt32 score;
assert(iface >= 0 && iface <= UINT8_MAX);
/* current interface */ /* current interface */
struct darwin_interface *cInterface = &priv->interfaces[iface]; struct darwin_interface *cInterface = &priv->interfaces[iface];
kresult = darwin_get_interface (dpriv->device, (uint8_t)iface, &usbInterface); kresult = darwin_get_interface (dpriv->device, iface, &usbInterface);
if (kresult != kIOReturnSuccess) if (kresult != kIOReturnSuccess)
return darwin_to_libusb (kresult); return darwin_to_libusb (kresult);
@ -1399,13 +1438,13 @@ static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int i
usbi_info (HANDLE_CTX (dev_handle), "no interface found; setting configuration: %d", dpriv->first_config); usbi_info (HANDLE_CTX (dev_handle), "no interface found; setting configuration: %d", dpriv->first_config);
/* set the configuration */ /* set the configuration */
ret = darwin_set_configuration (dev_handle, dpriv->first_config); ret = darwin_set_configuration (dev_handle, (int) dpriv->first_config);
if (ret != LIBUSB_SUCCESS) { if (ret != LIBUSB_SUCCESS) {
usbi_err (HANDLE_CTX (dev_handle), "could not set configuration"); usbi_err (HANDLE_CTX (dev_handle), "could not set configuration");
return ret; return ret;
} }
kresult = darwin_get_interface (dpriv->device, (uint8_t)iface, &usbInterface); kresult = darwin_get_interface (dpriv->device, iface, &usbInterface);
if (kresult != kIOReturnSuccess) { if (kresult != kIOReturnSuccess) {
usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult)); usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult));
return darwin_to_libusb (kresult); return darwin_to_libusb (kresult);
@ -1483,8 +1522,8 @@ static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int i
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
static int darwin_release_interface(struct libusb_device_handle *dev_handle, int iface) { static int darwin_release_interface(struct libusb_device_handle *dev_handle, uint8_t iface) {
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
IOReturn kresult; IOReturn kresult;
/* current interface */ /* current interface */
@ -1516,8 +1555,8 @@ static int darwin_release_interface(struct libusb_device_handle *dev_handle, int
return darwin_to_libusb (kresult); return darwin_to_libusb (kresult);
} }
static int darwin_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) { static int darwin_set_interface_altsetting(struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting) {
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
IOReturn kresult; IOReturn kresult;
enum libusb_error ret; enum libusb_error ret;
@ -1527,8 +1566,7 @@ static int darwin_set_interface_altsetting(struct libusb_device_handle *dev_hand
if (!cInterface->interface) if (!cInterface->interface)
return LIBUSB_ERROR_NO_DEVICE; return LIBUSB_ERROR_NO_DEVICE;
assert(altsetting >= 0 && altsetting <= UINT8_MAX); kresult = (*(cInterface->interface))->SetAlternateInterface (cInterface->interface, altsetting);
kresult = (*(cInterface->interface))->SetAlternateInterface (cInterface->interface, (UInt8)altsetting);
if (kresult != kIOReturnSuccess) if (kresult != kIOReturnSuccess)
darwin_reset_device (dev_handle); darwin_reset_device (dev_handle);
@ -1568,7 +1606,7 @@ static int darwin_clear_halt(struct libusb_device_handle *dev_handle, unsigned c
static int darwin_restore_state (struct libusb_device_handle *dev_handle, int8_t active_config, static int darwin_restore_state (struct libusb_device_handle *dev_handle, int8_t active_config,
unsigned long claimed_interfaces) { unsigned long claimed_interfaces) {
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
int open_count = dpriv->open_count; int open_count = dpriv->open_count;
int ret; int ret;
@ -1603,16 +1641,16 @@ static int darwin_restore_state (struct libusb_device_handle *dev_handle, int8_t
usbi_dbg ("darwin/restore_state: reclaiming interfaces"); usbi_dbg ("darwin/restore_state: reclaiming interfaces");
if (claimed_interfaces) { if (claimed_interfaces) {
for (int iface = 0 ; iface < USB_MAXINTERFACES ; ++iface) { for (uint8_t iface = 0 ; iface < USB_MAXINTERFACES ; ++iface) {
if (!(claimed_interfaces & (1U << iface))) { if (!(claimed_interfaces & (1U << iface))) {
continue; continue;
} }
usbi_dbg ("darwin/restore_state: re-claiming interface %d", iface); usbi_dbg ("darwin/restore_state: re-claiming interface %u", iface);
ret = darwin_claim_interface (dev_handle, iface); ret = darwin_claim_interface (dev_handle, iface);
if (LIBUSB_SUCCESS != ret) { if (LIBUSB_SUCCESS != ret) {
usbi_dbg ("darwin/restore_state: could not claim interface %d", iface); usbi_dbg ("darwin/restore_state: could not claim interface %u", iface);
return LIBUSB_ERROR_NOT_FOUND; return LIBUSB_ERROR_NOT_FOUND;
} }
@ -1688,14 +1726,13 @@ static int darwin_reset_device(struct libusb_device_handle *dev_handle) {
return darwin_restore_state (dev_handle, active_config, claimed_interfaces); return darwin_restore_state (dev_handle, active_config, claimed_interfaces);
} }
static int darwin_kernel_driver_active(struct libusb_device_handle *dev_handle, int interface) { static int darwin_kernel_driver_active(struct libusb_device_handle *dev_handle, uint8_t interface) {
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
io_service_t usbInterface; io_service_t usbInterface;
CFTypeRef driver; CFTypeRef driver;
IOReturn kresult; IOReturn kresult;
assert(interface >= 0 && interface <= UINT8_MAX); kresult = darwin_get_interface (dpriv->device, interface, &usbInterface);
kresult = darwin_get_interface (dpriv->device, (uint8_t)interface, &usbInterface);
if (kresult != kIOReturnSuccess) { if (kresult != kIOReturnSuccess) {
usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult)); usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult));
@ -1715,21 +1752,8 @@ static int darwin_kernel_driver_active(struct libusb_device_handle *dev_handle,
return 0; return 0;
} }
/* attaching/detaching kernel drivers is not currently supported (maybe in the future?) */
static int darwin_attach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) {
UNUSED(dev_handle);
UNUSED(interface);
return LIBUSB_ERROR_NOT_SUPPORTED;
}
static int darwin_detach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) {
UNUSED(dev_handle);
UNUSED(interface);
return LIBUSB_ERROR_NOT_SUPPORTED;
}
static void darwin_destroy_device(struct libusb_device *dev) { static void darwin_destroy_device(struct libusb_device *dev) {
struct darwin_device_priv *dpriv = (struct darwin_device_priv *) dev->os_priv; struct darwin_device_priv *dpriv = usbi_get_device_priv(dev);
if (dpriv->dev) { if (dpriv->dev) {
/* need to hold the lock in case this is the last reference to the device */ /* need to hold the lock in case this is the last reference to the device */
@ -1745,11 +1769,16 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer) {
IOReturn ret; IOReturn ret;
uint8_t transferType; uint8_t transferType;
/* None of the values below are used in libusbx for bulk transfers */ uint8_t pipeRef;
uint8_t direction, number, interval, pipeRef;
uint16_t maxPacketSize; uint16_t maxPacketSize;
struct darwin_interface *cInterface; struct darwin_interface *cInterface;
#if InterfaceVersion >= 550
IOUSBEndpointProperties pipeProperties = {.bVersion = kUSBEndpointPropertiesVersion3};
#else
/* None of the values below are used in libusb for bulk transfers */
uint8_t direction, number, interval;
#endif
if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, NULL, &cInterface) != 0) { if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, NULL, &cInterface) != 0) {
usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface"); usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
@ -1757,8 +1786,15 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer) {
return LIBUSB_ERROR_NOT_FOUND; return LIBUSB_ERROR_NOT_FOUND;
} }
#if InterfaceVersion >= 550
ret = (*(cInterface->interface))->GetPipePropertiesV3 (cInterface->interface, pipeRef, &pipeProperties);
transferType = pipeProperties.bTransferType;
maxPacketSize = pipeProperties.wMaxPacketSize;
#else
ret = (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number, ret = (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number,
&transferType, &maxPacketSize, &interval); &transferType, &maxPacketSize, &interval);
#endif
if (ret) { if (ret) {
usbi_err (TRANSFER_CTX (transfer), "bulk transfer failed (dir = %s): %s (code = 0x%08x)", IS_XFERIN(transfer) ? "In" : "Out", usbi_err (TRANSFER_CTX (transfer), "bulk transfer failed (dir = %s): %s (code = 0x%08x)", IS_XFERIN(transfer) ? "In" : "Out",
@ -1834,7 +1870,7 @@ static int submit_stream_transfer(struct usbi_transfer *itransfer) {
static int submit_iso_transfer(struct usbi_transfer *itransfer) { static int submit_iso_transfer(struct usbi_transfer *itransfer) {
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); struct darwin_transfer_priv *tpriv = usbi_get_transfer_priv(itransfer);
IOReturn kresult; IOReturn kresult;
uint8_t direction, number, interval, pipeRef, transferType; uint8_t direction, number, interval, pipeRef, transferType;
@ -1926,7 +1962,7 @@ static int submit_control_transfer(struct usbi_transfer *itransfer) {
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct libusb_control_setup *setup = (struct libusb_control_setup *) transfer->buffer; struct libusb_control_setup *setup = (struct libusb_control_setup *) transfer->buffer;
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(transfer->dev_handle->dev); struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(transfer->dev_handle->dev);
struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); struct darwin_transfer_priv *tpriv = usbi_get_transfer_priv(itransfer);
IOReturn kresult; IOReturn kresult;
@ -2058,20 +2094,10 @@ static int darwin_cancel_transfer(struct usbi_transfer *itransfer) {
} }
} }
static void darwin_clear_transfer_priv (struct usbi_transfer *itransfer) {
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS && tpriv->isoc_framelist) {
free (tpriv->isoc_framelist);
tpriv->isoc_framelist = NULL;
}
}
static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0) { static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0) {
struct usbi_transfer *itransfer = (struct usbi_transfer *)refcon; struct usbi_transfer *itransfer = (struct usbi_transfer *)refcon;
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); struct darwin_transfer_priv *tpriv = usbi_get_transfer_priv(itransfer);
usbi_dbg ("an async io operation has completed"); usbi_dbg ("an async io operation has completed");
@ -2120,73 +2146,62 @@ static enum libusb_transfer_status darwin_transfer_status (struct usbi_transfer
static int darwin_handle_transfer_completion (struct usbi_transfer *itransfer) { static int darwin_handle_transfer_completion (struct usbi_transfer *itransfer) {
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); struct darwin_transfer_priv *tpriv = usbi_get_transfer_priv(itransfer);
bool isIsoc = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type; const unsigned char max_transfer_type = LIBUSB_TRANSFER_TYPE_BULK_STREAM;
bool isBulk = LIBUSB_TRANSFER_TYPE_BULK == transfer->type; const char *transfer_types[max_transfer_type + 1] = {"control", "isoc", "bulk", "interrupt", "bulk-stream"};
bool isControl = LIBUSB_TRANSFER_TYPE_CONTROL == transfer->type; bool is_isoc = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type;
bool isInterrupt = LIBUSB_TRANSFER_TYPE_INTERRUPT == transfer->type;
int i;
if (!isIsoc && !isBulk && !isControl && !isInterrupt) { if (transfer->type > max_transfer_type) {
usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
return LIBUSB_ERROR_INVALID_PARAM; return LIBUSB_ERROR_INVALID_PARAM;
} }
usbi_dbg ("handling %s completion with kernel status %d", if (NULL == tpriv) {
isControl ? "control" : isBulk ? "bulk" : isIsoc ? "isoc" : "interrupt", tpriv->result); 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 (kIOReturnSuccess == tpriv->result || kIOReturnUnderrun == tpriv->result) {
if (isIsoc && tpriv->isoc_framelist) { if (is_isoc && tpriv->isoc_framelist) {
/* copy isochronous results back */ /* 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]; 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->status = darwin_transfer_status (itransfer, tpriv->isoc_framelist[i].frStatus);
lib_desc->actual_length = tpriv->isoc_framelist[i].frActCount; lib_desc->actual_length = tpriv->isoc_framelist[i].frActCount;
} }
} else if (!isIsoc) } else if (!is_isoc) {
itransfer->transferred += tpriv->size; itransfer->transferred += tpriv->size;
} }
}
/* it is ok to handle cancelled transfers without calling usbi_handle_transfer_cancellation (we catch timeout transfers) */ /* it is ok to handle cancelled transfers without calling usbi_handle_transfer_cancellation (we catch timeout transfers) */
return usbi_handle_transfer_completion (itransfer, darwin_transfer_status (itransfer, tpriv->result)); return usbi_handle_transfer_completion (itransfer, darwin_transfer_status (itransfer, tpriv->result));
} }
static int darwin_clock_gettime(int clk_id, struct timespec *tp) { #if !defined(HAVE_CLOCK_GETTIME)
#if !OSX_USE_CLOCK_GETTIME void usbi_get_monotonic_time(struct timespec *tp) {
mach_timespec_t sys_time; 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 */ /* use system boot time as reference for the monotonic clock */
clock_ref = clock_monotonic; clock_get_time (clock_monotonic, &sys_time);
break;
default:
return LIBUSB_ERROR_INVALID_PARAM;
}
clock_get_time (clock_ref, &sys_time);
tp->tv_sec = sys_time.tv_sec; tp->tv_sec = sys_time.tv_sec;
tp->tv_nsec = sys_time.tv_nsec; tp->tv_nsec = sys_time.tv_nsec;
}
return LIBUSB_SUCCESS; void usbi_get_real_time(struct timespec *tp) {
#else mach_timespec_t sys_time;
switch (clk_id) {
case USBI_CLOCK_MONOTONIC: /* CLOCK_REALTIME represents time since the epoch */
return clock_gettime(CLOCK_MONOTONIC, tp); clock_get_time (clock_realtime, &sys_time);
case USBI_CLOCK_REALTIME:
return clock_gettime(CLOCK_REALTIME, tp); tp->tv_sec = sys_time.tv_sec;
default: tp->tv_nsec = sys_time.tv_nsec;
return LIBUSB_ERROR_INVALID_PARAM;
} }
#endif #endif
}
#if InterfaceVersion >= 550 #if InterfaceVersion >= 550
static int darwin_alloc_streams (struct libusb_device_handle *dev_handle, uint32_t num_streams, unsigned char *endpoints, static int darwin_alloc_streams (struct libusb_device_handle *dev_handle, uint32_t num_streams, unsigned char *endpoints,
@ -2196,7 +2211,7 @@ static int darwin_alloc_streams (struct libusb_device_handle *dev_handle, uint32
uint8_t pipeRef; uint8_t pipeRef;
int rc, i; 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) { for (i = 0 ; i < num_endpoints ; ++i) {
if (0 != (rc = ep_to_pipeRef (dev_handle, endpoints[i], &pipeRef, NULL, &cInterface))) { if (0 != (rc = ep_to_pipeRef (dev_handle, endpoints[i], &pipeRef, NULL, &cInterface))) {
return rc; return rc;
@ -2252,8 +2267,6 @@ const struct usbi_os_backend usbi_backend = {
.caps = 0, .caps = 0,
.init = darwin_init, .init = darwin_init,
.exit = darwin_exit, .exit = darwin_exit,
.get_device_list = NULL, /* not needed */
.get_device_descriptor = darwin_get_device_descriptor,
.get_active_config_descriptor = darwin_get_active_config_descriptor, .get_active_config_descriptor = darwin_get_active_config_descriptor,
.get_config_descriptor = darwin_get_config_descriptor, .get_config_descriptor = darwin_get_config_descriptor,
.hotplug_poll = darwin_hotplug_poll, .hotplug_poll = darwin_hotplug_poll,
@ -2275,19 +2288,14 @@ const struct usbi_os_backend usbi_backend = {
#endif #endif
.kernel_driver_active = darwin_kernel_driver_active, .kernel_driver_active = darwin_kernel_driver_active,
.detach_kernel_driver = darwin_detach_kernel_driver,
.attach_kernel_driver = darwin_attach_kernel_driver,
.destroy_device = darwin_destroy_device, .destroy_device = darwin_destroy_device,
.submit_transfer = darwin_submit_transfer, .submit_transfer = darwin_submit_transfer,
.cancel_transfer = darwin_cancel_transfer, .cancel_transfer = darwin_cancel_transfer,
.clear_transfer_priv = darwin_clear_transfer_priv,
.handle_transfer_completion = darwin_handle_transfer_completion, .handle_transfer_completion = darwin_handle_transfer_completion,
.clock_gettime = darwin_clock_gettime,
.device_priv_size = sizeof(struct darwin_device_priv), .device_priv_size = sizeof(struct darwin_device_priv),
.device_handle_priv_size = sizeof(struct darwin_device_handle_priv), .device_handle_priv_size = sizeof(struct darwin_device_handle_priv),
.transfer_priv_size = sizeof(struct darwin_transfer_priv), .transfer_priv_size = sizeof(struct darwin_transfer_priv),

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -97,7 +97,7 @@ WatchedEntry::WatchedEntry(BMessenger *messenger, entry_ref *ref)
unsigned long session_id = (unsigned long)&fDevice; unsigned long session_id = (unsigned long)&fDevice;
usbi_mutex_lock(&active_contexts_lock); 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); struct libusb_device *dev = usbi_get_device_by_session_id(ctx, session_id);
if (dev) { if (dev) {
usbi_dbg("using previously allocated device with location %lu", session_id); usbi_dbg("using previously allocated device with location %lu", session_id);
@ -110,7 +110,7 @@ WatchedEntry::WatchedEntry(BMessenger *messenger, entry_ref *ref)
usbi_dbg("device allocation failed"); usbi_dbg("device allocation failed");
continue; continue;
} }
*((USBDevice **)dev->os_priv) = fDevice; *((USBDevice **)usbi_get_device_priv(dev)) = fDevice;
// Calculate pseudo-device-address // Calculate pseudo-device-address
int addr, tmp; int addr, tmp;
@ -125,9 +125,14 @@ WatchedEntry::WatchedEntry(BMessenger *messenger, entry_ref *ref)
addr += tmp + 1; addr += tmp + 1;
parent_path.GetParent(&parent_path); parent_path.GetParent(&parent_path);
} }
sscanf(path.Path(), "/dev/bus/usb/%d", &dev->bus_number); sscanf(path.Path(), "/dev/bus/usb/%hhu", &dev->bus_number);
dev->device_address = addr - (dev->bus_number + 1); dev->device_address = addr - (dev->bus_number + 1);
static_assert(sizeof(dev->device_descriptor) == sizeof(usb_device_descriptor),
"mismatch between libusb and OS device descriptor sizes");
memcpy(&dev->device_descriptor, fDevice->Descriptor(), LIBUSB_DT_DEVICE_SIZE);
usbi_localize_device_descriptor(&dev->device_descriptor);
if (usbi_sanitize_device(dev) < 0) { if (usbi_sanitize_device(dev) < 0) {
usbi_dbg("device sanitization failed"); usbi_dbg("device sanitization failed");
libusb_unref_device(dev); libusb_unref_device(dev);
@ -167,7 +172,7 @@ WatchedEntry::~WatchedEntry()
unsigned long session_id = (unsigned long)&fDevice; unsigned long session_id = (unsigned long)&fDevice;
usbi_mutex_lock(&active_contexts_lock); 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); dev = usbi_get_device_by_session_id(ctx, session_id);
if (dev != NULL) { if (dev != NULL) {
usbi_disconnect_device(dev); usbi_disconnect_device(dev);

View file

@ -38,22 +38,22 @@ public:
const char* Location() const; const char* Location() const;
uint8 CountConfigurations() const; uint8 CountConfigurations() const;
const usb_device_descriptor* Descriptor() const; const usb_device_descriptor* Descriptor() const;
const usb_configuration_descriptor* ConfigurationDescriptor(uint32) const; const usb_configuration_descriptor* ConfigurationDescriptor(uint8) const;
const usb_configuration_descriptor* ActiveConfiguration() const; const usb_configuration_descriptor* ActiveConfiguration() const;
uint8 EndpointToIndex(uint8) const; uint8 EndpointToIndex(uint8) const;
uint8 EndpointToInterface(uint8) const; uint8 EndpointToInterface(uint8) const;
int ClaimInterface(int); int ClaimInterface(uint8);
int ReleaseInterface(int); int ReleaseInterface(uint8);
int CheckInterfacesFree(int); int CheckInterfacesFree(uint8);
int SetActiveConfiguration(int); void SetActiveConfiguration(uint8);
int ActiveConfigurationIndex() const; uint8 ActiveConfigurationIndex() const;
bool InitCheck(); bool InitCheck();
private: private:
int Initialise(); int Initialise();
unsigned int fClaimedInterfaces; // Max Interfaces can be 32. Using a bitmask unsigned int fClaimedInterfaces; // Max Interfaces can be 32. Using a bitmask
usb_device_descriptor fDeviceDescriptor; usb_device_descriptor fDeviceDescriptor;
unsigned char** fConfigurationDescriptors; unsigned char** fConfigurationDescriptors;
int fActiveConfiguration; uint8 fActiveConfiguration;
char* fPath; char* fPath;
map<uint8,uint8> fConfigToIndex; map<uint8,uint8> fConfigToIndex;
map<uint8,uint8>* fEndpointToIndex; map<uint8,uint8>* fEndpointToIndex;
@ -65,11 +65,11 @@ class USBDeviceHandle {
public: public:
USBDeviceHandle(USBDevice *dev); USBDeviceHandle(USBDevice *dev);
virtual ~USBDeviceHandle(); virtual ~USBDeviceHandle();
int ClaimInterface(int); int ClaimInterface(uint8);
int ReleaseInterface(int); int ReleaseInterface(uint8);
int SetConfiguration(int); int SetConfiguration(uint8);
int SetAltSetting(int, int); int SetAltSetting(uint8, uint8);
int ClearHalt(int); int ClearHalt(uint8);
status_t SubmitTransfer(struct usbi_transfer *); status_t SubmitTransfer(struct usbi_transfer *);
status_t CancelTransfer(USBTransfer *); status_t CancelTransfer(USBTransfer *);
bool InitCheck(); bool InitCheck();

View file

@ -26,7 +26,7 @@
#include "haiku_usb.h" #include "haiku_usb.h"
int _errno_to_libusb(int status) static int _errno_to_libusb(int status)
{ {
return status; return status;
} }
@ -127,7 +127,7 @@ USBTransfer::Do(int fRawFD)
int i; int i;
usb_iso_packet_descriptor *packetDescriptors = new usb_iso_packet_descriptor[fLibusbTransfer->num_iso_packets]; usb_iso_packet_descriptor *packetDescriptors = new usb_iso_packet_descriptor[fLibusbTransfer->num_iso_packets];
for (i = 0; i < fLibusbTransfer->num_iso_packets; i++) { for (i = 0; i < fLibusbTransfer->num_iso_packets; i++) {
if ((int16)(fLibusbTransfer->iso_packet_desc[i]).length != (fLibusbTransfer->iso_packet_desc[i]).length) { if ((fLibusbTransfer->iso_packet_desc[i]).length > (unsigned int)INT16_MAX) {
fUsbiTransfer->transferred = -1; fUsbiTransfer->transferred = -1;
usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed isochronous transfer"); usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed isochronous transfer");
break; break;
@ -201,7 +201,7 @@ status_t
USBDeviceHandle::SubmitTransfer(struct usbi_transfer *itransfer) USBDeviceHandle::SubmitTransfer(struct usbi_transfer *itransfer)
{ {
USBTransfer *transfer = new USBTransfer(itransfer, fUSBDevice); USBTransfer *transfer = new USBTransfer(itransfer, fUSBDevice);
*((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = transfer; *((USBTransfer **)usbi_get_transfer_priv(itransfer)) = transfer;
BAutolock locker(fTransfersLock); BAutolock locker(fTransfersLock);
fTransfers.AddItem(transfer); fTransfers.AddItem(transfer);
release_sem(fTransfersSem); release_sem(fTransfersSem);
@ -222,9 +222,9 @@ USBDeviceHandle::CancelTransfer(USBTransfer *transfer)
USBDeviceHandle::USBDeviceHandle(USBDevice *dev) USBDeviceHandle::USBDeviceHandle(USBDevice *dev)
: :
fTransfersThread(-1),
fUSBDevice(dev), fUSBDevice(dev),
fClaimedInterfaces(0), fClaimedInterfaces(0),
fTransfersThread(-1),
fInitCheck(false) fInitCheck(false)
{ {
fRawFD = open(dev->Location(), O_RDWR | O_CLOEXEC); fRawFD = open(dev->Location(), O_RDWR | O_CLOEXEC);
@ -252,7 +252,7 @@ USBDeviceHandle::~USBDeviceHandle()
} }
int int
USBDeviceHandle::ClaimInterface(int inumber) USBDeviceHandle::ClaimInterface(uint8 inumber)
{ {
int status = fUSBDevice->ClaimInterface(inumber); int status = fUSBDevice->ClaimInterface(inumber);
if (status == LIBUSB_SUCCESS) if (status == LIBUSB_SUCCESS)
@ -261,7 +261,7 @@ USBDeviceHandle::ClaimInterface(int inumber)
} }
int int
USBDeviceHandle::ReleaseInterface(int inumber) USBDeviceHandle::ReleaseInterface(uint8 inumber)
{ {
fUSBDevice->ReleaseInterface(inumber); fUSBDevice->ReleaseInterface(inumber);
fClaimedInterfaces &= ~(1U << inumber); fClaimedInterfaces &= ~(1U << inumber);
@ -269,7 +269,7 @@ USBDeviceHandle::ReleaseInterface(int inumber)
} }
int int
USBDeviceHandle::SetConfiguration(int config) USBDeviceHandle::SetConfiguration(uint8 config)
{ {
int config_index = fUSBDevice->CheckInterfacesFree(config); int config_index = fUSBDevice->CheckInterfacesFree(config);
if (config_index == LIBUSB_ERROR_BUSY || config_index == LIBUSB_ERROR_NOT_FOUND) if (config_index == LIBUSB_ERROR_BUSY || config_index == LIBUSB_ERROR_NOT_FOUND)
@ -280,12 +280,12 @@ USBDeviceHandle::SetConfiguration(int config)
command.config.status != B_USB_RAW_STATUS_SUCCESS) { command.config.status != B_USB_RAW_STATUS_SUCCESS) {
return _errno_to_libusb(command.config.status); return _errno_to_libusb(command.config.status);
} }
fUSBDevice->SetActiveConfiguration(config_index); fUSBDevice->SetActiveConfiguration((uint8)config_index);
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
int int
USBDeviceHandle::SetAltSetting(int inumber, int alt) USBDeviceHandle::SetAltSetting(uint8 inumber, uint8 alt)
{ {
usb_raw_command command; usb_raw_command command;
command.alternate.config_index = fUSBDevice->ActiveConfigurationIndex(); command.alternate.config_index = fUSBDevice->ActiveConfigurationIndex();
@ -295,7 +295,7 @@ USBDeviceHandle::SetAltSetting(int inumber, int alt)
usbi_err(NULL, "Error retrieving active alternate interface"); usbi_err(NULL, "Error retrieving active alternate interface");
return _errno_to_libusb(command.alternate.status); return _errno_to_libusb(command.alternate.status);
} }
if (command.alternate.alternate_info == alt) { if (command.alternate.alternate_info == (uint32)alt) {
usbi_dbg("Setting alternate interface successful"); usbi_dbg("Setting alternate interface successful");
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
@ -309,9 +309,8 @@ USBDeviceHandle::SetAltSetting(int inumber, int alt)
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
int int
USBDevice::ClearHalt(int endpoint) USBDeviceHandle::ClearHalt(uint8 endpoint)
{ {
usb_raw_command command; usb_raw_command command;
command.control.request_type = USB_REQTYPE_ENDPOINT_OUT; command.control.request_type = USB_REQTYPE_ENDPOINT_OUT;
@ -324,15 +323,16 @@ USBDevice::ClearHalt(int endpoint)
command.control.status != B_USB_RAW_STATUS_SUCCESS) { command.control.status != B_USB_RAW_STATUS_SUCCESS) {
return _errno_to_libusb(command.control.status); return _errno_to_libusb(command.control.status);
} }
return LIBUSB_SUCCESS;
} }
USBDevice::USBDevice(const char *path) USBDevice::USBDevice(const char *path)
: :
fPath(NULL),
fActiveConfiguration(0), //0?
fConfigurationDescriptors(NULL),
fClaimedInterfaces(0), fClaimedInterfaces(0),
fConfigurationDescriptors(NULL),
fActiveConfiguration(0), //0?
fPath(NULL),
fEndpointToIndex(NULL), fEndpointToIndex(NULL),
fEndpointToInterface(NULL), fEndpointToInterface(NULL),
fInitCheck(false) fInitCheck(false)
@ -345,7 +345,7 @@ USBDevice::~USBDevice()
{ {
free(fPath); free(fPath);
if (fConfigurationDescriptors) { if (fConfigurationDescriptors) {
for(int i = 0; i < fDeviceDescriptor.num_configurations; i++) { for (uint8 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
if (fConfigurationDescriptors[i]) if (fConfigurationDescriptors[i])
delete fConfigurationDescriptors[i]; delete fConfigurationDescriptors[i];
} }
@ -382,7 +382,7 @@ USBDevice::Descriptor() const
} }
const usb_configuration_descriptor * const usb_configuration_descriptor *
USBDevice::ConfigurationDescriptor(uint32 index) const USBDevice::ConfigurationDescriptor(uint8 index) const
{ {
if (index > CountConfigurations()) if (index > CountConfigurations())
return NULL; return NULL;
@ -395,13 +395,13 @@ USBDevice::ActiveConfiguration() const
return (usb_configuration_descriptor *) fConfigurationDescriptors[fActiveConfiguration]; return (usb_configuration_descriptor *) fConfigurationDescriptors[fActiveConfiguration];
} }
int uint8
USBDevice::ActiveConfigurationIndex() const USBDevice::ActiveConfigurationIndex() const
{ {
return fActiveConfiguration; return fActiveConfiguration;
} }
int USBDevice::ClaimInterface(int interface) int USBDevice::ClaimInterface(uint8 interface)
{ {
if (interface > ActiveConfiguration()->number_interfaces) if (interface > ActiveConfiguration()->number_interfaces)
return LIBUSB_ERROR_NOT_FOUND; return LIBUSB_ERROR_NOT_FOUND;
@ -411,27 +411,26 @@ int USBDevice::ClaimInterface(int interface)
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
int USBDevice::ReleaseInterface(int interface) int USBDevice::ReleaseInterface(uint8 interface)
{ {
fClaimedInterfaces &= ~(1U << interface); fClaimedInterfaces &= ~(1U << interface);
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
int int
USBDevice::CheckInterfacesFree(int config) USBDevice::CheckInterfacesFree(uint8 config)
{ {
if (fConfigToIndex.count(config) == 0) if (fConfigToIndex.count(config) == 0)
return LIBUSB_ERROR_NOT_FOUND; return LIBUSB_ERROR_NOT_FOUND;
if (fClaimedInterfaces == 0) if (fClaimedInterfaces == 0)
return fConfigToIndex[(uint8)config]; return fConfigToIndex[config];
return LIBUSB_ERROR_BUSY; return LIBUSB_ERROR_BUSY;
} }
int void
USBDevice::SetActiveConfiguration(int config_index) USBDevice::SetActiveConfiguration(uint8 config_index)
{ {
fActiveConfiguration = config_index; fActiveConfiguration = config_index;
return LIBUSB_SUCCESS;
} }
uint8 uint8
@ -463,7 +462,7 @@ USBDevice::Initialise() //Do we need more error checking, etc? How to report?
fConfigurationDescriptors = new(std::nothrow) unsigned char *[fDeviceDescriptor.num_configurations]; fConfigurationDescriptors = new(std::nothrow) unsigned char *[fDeviceDescriptor.num_configurations];
fEndpointToIndex = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations]; fEndpointToIndex = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
fEndpointToInterface = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations]; fEndpointToInterface = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
for (int i = 0; i < fDeviceDescriptor.num_configurations; i++) { for (uint8 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
usb_configuration_descriptor tmp_config; usb_configuration_descriptor tmp_config;
command.config.descriptor = &tmp_config; command.config.descriptor = &tmp_config;
command.config.config_index = i; command.config.config_index = i;
@ -479,14 +478,14 @@ USBDevice::Initialise() //Do we need more error checking, etc? How to report?
command.config_etc.descriptor = (usb_configuration_descriptor*)fConfigurationDescriptors[i]; command.config_etc.descriptor = (usb_configuration_descriptor*)fConfigurationDescriptors[i];
command.config_etc.length = tmp_config.total_length; command.config_etc.length = tmp_config.total_length;
command.config_etc.config_index = i; command.config_etc.config_index = i;
if (ioctl(fRawFD, B_USB_COMMAND_GET_CONFIGURATION_DESCRIPTOR_ETC, &command, sizeof(command)) || if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR_ETC, &command, sizeof(command)) ||
command.config_etc.status != B_USB_RAW_STATUS_SUCCESS) { command.config_etc.status != B_USB_RAW_STATUS_SUCCESS) {
usbi_err(NULL, "failed retrieving full configuration descriptor"); usbi_err(NULL, "failed retrieving full configuration descriptor");
close(fRawFD); close(fRawFD);
return B_ERROR; return B_ERROR;
} }
for (int j = 0; j < tmp_config.number_interfaces; j++) { for (uint8 j = 0; j < tmp_config.number_interfaces; j++) {
command.alternate.config_index = i; command.alternate.config_index = i;
command.alternate.interface_index = j; command.alternate.interface_index = j;
if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT, &command, sizeof(command)) || if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT, &command, sizeof(command)) ||
@ -495,8 +494,8 @@ USBDevice::Initialise() //Do we need more error checking, etc? How to report?
close(fRawFD); close(fRawFD);
return B_ERROR; return B_ERROR;
} }
int num_alternate = command.alternate.alternate_info; uint8 num_alternate = (uint8)command.alternate.alternate_info;
for (int k = 0; k < num_alternate; k++) { for (uint8 k = 0; k < num_alternate; k++) {
usb_interface_descriptor tmp_interface; usb_interface_descriptor tmp_interface;
command.interface_etc.config_index = i; command.interface_etc.config_index = i;
command.interface_etc.interface_index = j; command.interface_etc.interface_index = j;
@ -508,7 +507,7 @@ USBDevice::Initialise() //Do we need more error checking, etc? How to report?
close(fRawFD); close(fRawFD);
return B_ERROR; return B_ERROR;
} }
for (int l = 0; l < tmp_interface.num_endpoints; l++) { for (uint8 l = 0; l < tmp_interface.num_endpoints; l++) {
usb_endpoint_descriptor tmp_endpoint; usb_endpoint_descriptor tmp_endpoint;
command.endpoint_etc.config_index = i; command.endpoint_etc.config_index = i;
command.endpoint_etc.interface_index = j; command.endpoint_etc.interface_index = j;

View file

@ -30,11 +30,12 @@ USBRoster gUsbRoster;
int32 gInitCount = 0; int32 gInitCount = 0;
static int haiku_get_config_descriptor(struct libusb_device *, uint8_t, static int haiku_get_config_descriptor(struct libusb_device *, uint8_t,
unsigned char *, size_t, int *); void *, size_t);
static int static int
haiku_init(struct libusb_context *ctx) haiku_init(struct libusb_context *ctx)
{ {
UNUSED(ctx);
if (atomic_add(&gInitCount, 1) == 0) if (atomic_add(&gInitCount, 1) == 0)
return gUsbRoster.Start(); return gUsbRoster.Start();
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
@ -51,7 +52,7 @@ haiku_exit(struct libusb_context *ctx)
static int static int
haiku_open(struct libusb_device_handle *dev_handle) haiku_open(struct libusb_device_handle *dev_handle)
{ {
USBDevice *dev = *((USBDevice **)dev_handle->dev->os_priv); USBDevice *dev = *((USBDevice **)usbi_get_device_priv(dev_handle->dev));
USBDeviceHandle *handle = new(std::nothrow) USBDeviceHandle(dev); USBDeviceHandle *handle = new(std::nothrow) USBDeviceHandle(dev);
if (handle == NULL) if (handle == NULL)
return LIBUSB_ERROR_NO_MEM; return LIBUSB_ERROR_NO_MEM;
@ -59,92 +60,78 @@ haiku_open(struct libusb_device_handle *dev_handle)
delete handle; delete handle;
return LIBUSB_ERROR_NO_DEVICE; return LIBUSB_ERROR_NO_DEVICE;
} }
*((USBDeviceHandle **)dev_handle->os_priv) = handle; *((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle)) = handle;
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
static void static void
haiku_close(struct libusb_device_handle *dev_handle) haiku_close(struct libusb_device_handle *dev_handle)
{ {
USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv); USBDeviceHandle **pHandle = (USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle);
USBDeviceHandle *handle = *pHandle;
if (handle == NULL) if (handle == NULL)
return; return;
delete handle; delete handle;
*((USBDeviceHandle **)dev_handle->os_priv) = NULL; *pHandle = NULL;
} }
static int static int
haiku_get_device_descriptor(struct libusb_device *device, unsigned char *buffer, int *host_endian) haiku_get_active_config_descriptor(struct libusb_device *device, void *buffer, size_t len)
{ {
USBDevice *dev = *((USBDevice **)device->os_priv); USBDevice *dev = *((USBDevice **)usbi_get_device_priv(device));
memcpy(buffer, dev->Descriptor(), DEVICE_DESC_LENGTH); return haiku_get_config_descriptor(device, dev->ActiveConfigurationIndex(), buffer, len);
*host_endian = 0;
return LIBUSB_SUCCESS;
} }
static int static int
haiku_get_active_config_descriptor(struct libusb_device *device, unsigned char *buffer, size_t len, int *host_endian) haiku_get_config_descriptor(struct libusb_device *device, uint8_t config_index, void *buffer, size_t len)
{ {
USBDevice *dev = *((USBDevice **)device->os_priv); USBDevice *dev = *((USBDevice **)usbi_get_device_priv(device));
return haiku_get_config_descriptor(device, dev->ActiveConfigurationIndex(), buffer, len, host_endian);
}
static int
haiku_get_config_descriptor(struct libusb_device *device, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
{
USBDevice *dev = *((USBDevice **)device->os_priv);
const usb_configuration_descriptor *config = dev->ConfigurationDescriptor(config_index); const usb_configuration_descriptor *config = dev->ConfigurationDescriptor(config_index);
if (config == NULL) { if (config == NULL) {
usbi_err(DEVICE_CTX(device), "failed getting configuration descriptor"); usbi_err(DEVICE_CTX(device), "failed getting configuration descriptor");
return LIBUSB_ERROR_INVALID_PARAM; return LIBUSB_ERROR_IO;
} }
if (len > config->total_length) { if (len > config->total_length) {
len = config->total_length; len = config->total_length;
} }
memcpy(buffer, config, len); memcpy(buffer, config, len);
*host_endian = 0;
return len; return len;
} }
static int static int
haiku_set_configuration(struct libusb_device_handle *dev_handle, int config) haiku_set_configuration(struct libusb_device_handle *dev_handle, int config)
{ {
USBDeviceHandle *handle= *((USBDeviceHandle **)dev_handle->os_priv); USBDeviceHandle *handle= *((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle));
return handle->SetConfiguration(config); if (config <= 0)
return LIBUSB_ERROR_NOT_SUPPORTED; // cannot unconfigure
return handle->SetConfiguration((uint8)config);
} }
static int static int
haiku_claim_interface(struct libusb_device_handle *dev_handle, int interface_number) haiku_claim_interface(struct libusb_device_handle *dev_handle, uint8_t interface_number)
{ {
USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv); USBDeviceHandle *handle = *((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle));
return handle->ClaimInterface(interface_number); return handle->ClaimInterface(interface_number);
} }
static int static int
haiku_set_altsetting(struct libusb_device_handle *dev_handle, int interface_number, int altsetting) haiku_set_altsetting(struct libusb_device_handle *dev_handle, uint8_t interface_number, uint8_t altsetting)
{ {
USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv); USBDeviceHandle *handle = *((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle));
return handle->SetAltSetting(interface_number, altsetting); return handle->SetAltSetting(interface_number, altsetting);
} }
static int static int
haiku_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) haiku_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
{ {
USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv); USBDeviceHandle *handle = *((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle));
return handle->ClearHalt(endpoint); return handle->ClearHalt(endpoint);
} }
static int static int
haiku_reset_device(struct libusb_device_handle *dev_handle) haiku_release_interface(struct libusb_device_handle *dev_handle, uint8_t interface_number)
{ {
/* TODO */ USBDeviceHandle *handle = *((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle));
return LIBUSB_ERROR_NOT_SUPPORTED;
}
static int
haiku_release_interface(struct libusb_device_handle *dev_handle, int interface_number)
{
USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv);
haiku_set_altsetting(dev_handle, interface_number, 0); haiku_set_altsetting(dev_handle, interface_number, 0);
return handle->ReleaseInterface(interface_number); return handle->ReleaseInterface(interface_number);
} }
@ -153,7 +140,7 @@ static int
haiku_submit_transfer(struct usbi_transfer *itransfer) haiku_submit_transfer(struct usbi_transfer *itransfer)
{ {
struct libusb_transfer *fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct libusb_transfer *fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
USBDeviceHandle *fDeviceHandle = *((USBDeviceHandle **)fLibusbTransfer->dev_handle->os_priv); USBDeviceHandle *fDeviceHandle = *((USBDeviceHandle **)usbi_get_device_handle_priv(fLibusbTransfer->dev_handle));
return fDeviceHandle->SubmitTransfer(itransfer); return fDeviceHandle->SubmitTransfer(itransfer);
} }
@ -161,27 +148,20 @@ static int
haiku_cancel_transfer(struct usbi_transfer *itransfer) haiku_cancel_transfer(struct usbi_transfer *itransfer)
{ {
struct libusb_transfer *fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct libusb_transfer *fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
USBDeviceHandle *fDeviceHandle = *((USBDeviceHandle **)fLibusbTransfer->dev_handle->os_priv); USBDeviceHandle *fDeviceHandle = *((USBDeviceHandle **)usbi_get_device_handle_priv(fLibusbTransfer->dev_handle));
return fDeviceHandle->CancelTransfer(*((USBTransfer **)usbi_transfer_get_os_priv(itransfer))); return fDeviceHandle->CancelTransfer(*((USBTransfer **)usbi_get_transfer_priv(itransfer)));
}
static void
haiku_clear_transfer_priv(struct usbi_transfer *itransfer)
{
USBTransfer *transfer = *((USBTransfer **)usbi_transfer_get_os_priv(itransfer));
delete transfer;
*((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = NULL;
} }
static int static int
haiku_handle_transfer_completion(struct usbi_transfer *itransfer) haiku_handle_transfer_completion(struct usbi_transfer *itransfer)
{ {
USBTransfer *transfer = *((USBTransfer **)usbi_transfer_get_os_priv(itransfer)); USBTransfer **pTransfer = (USBTransfer **)usbi_get_transfer_priv(itransfer);
USBTransfer *transfer = *pTransfer;
usbi_mutex_lock(&itransfer->lock); usbi_mutex_lock(&itransfer->lock);
if (transfer->IsCancelled()) { if (transfer->IsCancelled()) {
delete transfer; delete transfer;
*((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = NULL; *pTransfer = NULL;
usbi_mutex_unlock(&itransfer->lock); usbi_mutex_unlock(&itransfer->lock);
if (itransfer->transferred < 0) if (itransfer->transferred < 0)
itransfer->transferred = 0; itransfer->transferred = 0;
@ -194,74 +174,58 @@ haiku_handle_transfer_completion(struct usbi_transfer *itransfer)
itransfer->transferred = 0; itransfer->transferred = 0;
} }
delete transfer; delete transfer;
*((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = NULL; *pTransfer = NULL;
usbi_mutex_unlock(&itransfer->lock); usbi_mutex_unlock(&itransfer->lock);
return usbi_handle_transfer_completion(itransfer, status); return usbi_handle_transfer_completion(itransfer, status);
} }
static int
haiku_clock_gettime(int clkid, struct timespec *tp)
{
if (clkid == USBI_CLOCK_REALTIME)
return clock_gettime(CLOCK_REALTIME, tp);
if (clkid == USBI_CLOCK_MONOTONIC)
return clock_gettime(CLOCK_MONOTONIC, tp);
return LIBUSB_ERROR_INVALID_PARAM;
}
const struct usbi_os_backend usbi_backend = { const struct usbi_os_backend usbi_backend = {
.name = "Haiku usbfs", /*.name =*/ "Haiku usbfs",
.caps = 0, /*.caps =*/ 0,
.init = haiku_init, /*.init =*/ haiku_init,
.exit = haiku_exit, /*.exit =*/ haiku_exit,
.set_option = NULL, /*.set_option =*/ NULL,
.get_device_list = NULL, /*.get_device_list =*/ NULL,
.hotplug_poll = NULL, /*.hotplug_poll =*/ NULL,
.wrap_sys_device = NULL, /*.wrap_sys_device =*/ NULL,
.open = haiku_open, /*.open =*/ haiku_open,
.close = haiku_close, /*.close =*/ haiku_close,
.get_device_descriptor = haiku_get_device_descriptor,
.get_active_config_descriptor = haiku_get_active_config_descriptor,
.get_config_descriptor = haiku_get_config_descriptor,
.get_config_descriptor_by_value = NULL,
/*.get_active_config_descriptor =*/ haiku_get_active_config_descriptor,
/*.get_config_descriptor =*/ haiku_get_config_descriptor,
/*.get_config_descriptor_by_value =*/ NULL,
.get_configuration = NULL, /*.get_configuration =*/ NULL,
.set_configuration = haiku_set_configuration, /*.set_configuration =*/ haiku_set_configuration,
.claim_interface = haiku_claim_interface,
.release_interface = haiku_release_interface,
.set_interface_altsetting = haiku_set_altsetting, /*.claim_interface =*/ haiku_claim_interface,
.clear_halt = haiku_clear_halt, /*.release_interface =*/ haiku_release_interface,
.reset_device = haiku_reset_device, /*.set_interface_altsetting =*/ haiku_set_altsetting,
.alloc_streams = NULL, /*.clear_halt =*/ haiku_clear_halt,
.free_streams = NULL, /*.reset_device =*/ NULL,
.dev_mem_alloc = NULL, /*.alloc_streams =*/ NULL,
.dev_mem_free = NULL, /*.free_streams =*/ NULL,
.kernel_driver_active = NULL, /*.dev_mem_alloc =*/ NULL,
.detach_kernel_driver = NULL, /*.dev_mem_free =*/ NULL,
.attach_kernel_driver = NULL,
.destroy_device = NULL, /*.kernel_driver_active =*/ NULL,
/*.detach_kernel_driver =*/ NULL,
/*.attach_kernel_driver =*/ NULL,
.submit_transfer = haiku_submit_transfer, /*.destroy_device =*/ NULL,
.cancel_transfer = haiku_cancel_transfer,
.clear_transfer_priv = haiku_clear_transfer_priv,
.handle_events = NULL, /*.submit_transfer =*/ haiku_submit_transfer,
.handle_transfer_completion = haiku_handle_transfer_completion, /*.cancel_transfer =*/ haiku_cancel_transfer,
/*.clear_transfer_priv =*/ NULL,
.clock_gettime = haiku_clock_gettime, /*.handle_events =*/ NULL,
/*.handle_transfer_completion =*/ haiku_handle_transfer_completion,
#ifdef USBI_TIMERFD_AVAILABLE /*.context_priv_size =*/ 0,
.get_timerfd_clockid = NULL, /*.device_priv_size =*/ sizeof(USBDevice *),
#endif /*.device_handle_priv_size =*/ sizeof(USBDeviceHandle *),
/*.transfer_priv_size =*/ sizeof(USBTransfer *),
.context_priv_size = 0,
.device_priv_size = sizeof(USBDevice *),
.device_handle_priv_size = sizeof(USBDeviceHandle *),
.transfer_priv_size = sizeof(USBTransfer *),
}; };

View file

@ -21,27 +21,21 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <config.h> #include "libusbi.h"
#include "linux_usbfs.h"
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <poll.h> #include <poll.h>
#include <stdio.h> #include <pthread.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <sys/types.h>
#ifdef HAVE_ASM_TYPES_H #ifdef HAVE_ASM_TYPES_H
#include <asm/types.h> #include <asm/types.h>
#endif #endif
#include <sys/socket.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <sys/socket.h>
#include "libusbi.h"
#include "linux_usbfs.h"
#define NL_GROUP_KERNEL 1 #define NL_GROUP_KERNEL 1
@ -54,7 +48,7 @@
#endif #endif
static int linux_netlink_socket = -1; 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 pthread_t libusb_linux_event_thread;
static void *linux_netlink_event_thread_main(void *arg); static void *linux_netlink_event_thread_main(void *arg);
@ -68,12 +62,12 @@ static int set_fd_cloexec_nb(int fd, int socktype)
if (!(socktype & SOCK_CLOEXEC)) { if (!(socktype & SOCK_CLOEXEC)) {
flags = fcntl(fd, F_GETFD); flags = fcntl(fd, F_GETFD);
if (flags == -1) { if (flags == -1) {
usbi_err(NULL, "failed to get netlink fd flags (%d)", errno); usbi_err(NULL, "failed to get netlink fd flags, errno=%d", errno);
return -1; return -1;
} }
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
usbi_err(NULL, "failed to set netlink fd flags (%d)", errno); usbi_err(NULL, "failed to set netlink fd flags, errno=%d", errno);
return -1; return -1;
} }
} }
@ -83,12 +77,12 @@ static int set_fd_cloexec_nb(int fd, int socktype)
if (!(socktype & SOCK_NONBLOCK)) { if (!(socktype & SOCK_NONBLOCK)) {
flags = fcntl(fd, F_GETFL); flags = fcntl(fd, F_GETFL);
if (flags == -1) { if (flags == -1) {
usbi_err(NULL, "failed to get netlink fd status flags (%d)", errno); usbi_err(NULL, "failed to get netlink fd status flags, errno=%d", errno);
return -1; return -1;
} }
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
usbi_err(NULL, "failed to set netlink fd status flags (%d)", errno); usbi_err(NULL, "failed to set netlink fd status flags, errno=%d", errno);
return -1; return -1;
} }
} }
@ -111,7 +105,7 @@ int linux_netlink_start_event_monitor(void)
} }
if (linux_netlink_socket == -1) { if (linux_netlink_socket == -1) {
usbi_err(NULL, "failed to create netlink socket (%d)", errno); usbi_err(NULL, "failed to create netlink socket, errno=%d", errno);
goto err; goto err;
} }
@ -121,35 +115,33 @@ int linux_netlink_start_event_monitor(void)
ret = bind(linux_netlink_socket, (struct sockaddr *)&sa_nl, sizeof(sa_nl)); ret = bind(linux_netlink_socket, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
if (ret == -1) { if (ret == -1) {
usbi_err(NULL, "failed to bind netlink socket (%d)", errno); usbi_err(NULL, "failed to bind netlink socket, errno=%d", errno);
goto err_close_socket; goto err_close_socket;
} }
ret = setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt)); ret = setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt));
if (ret == -1) { if (ret == -1) {
usbi_err(NULL, "failed to set netlink socket SO_PASSCRED option (%d)", errno); usbi_err(NULL, "failed to set netlink socket SO_PASSCRED option, errno=%d", errno);
goto err_close_socket; goto err_close_socket;
} }
ret = usbi_pipe(netlink_control_pipe); ret = usbi_create_event(&netlink_control_event);
if (ret) { if (ret) {
usbi_err(NULL, "failed to create netlink control pipe"); usbi_err(NULL, "failed to create netlink control event");
goto err_close_socket; goto err_close_socket;
} }
ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL); ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL);
if (ret != 0) { if (ret != 0) {
usbi_err(NULL, "failed to create netlink event thread (%d)", ret); usbi_err(NULL, "failed to create netlink event thread (%d)", ret);
goto err_close_pipe; goto err_destroy_event;
} }
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
err_close_pipe: err_destroy_event:
close(netlink_control_pipe[0]); usbi_destroy_event(&netlink_control_event);
close(netlink_control_pipe[1]); netlink_control_event = (usbi_event_t)USBI_INVALID_EVENT;
netlink_control_pipe[0] = -1;
netlink_control_pipe[1] = -1;
err_close_socket: err_close_socket:
close(linux_netlink_socket); close(linux_netlink_socket);
linux_netlink_socket = -1; linux_netlink_socket = -1;
@ -159,28 +151,23 @@ err:
int linux_netlink_stop_event_monitor(void) int linux_netlink_stop_event_monitor(void)
{ {
char dummy = 1; int ret;
ssize_t r;
assert(linux_netlink_socket != -1); assert(linux_netlink_socket != -1);
/* Write some dummy data to the control pipe and /* Signal the control event and wait for the thread to exit */
* wait for the thread to exit */ usbi_signal_event(&netlink_control_event);
r = write(netlink_control_pipe[1], &dummy, sizeof(dummy));
if (r <= 0)
usbi_warn(NULL, "netlink control pipe signal failed");
pthread_join(libusb_linux_event_thread, NULL); ret = pthread_join(libusb_linux_event_thread, NULL);
if (ret)
usbi_warn(NULL, "failed to join netlink event thread (%d)", ret);
usbi_destroy_event(&netlink_control_event);
netlink_control_event = (usbi_event_t)USBI_INVALID_EVENT;
close(linux_netlink_socket); close(linux_netlink_socket);
linux_netlink_socket = -1; 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; return LIBUSB_SUCCESS;
} }
@ -314,7 +301,7 @@ static int linux_netlink_read_message(void)
len = recvmsg(linux_netlink_socket, &msg, 0); len = recvmsg(linux_netlink_socket, &msg, 0);
if (len == -1) { if (len == -1) {
if (errno != EAGAIN && errno != EINTR) if (errno != EAGAIN && errno != EINTR)
usbi_err(NULL, "error receiving message from netlink (%d)", errno); usbi_err(NULL, "error receiving message from netlink, errno=%d", errno);
return -1; return -1;
} }
@ -359,33 +346,38 @@ static int linux_netlink_read_message(void)
static void *linux_netlink_event_thread_main(void *arg) static void *linux_netlink_event_thread_main(void *arg)
{ {
char dummy;
int r;
ssize_t nb;
struct pollfd fds[] = { struct pollfd fds[] = {
{ .fd = netlink_control_pipe[0], { .fd = USBI_EVENT_OS_HANDLE(&netlink_control_event),
.events = POLLIN }, .events = USBI_EVENT_POLL_EVENTS },
{ .fd = linux_netlink_socket, { .fd = linux_netlink_socket,
.events = POLLIN }, .events = POLLIN },
}; };
int r;
UNUSED(arg); UNUSED(arg);
#if defined(HAVE_PTHREAD_SETNAME_NP)
r = pthread_setname_np(pthread_self(), "libusb_event");
if (r)
usbi_warn(NULL, "failed to set hotplug event thread name, error=%d", r);
#endif
usbi_dbg("netlink event thread entering"); usbi_dbg("netlink event thread entering");
while ((r = poll(fds, 2, -1)) >= 0 || errno == EINTR) { while (1) {
if (r < 0) { r = poll(fds, 2, -1);
/* temporary failure */ if (r == -1) {
/* check for temporary failure */
if (errno == EINTR)
continue; continue;
} usbi_err(NULL, "poll() failed, errno=%d", errno);
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");
break; break;
} }
if (fds[1].revents & POLLIN) { if (fds[0].revents) {
/* activity on control event, exit */
break;
}
if (fds[1].revents) {
usbi_mutex_static_lock(&linux_hotplug_lock); usbi_mutex_static_lock(&linux_hotplug_lock);
linux_netlink_read_message(); linux_netlink_read_message();
usbi_mutex_static_unlock(&linux_hotplug_lock); usbi_mutex_static_unlock(&linux_hotplug_lock);

View file

@ -20,32 +20,21 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <config.h>
#include <assert.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/socket.h>
#include <unistd.h>
#include <libudev.h>
#include "libusbi.h" #include "libusbi.h"
#include "linux_usbfs.h" #include "linux_usbfs.h"
#include <errno.h>
#include <fcntl.h>
#include <libudev.h>
#include <poll.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
/* udev context */ /* udev context */
static struct udev *udev_ctx = NULL; static struct udev *udev_ctx = NULL;
static int udev_monitor_fd = -1; 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 struct udev_monitor *udev_monitor = NULL;
static pthread_t linux_event_thread; static pthread_t linux_event_thread;
@ -86,12 +75,12 @@ int linux_udev_start_event_monitor(void)
/* Make sure the udev file descriptor is marked as CLOEXEC */ /* Make sure the udev file descriptor is marked as CLOEXEC */
r = fcntl(udev_monitor_fd, F_GETFD); r = fcntl(udev_monitor_fd, F_GETFD);
if (r == -1) { if (r == -1) {
usbi_err(NULL, "geting udev monitor fd flags (%d)", errno); usbi_err(NULL, "failed to get udev monitor fd flags, errno=%d", errno);
goto err_free_monitor; goto err_free_monitor;
} }
if (!(r & FD_CLOEXEC)) { if (!(r & FD_CLOEXEC)) {
if (fcntl(udev_monitor_fd, F_SETFD, r | FD_CLOEXEC) == -1) { if (fcntl(udev_monitor_fd, F_SETFD, r | FD_CLOEXEC) == -1) {
usbi_err(NULL, "setting udev monitor fd flags (%d)", errno); usbi_err(NULL, "failed to set udev monitor fd flags, errno=%d", errno);
goto err_free_monitor; goto err_free_monitor;
} }
} }
@ -101,33 +90,33 @@ int linux_udev_start_event_monitor(void)
* so make sure this is set */ * so make sure this is set */
r = fcntl(udev_monitor_fd, F_GETFL); r = fcntl(udev_monitor_fd, F_GETFL);
if (r == -1) { if (r == -1) {
usbi_err(NULL, "getting udev monitor fd status flags (%d)", errno); usbi_err(NULL, "failed to get udev monitor fd status flags, errno=%d", errno);
goto err_free_monitor; goto err_free_monitor;
} }
if (!(r & O_NONBLOCK)) { if (!(r & O_NONBLOCK)) {
if (fcntl(udev_monitor_fd, F_SETFL, r | O_NONBLOCK) == -1) { if (fcntl(udev_monitor_fd, F_SETFL, r | O_NONBLOCK) == -1) {
usbi_err(NULL, "setting udev monitor fd status flags (%d)", errno); usbi_err(NULL, "failed to set udev monitor fd status flags, errno=%d", errno);
goto err_free_monitor; goto err_free_monitor;
} }
} }
r = usbi_pipe(udev_control_pipe); r = usbi_create_event(&udev_control_event);
if (r) { if (r) {
usbi_err(NULL, "could not create udev control pipe"); usbi_err(NULL, "failed to create udev control event");
goto err_free_monitor; goto err_free_monitor;
} }
r = pthread_create(&linux_event_thread, NULL, linux_udev_event_thread_main, NULL); r = pthread_create(&linux_event_thread, NULL, linux_udev_event_thread_main, NULL);
if (r) { if (r) {
usbi_err(NULL, "creating hotplug event thread (%d)", r); usbi_err(NULL, "failed to create hotplug event thread (%d)", r);
goto err_close_pipe; goto err_destroy_event;
} }
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
err_close_pipe: err_destroy_event:
close(udev_control_pipe[0]); usbi_destroy_event(&udev_control_event);
close(udev_control_pipe[1]); udev_control_event = (usbi_event_t)USBI_INVALID_EVENT;
err_free_monitor: err_free_monitor:
udev_monitor_unref(udev_monitor); udev_monitor_unref(udev_monitor);
udev_monitor = NULL; udev_monitor = NULL;
@ -141,20 +130,21 @@ err:
int linux_udev_stop_event_monitor(void) int linux_udev_stop_event_monitor(void)
{ {
char dummy = 1;
int r; int r;
assert(udev_ctx != NULL); assert(udev_ctx != NULL);
assert(udev_monitor != NULL); assert(udev_monitor != NULL);
assert(udev_monitor_fd != -1); assert(udev_monitor_fd != -1);
/* Write some dummy data to the control pipe and /* Signal the control event and wait for the thread to exit */
* wait for the thread to exit */ usbi_signal_event(&udev_control_event);
r = write(udev_control_pipe[1], &dummy, sizeof(dummy));
if (r <= 0) { r = pthread_join(linux_event_thread, NULL);
usbi_warn(NULL, "udev control pipe signal failed"); if (r)
} usbi_warn(NULL, "failed to join hotplug event thread (%d)", r);
pthread_join(linux_event_thread, NULL);
usbi_destroy_event(&udev_control_event);
udev_control_event = (usbi_event_t)USBI_INVALID_EVENT;
/* Release the udev monitor */ /* Release the udev monitor */
udev_monitor_unref(udev_monitor); udev_monitor_unref(udev_monitor);
@ -165,44 +155,44 @@ int linux_udev_stop_event_monitor(void)
udev_unref(udev_ctx); udev_unref(udev_ctx);
udev_ctx = NULL; 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; return LIBUSB_SUCCESS;
} }
static void *linux_udev_event_thread_main(void *arg) static void *linux_udev_event_thread_main(void *arg)
{ {
char dummy;
int r;
ssize_t nb;
struct udev_device* udev_dev;
struct pollfd fds[] = { struct pollfd fds[] = {
{.fd = udev_control_pipe[0], { .fd = USBI_EVENT_OS_HANDLE(&udev_control_event),
.events = POLLIN}, .events = USBI_EVENT_POLL_EVENTS },
{ .fd = udev_monitor_fd, { .fd = udev_monitor_fd,
.events = POLLIN }, .events = POLLIN },
}; };
struct udev_device *udev_dev;
int r;
usbi_dbg("udev event thread entering."); UNUSED(arg);
while ((r = poll(fds, 2, -1)) >= 0 || errno == EINTR) { #if defined(HAVE_PTHREAD_SETNAME_NP)
if (r < 0) { r = pthread_setname_np(pthread_self(), "libusb_event");
/* temporary failure */ if (r)
usbi_warn(NULL, "failed to set hotplug event thread name, error=%d", r);
#endif
usbi_dbg("udev event thread entering");
while (1) {
r = poll(fds, 2, -1);
if (r == -1) {
/* check for temporary failure */
if (errno == EINTR)
continue; continue;
} usbi_err(NULL, "poll() failed, errno=%d", errno);
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");
}
break; break;
} }
if (fds[1].revents & POLLIN) { if (fds[0].revents) {
/* activity on control event, exit */
break;
}
if (fds[1].revents) {
usbi_mutex_static_lock(&linux_hotplug_lock); usbi_mutex_static_lock(&linux_hotplug_lock);
udev_dev = udev_monitor_receive_device(udev_monitor); udev_dev = udev_monitor_receive_device(udev_monitor);
if (udev_dev) if (udev_dev)
@ -262,6 +252,8 @@ static void udev_hotplug_event(struct udev_device* udev_dev)
linux_hotplug_enumerate(busnum, devaddr, sys_name); linux_hotplug_enumerate(busnum, devaddr, sys_name);
} else if (detached) { } else if (detached) {
linux_device_disconnected(busnum, devaddr); linux_device_disconnected(busnum, devaddr);
} else if (strncmp(udev_action, "bind", 4) == 0) {
/* silently ignore "known unhandled" action */
} else { } else {
usbi_err(NULL, "ignoring udev action %s", udev_action); usbi_err(NULL, "ignoring udev action %s", udev_action);
} }

File diff suppressed because it is too large Load diff

View file

@ -21,29 +21,20 @@
#ifndef LIBUSB_USBFS_H #ifndef LIBUSB_USBFS_H
#define LIBUSB_USBFS_H #define LIBUSB_USBFS_H
#include <linux/magic.h>
#include <linux/types.h> #include <linux/types.h>
#define SYSFS_DEVICE_PATH "/sys/bus/usb/devices" #define SYSFS_MOUNT_PATH "/sys"
#define SYSFS_DEVICE_PATH SYSFS_MOUNT_PATH "/bus/usb/devices"
struct usbfs_ctrltransfer { struct usbfs_ctrltransfer {
/* keep in sync with usbdevice_fs.h:usbdevfs_ctrltransfer */ /* keep in sync with usbdevice_fs.h:usbdevfs_ctrltransfer */
uint8_t bmRequestType; __u8 bmRequestType;
uint8_t bRequest; __u8 bRequest;
uint16_t wValue; __u16 wValue;
uint16_t wIndex; __u16 wIndex;
uint16_t wLength; __u16 wLength;
__u32 timeout; /* in milliseconds */
uint32_t timeout; /* in milliseconds */
/* pointer to data */
void *data;
};
struct usbfs_bulktransfer {
/* keep in sync with usbdevice_fs.h:usbdevfs_bulktransfer */
unsigned int ep;
unsigned int len;
unsigned int timeout; /* in milliseconds */
/* pointer to data */ /* pointer to data */
void *data; void *data;
@ -68,12 +59,10 @@ struct usbfs_getdriver {
#define USBFS_URB_QUEUE_BULK 0x10 #define USBFS_URB_QUEUE_BULK 0x10
#define USBFS_URB_ZERO_PACKET 0x40 #define USBFS_URB_ZERO_PACKET 0x40
enum usbfs_urb_type { #define USBFS_URB_TYPE_ISO 0
USBFS_URB_TYPE_ISO = 0, #define USBFS_URB_TYPE_INTERRUPT 1
USBFS_URB_TYPE_INTERRUPT = 1, #define USBFS_URB_TYPE_CONTROL 2
USBFS_URB_TYPE_CONTROL = 2, #define USBFS_URB_TYPE_BULK 3
USBFS_URB_TYPE_BULK = 3,
};
struct usbfs_iso_packet_desc { struct usbfs_iso_packet_desc {
unsigned int length; unsigned int length;
@ -117,11 +106,6 @@ struct usbfs_ioctl {
void *data; /* param buffer (in, or out) */ void *data; /* param buffer (in, or out) */
}; };
struct usbfs_hub_portinfo {
unsigned char numports;
unsigned char port[127]; /* port to device num mapping */
};
#define USBFS_CAP_ZERO_PACKET 0x01 #define USBFS_CAP_ZERO_PACKET 0x01
#define USBFS_CAP_BULK_CONTINUATION 0x02 #define USBFS_CAP_BULK_CONTINUATION 0x02
#define USBFS_CAP_NO_PACKET_SIZE_LIM 0x04 #define USBFS_CAP_NO_PACKET_SIZE_LIM 0x04
@ -143,35 +127,39 @@ struct usbfs_streams {
unsigned char eps[0]; 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_CONTROL _IOWR('U', 0, struct usbfs_ctrltransfer)
#define IOCTL_USBFS_BULK _IOWR('U', 2, struct usbfs_bulktransfer) #define IOCTL_USBFS_SETINTERFACE _IOR('U', 4, struct usbfs_setinterface)
#define IOCTL_USBFS_RESETEP _IOR('U', 3, unsigned int) #define IOCTL_USBFS_SETCONFIGURATION _IOR('U', 5, unsigned int)
#define IOCTL_USBFS_SETINTF _IOR('U', 4, struct usbfs_setinterface)
#define IOCTL_USBFS_SETCONFIG _IOR('U', 5, unsigned int)
#define IOCTL_USBFS_GETDRIVER _IOW('U', 8, struct usbfs_getdriver) #define IOCTL_USBFS_GETDRIVER _IOW('U', 8, struct usbfs_getdriver)
#define IOCTL_USBFS_SUBMITURB _IOR('U', 10, struct usbfs_urb) #define IOCTL_USBFS_SUBMITURB _IOR('U', 10, struct usbfs_urb)
#define IOCTL_USBFS_DISCARDURB _IO('U', 11) #define IOCTL_USBFS_DISCARDURB _IO('U', 11)
#define IOCTL_USBFS_REAPURB _IOW('U', 12, void *)
#define IOCTL_USBFS_REAPURBNDELAY _IOW('U', 13, void *) #define IOCTL_USBFS_REAPURBNDELAY _IOW('U', 13, void *)
#define IOCTL_USBFS_CLAIMINTF _IOR('U', 15, unsigned int) #define IOCTL_USBFS_CLAIMINTERFACE _IOR('U', 15, unsigned int)
#define IOCTL_USBFS_RELEASEINTF _IOR('U', 16, unsigned int) #define IOCTL_USBFS_RELEASEINTERFACE _IOR('U', 16, unsigned int)
#define IOCTL_USBFS_CONNECTINFO _IOW('U', 17, struct usbfs_connectinfo) #define IOCTL_USBFS_CONNECTINFO _IOW('U', 17, struct usbfs_connectinfo)
#define IOCTL_USBFS_IOCTL _IOWR('U', 18, struct usbfs_ioctl) #define IOCTL_USBFS_IOCTL _IOWR('U', 18, struct usbfs_ioctl)
#define IOCTL_USBFS_HUB_PORTINFO _IOR('U', 19, struct usbfs_hub_portinfo)
#define IOCTL_USBFS_RESET _IO('U', 20) #define IOCTL_USBFS_RESET _IO('U', 20)
#define IOCTL_USBFS_CLEAR_HALT _IOR('U', 21, unsigned int) #define IOCTL_USBFS_CLEAR_HALT _IOR('U', 21, unsigned int)
#define IOCTL_USBFS_DISCONNECT _IO('U', 22) #define IOCTL_USBFS_DISCONNECT _IO('U', 22)
#define IOCTL_USBFS_CONNECT _IO('U', 23) #define IOCTL_USBFS_CONNECT _IO('U', 23)
#define IOCTL_USBFS_CLAIM_PORT _IOR('U', 24, unsigned int)
#define IOCTL_USBFS_RELEASE_PORT _IOR('U', 25, unsigned int)
#define IOCTL_USBFS_GET_CAPABILITIES _IOR('U', 26, __u32) #define IOCTL_USBFS_GET_CAPABILITIES _IOR('U', 26, __u32)
#define IOCTL_USBFS_DISCONNECT_CLAIM _IOR('U', 27, struct usbfs_disconnect_claim) #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_ALLOC_STREAMS _IOR('U', 28, struct usbfs_streams)
#define IOCTL_USBFS_FREE_STREAMS _IOR('U', 29, 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; extern usbi_mutex_static_t linux_hotplug_lock;
#if defined(HAVE_LIBUDEV) #ifdef HAVE_LIBUDEV
int linux_udev_start_event_monitor(void); int linux_udev_start_event_monitor(void);
int linux_udev_stop_event_monitor(void); int linux_udev_stop_event_monitor(void);
int linux_udev_scan_devices(struct libusb_context *ctx); int linux_udev_scan_devices(struct libusb_context *ctx);
@ -182,6 +170,35 @@ int linux_netlink_stop_event_monitor(void);
void linux_netlink_hotplug_poll(void); void linux_netlink_hotplug_poll(void);
#endif #endif
static inline int linux_start_event_monitor(void)
{
#if defined(HAVE_LIBUDEV)
return linux_udev_start_event_monitor();
#elif !defined(__ANDROID__)
return linux_netlink_start_event_monitor();
#else
return LIBUSB_SUCCESS;
#endif
}
static inline void linux_stop_event_monitor(void)
{
#if defined(HAVE_LIBUDEV)
linux_udev_stop_event_monitor();
#elif !defined(__ANDROID__)
linux_netlink_stop_event_monitor();
#endif
}
static inline void linux_hotplug_poll(void)
{
#if defined(HAVE_LIBUDEV)
linux_udev_hotplug_poll();
#elif !defined(__ANDROID__)
linux_netlink_hotplug_poll();
#endif
}
void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_name); void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_name);
void linux_device_disconnected(uint8_t busnum, uint8_t devaddr); void linux_device_disconnected(uint8_t busnum, uint8_t devaddr);

View file

@ -36,8 +36,7 @@ struct device_priv {
char devnode[16]; char devnode[16];
int fd; int fd;
unsigned char *cdesc; /* active config descriptor */ usb_config_descriptor_t *cdesc; /* active config descriptor */
usb_device_descriptor_t ddesc; /* usb device descriptor */
}; };
struct handle_priv { struct handle_priv {
@ -52,30 +51,25 @@ static int netbsd_get_device_list(struct libusb_context *,
static int netbsd_open(struct libusb_device_handle *); static int netbsd_open(struct libusb_device_handle *);
static void netbsd_close(struct libusb_device_handle *); static void netbsd_close(struct libusb_device_handle *);
static int netbsd_get_device_descriptor(struct libusb_device *, unsigned char *,
int *);
static int netbsd_get_active_config_descriptor(struct libusb_device *, static int netbsd_get_active_config_descriptor(struct libusb_device *,
unsigned char *, size_t, int *); void *, size_t);
static int netbsd_get_config_descriptor(struct libusb_device *, uint8_t, static int netbsd_get_config_descriptor(struct libusb_device *, uint8_t,
unsigned char *, size_t, int *); void *, size_t);
static int netbsd_get_configuration(struct libusb_device_handle *, int *); static int netbsd_get_configuration(struct libusb_device_handle *, uint8_t *);
static int netbsd_set_configuration(struct libusb_device_handle *, int); static int netbsd_set_configuration(struct libusb_device_handle *, int);
static int netbsd_claim_interface(struct libusb_device_handle *, int); static int netbsd_claim_interface(struct libusb_device_handle *, uint8_t);
static int netbsd_release_interface(struct libusb_device_handle *, int); static int netbsd_release_interface(struct libusb_device_handle *, uint8_t);
static int netbsd_set_interface_altsetting(struct libusb_device_handle *, int, static int netbsd_set_interface_altsetting(struct libusb_device_handle *,
int); uint8_t, uint8_t);
static int netbsd_clear_halt(struct libusb_device_handle *, unsigned char); static int netbsd_clear_halt(struct libusb_device_handle *, unsigned char);
static int netbsd_reset_device(struct libusb_device_handle *);
static void netbsd_destroy_device(struct libusb_device *); static void netbsd_destroy_device(struct libusb_device *);
static int netbsd_submit_transfer(struct usbi_transfer *); static int netbsd_submit_transfer(struct usbi_transfer *);
static int netbsd_cancel_transfer(struct usbi_transfer *); static int netbsd_cancel_transfer(struct usbi_transfer *);
static void netbsd_clear_transfer_priv(struct usbi_transfer *);
static int netbsd_handle_transfer_completion(struct usbi_transfer *); static int netbsd_handle_transfer_completion(struct usbi_transfer *);
static int netbsd_clock_gettime(int, struct timespec *);
/* /*
* Private functions * Private functions
@ -87,55 +81,33 @@ static int _sync_gen_transfer(struct usbi_transfer *);
static int _access_endpoint(struct libusb_transfer *); static int _access_endpoint(struct libusb_transfer *);
const struct usbi_os_backend usbi_backend = { const struct usbi_os_backend usbi_backend = {
"Synchronous NetBSD backend", .name = "Synchronous NetBSD backend",
0, .caps = 0,
NULL, /* init() */ .get_device_list = netbsd_get_device_list,
NULL, /* exit() */ .open = netbsd_open,
NULL, /* set_option() */ .close = netbsd_close,
netbsd_get_device_list,
NULL, /* hotplug_poll */
netbsd_open,
netbsd_close,
netbsd_get_device_descriptor, .get_active_config_descriptor = netbsd_get_active_config_descriptor,
netbsd_get_active_config_descriptor, .get_config_descriptor = netbsd_get_config_descriptor,
netbsd_get_config_descriptor,
NULL, /* get_config_descriptor_by_value() */
netbsd_get_configuration, .get_configuration = netbsd_get_configuration,
netbsd_set_configuration, .set_configuration = netbsd_set_configuration,
netbsd_claim_interface, .claim_interface = netbsd_claim_interface,
netbsd_release_interface, .release_interface = netbsd_release_interface,
netbsd_set_interface_altsetting, .set_interface_altsetting = netbsd_set_interface_altsetting,
netbsd_clear_halt, .clear_halt = netbsd_clear_halt,
netbsd_reset_device,
NULL, /* alloc_streams */ .destroy_device = netbsd_destroy_device,
NULL, /* free_streams */
NULL, /* dev_mem_alloc() */ .submit_transfer = netbsd_submit_transfer,
NULL, /* dev_mem_free() */ .cancel_transfer = netbsd_cancel_transfer,
NULL, /* kernel_driver_active() */ .handle_transfer_completion = netbsd_handle_transfer_completion,
NULL, /* detach_kernel_driver() */
NULL, /* attach_kernel_driver() */
netbsd_destroy_device, .device_priv_size = sizeof(struct device_priv),
.device_handle_priv_size = sizeof(struct handle_priv),
netbsd_submit_transfer,
netbsd_cancel_transfer,
netbsd_clear_transfer_priv,
NULL, /* handle_events() */
netbsd_handle_transfer_completion,
netbsd_clock_gettime,
0, /* context_priv_size */
sizeof(struct device_priv),
sizeof(struct handle_priv),
0, /* transfer_priv_size */
}; };
int int
@ -145,6 +117,7 @@ netbsd_get_device_list(struct libusb_context * ctx,
struct libusb_device *dev; struct libusb_device *dev;
struct device_priv *dpriv; struct device_priv *dpriv;
struct usb_device_info di; struct usb_device_info di;
usb_device_descriptor_t ddesc;
unsigned long session_id; unsigned long session_id;
char devnode[16]; char devnode[16];
int fd, err, i; int fd, err, i;
@ -177,16 +150,20 @@ netbsd_get_device_list(struct libusb_context * ctx,
dev->device_address = di.udi_addr; dev->device_address = di.udi_addr;
dev->speed = di.udi_speed; dev->speed = di.udi_speed;
dpriv = (struct device_priv *)dev->os_priv; dpriv = usbi_get_device_priv(dev);
strlcpy(dpriv->devnode, devnode, sizeof(devnode)); strlcpy(dpriv->devnode, devnode, sizeof(devnode));
dpriv->fd = -1; dpriv->fd = -1;
if (ioctl(fd, USB_GET_DEVICE_DESC, &dpriv->ddesc) < 0) { if (ioctl(fd, USB_GET_DEVICE_DESC, &ddesc) < 0) {
err = errno; err = errno;
goto error; goto error;
} }
dpriv->cdesc = NULL; static_assert(sizeof(dev->device_descriptor) == sizeof(ddesc),
"mismatch between libusb and OS device descriptor sizes");
memcpy(&dev->device_descriptor, &ddesc, LIBUSB_DT_DEVICE_SIZE);
usbi_localize_device_descriptor(&dev->device_descriptor);
if (_cache_active_config_descriptor(dev, fd)) { if (_cache_active_config_descriptor(dev, fd)) {
err = errno; err = errno;
goto error; goto error;
@ -214,8 +191,8 @@ error:
int int
netbsd_open(struct libusb_device_handle *handle) netbsd_open(struct libusb_device_handle *handle)
{ {
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
int i; int i;
dpriv->fd = open(dpriv->devnode, O_RDWR); dpriv->fd = open(dpriv->devnode, O_RDWR);
@ -236,7 +213,7 @@ netbsd_open(struct libusb_device_handle *handle)
void void
netbsd_close(struct libusb_device_handle *handle) netbsd_close(struct libusb_device_handle *handle)
{ {
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
usbi_dbg("close: fd %d", dpriv->fd); usbi_dbg("close: fd %d", dpriv->fd);
@ -244,49 +221,30 @@ netbsd_close(struct libusb_device_handle *handle)
dpriv->fd = -1; dpriv->fd = -1;
} }
int
netbsd_get_device_descriptor(struct libusb_device *dev, unsigned char *buf,
int *host_endian)
{
struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
usbi_dbg("");
memcpy(buf, &dpriv->ddesc, DEVICE_DESC_LENGTH);
*host_endian = 0;
return (LIBUSB_SUCCESS);
}
int int
netbsd_get_active_config_descriptor(struct libusb_device *dev, netbsd_get_active_config_descriptor(struct libusb_device *dev,
unsigned char *buf, size_t len, int *host_endian) void *buf, size_t len)
{ {
struct device_priv *dpriv = (struct device_priv *)dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(dev);
usb_config_descriptor_t *ucd;
ucd = (usb_config_descriptor_t *) dpriv->cdesc; len = MIN(len, (size_t)UGETW(dpriv->cdesc->wTotalLength));
len = MIN(len, UGETW(ucd->wTotalLength));
usbi_dbg("len %d", len); usbi_dbg("len %zu", len);
memcpy(buf, dpriv->cdesc, len); memcpy(buf, dpriv->cdesc, len);
*host_endian = 0; return (int)len;
return len;
} }
int int
netbsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx, netbsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
unsigned char *buf, size_t len, int *host_endian) void *buf, size_t len)
{ {
struct device_priv *dpriv = (struct device_priv *)dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(dev);
struct usb_full_desc ufd; struct usb_full_desc ufd;
int fd, err; int fd, err;
usbi_dbg("index %d, len %d", idx, len); usbi_dbg("index %u, len %zu", idx, len);
/* A config descriptor may be requested before opening the device */ /* A config descriptor may be requested before opening the device */
if (dpriv->fd >= 0) { if (dpriv->fd >= 0) {
@ -311,22 +269,22 @@ netbsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
if (dpriv->fd < 0) if (dpriv->fd < 0)
close(fd); close(fd);
*host_endian = 0; return (int)len;
return len;
} }
int int
netbsd_get_configuration(struct libusb_device_handle *handle, int *config) netbsd_get_configuration(struct libusb_device_handle *handle, uint8_t *config)
{ {
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
int tmp;
usbi_dbg(" "); usbi_dbg(" ");
if (ioctl(dpriv->fd, USB_GET_CONFIG, config) < 0) if (ioctl(dpriv->fd, USB_GET_CONFIG, &tmp) < 0)
return _errno_to_libusb(errno); return _errno_to_libusb(errno);
usbi_dbg("configuration %d", *config); usbi_dbg("configuration %d", tmp);
*config = (uint8_t)tmp;
return (LIBUSB_SUCCESS); return (LIBUSB_SUCCESS);
} }
@ -334,7 +292,7 @@ netbsd_get_configuration(struct libusb_device_handle *handle, int *config)
int int
netbsd_set_configuration(struct libusb_device_handle *handle, int config) netbsd_set_configuration(struct libusb_device_handle *handle, int config)
{ {
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
usbi_dbg("configuration %d", config); usbi_dbg("configuration %d", config);
@ -345,11 +303,13 @@ netbsd_set_configuration(struct libusb_device_handle *handle, int config)
} }
int int
netbsd_claim_interface(struct libusb_device_handle *handle, int iface) netbsd_claim_interface(struct libusb_device_handle *handle, uint8_t iface)
{ {
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
int i; int i;
UNUSED(iface);
for (i = 0; i < USB_MAX_ENDPOINTS; i++) for (i = 0; i < USB_MAX_ENDPOINTS; i++)
hpriv->endpoints[i] = -1; hpriv->endpoints[i] = -1;
@ -357,11 +317,13 @@ netbsd_claim_interface(struct libusb_device_handle *handle, int iface)
} }
int int
netbsd_release_interface(struct libusb_device_handle *handle, int iface) netbsd_release_interface(struct libusb_device_handle *handle, uint8_t iface)
{ {
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
int i; int i;
UNUSED(iface);
for (i = 0; i < USB_MAX_ENDPOINTS; i++) for (i = 0; i < USB_MAX_ENDPOINTS; i++)
if (hpriv->endpoints[i] >= 0) if (hpriv->endpoints[i] >= 0)
close(hpriv->endpoints[i]); close(hpriv->endpoints[i]);
@ -370,13 +332,13 @@ netbsd_release_interface(struct libusb_device_handle *handle, int iface)
} }
int int
netbsd_set_interface_altsetting(struct libusb_device_handle *handle, int iface, netbsd_set_interface_altsetting(struct libusb_device_handle *handle, uint8_t iface,
int altsetting) uint8_t altsetting)
{ {
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
struct usb_alt_interface intf; struct usb_alt_interface intf;
usbi_dbg("iface %d, setting %d", iface, altsetting); usbi_dbg("iface %u, setting %u", iface, altsetting);
memset(&intf, 0, sizeof(intf)); memset(&intf, 0, sizeof(intf));
@ -392,7 +354,7 @@ netbsd_set_interface_altsetting(struct libusb_device_handle *handle, int iface,
int int
netbsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint) netbsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
{ {
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
struct usb_ctl_request req; struct usb_ctl_request req;
usbi_dbg(" "); usbi_dbg(" ");
@ -409,18 +371,10 @@ netbsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
return (LIBUSB_SUCCESS); return (LIBUSB_SUCCESS);
} }
int
netbsd_reset_device(struct libusb_device_handle *handle)
{
usbi_dbg("");
return (LIBUSB_ERROR_NOT_SUPPORTED);
}
void void
netbsd_destroy_device(struct libusb_device *dev) netbsd_destroy_device(struct libusb_device *dev)
{ {
struct device_priv *dpriv = (struct device_priv *)dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(dev);
usbi_dbg(" "); usbi_dbg(" ");
@ -431,13 +385,11 @@ int
netbsd_submit_transfer(struct usbi_transfer *itransfer) netbsd_submit_transfer(struct usbi_transfer *itransfer)
{ {
struct libusb_transfer *transfer; struct libusb_transfer *transfer;
struct handle_priv *hpriv;
int err = 0; int err = 0;
usbi_dbg(" "); usbi_dbg(" ");
transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
hpriv = (struct handle_priv *)transfer->dev_handle->os_priv;
switch (transfer->type) { switch (transfer->type) {
case LIBUSB_TRANSFER_TYPE_CONTROL: case LIBUSB_TRANSFER_TYPE_CONTROL:
@ -476,39 +428,19 @@ netbsd_submit_transfer(struct usbi_transfer *itransfer)
int int
netbsd_cancel_transfer(struct usbi_transfer *itransfer) netbsd_cancel_transfer(struct usbi_transfer *itransfer)
{ {
UNUSED(itransfer);
usbi_dbg(" "); usbi_dbg(" ");
return (LIBUSB_ERROR_NOT_SUPPORTED); return (LIBUSB_ERROR_NOT_SUPPORTED);
} }
void
netbsd_clear_transfer_priv(struct usbi_transfer *itransfer)
{
usbi_dbg("");
/* Nothing to do */
}
int int
netbsd_handle_transfer_completion(struct usbi_transfer *itransfer) netbsd_handle_transfer_completion(struct usbi_transfer *itransfer)
{ {
return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED); return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
} }
int
netbsd_clock_gettime(int clkid, struct timespec *tp)
{
usbi_dbg("clock %d", clkid);
if (clkid == USBI_CLOCK_REALTIME)
return clock_gettime(CLOCK_REALTIME, tp);
if (clkid == USBI_CLOCK_MONOTONIC)
return clock_gettime(CLOCK_MONOTONIC, tp);
return (LIBUSB_ERROR_INVALID_PARAM);
}
int int
_errno_to_libusb(int err) _errno_to_libusb(int err)
{ {
@ -521,6 +453,9 @@ _errno_to_libusb(int err)
return (LIBUSB_ERROR_NO_DEVICE); return (LIBUSB_ERROR_NO_DEVICE);
case ENOMEM: case ENOMEM:
return (LIBUSB_ERROR_NO_MEM); return (LIBUSB_ERROR_NO_MEM);
case EWOULDBLOCK:
case ETIMEDOUT:
return (LIBUSB_ERROR_TIMEOUT);
} }
usbi_dbg("error: %s", strerror(err)); usbi_dbg("error: %s", strerror(err));
@ -531,10 +466,10 @@ _errno_to_libusb(int err)
int int
_cache_active_config_descriptor(struct libusb_device *dev, int fd) _cache_active_config_descriptor(struct libusb_device *dev, int fd)
{ {
struct device_priv *dpriv = (struct device_priv *)dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(dev);
struct usb_config_desc ucd; struct usb_config_desc ucd;
struct usb_full_desc ufd; struct usb_full_desc ufd;
unsigned char* buf; void *buf;
int len; int len;
usbi_dbg("fd %d", fd); usbi_dbg("fd %d", fd);
@ -547,7 +482,7 @@ _cache_active_config_descriptor(struct libusb_device *dev, int fd)
usbi_dbg("active bLength %d", ucd.ucd_desc.bLength); usbi_dbg("active bLength %d", ucd.ucd_desc.bLength);
len = UGETW(ucd.ucd_desc.wTotalLength); len = UGETW(ucd.ucd_desc.wTotalLength);
buf = malloc(len); buf = malloc((size_t)len);
if (buf == NULL) if (buf == NULL)
return (LIBUSB_ERROR_NO_MEM); return (LIBUSB_ERROR_NO_MEM);
@ -578,7 +513,7 @@ _sync_control_transfer(struct usbi_transfer *itransfer)
struct usb_ctl_request req; struct usb_ctl_request req;
transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv; dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
setup = (struct libusb_control_setup *)transfer->buffer; setup = (struct libusb_control_setup *)transfer->buffer;
usbi_dbg("type %d request %d value %d index %d length %d timeout %d", usbi_dbg("type %d request %d value %d index %d length %d timeout %d",
@ -620,8 +555,8 @@ _access_endpoint(struct libusb_transfer *transfer)
int fd, endpt; int fd, endpt;
mode_t mode; mode_t mode;
hpriv = (struct handle_priv *)transfer->dev_handle->os_priv; hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv; dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
endpt = UE_GET_ADDR(transfer->endpoint); endpt = UE_GET_ADDR(transfer->endpoint);
mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY; mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY;

111
externals/libusb/libusb/libusb/os/null_usb.c vendored Executable file
View file

@ -0,0 +1,111 @@
/*
* Copyright © 2019 Pino Toscano <toscano.pino@tiscali.it>
*
* 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"
static int
null_get_device_list(struct libusb_context * ctx,
struct discovered_devs **discdevs)
{
return LIBUSB_SUCCESS;
}
static int
null_open(struct libusb_device_handle *handle)
{
return LIBUSB_ERROR_NOT_SUPPORTED;
}
static void
null_close(struct libusb_device_handle *handle)
{
}
static int
null_get_active_config_descriptor(struct libusb_device *dev,
void *buf, size_t len)
{
return LIBUSB_ERROR_NOT_SUPPORTED;
}
static int
null_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
void *buf, size_t len)
{
return LIBUSB_ERROR_NOT_SUPPORTED;
}
static int
null_set_configuration(struct libusb_device_handle *handle, int config)
{
return LIBUSB_ERROR_NOT_SUPPORTED;
}
static int
null_claim_interface(struct libusb_device_handle *handle, uint8_t iface)
{
return LIBUSB_ERROR_NOT_SUPPORTED;
}
static int
null_release_interface(struct libusb_device_handle *handle, uint8_t iface)
{
return LIBUSB_ERROR_NOT_SUPPORTED;
}
static int
null_set_interface_altsetting(struct libusb_device_handle *handle, uint8_t iface,
uint8_t altsetting)
{
return LIBUSB_ERROR_NOT_SUPPORTED;
}
static int
null_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
{
return LIBUSB_ERROR_NOT_SUPPORTED;
}
static int
null_submit_transfer(struct usbi_transfer *itransfer)
{
return LIBUSB_ERROR_NOT_SUPPORTED;
}
static int
null_cancel_transfer(struct usbi_transfer *itransfer)
{
return LIBUSB_ERROR_NOT_SUPPORTED;
}
const struct usbi_os_backend usbi_backend = {
.name = "Null backend",
.caps = 0,
.get_device_list = null_get_device_list,
.open = null_open,
.close = null_close,
.get_active_config_descriptor = null_get_active_config_descriptor,
.get_config_descriptor = null_get_config_descriptor,
.set_configuration = null_set_configuration,
.claim_interface = null_claim_interface,
.release_interface = null_release_interface,
.set_interface_altsetting = null_set_interface_altsetting,
.clear_halt = null_clear_halt,
.submit_transfer = null_submit_transfer,
.cancel_transfer = null_cancel_transfer,
};

View file

@ -36,8 +36,7 @@ struct device_priv {
char *devname; /* name of the ugen(4) node */ char *devname; /* name of the ugen(4) node */
int fd; /* device file descriptor */ int fd; /* device file descriptor */
unsigned char *cdesc; /* active config descriptor */ usb_config_descriptor_t *cdesc; /* active config descriptor */
usb_device_descriptor_t ddesc; /* usb device descriptor */
}; };
struct handle_priv { struct handle_priv {
@ -52,30 +51,25 @@ static int obsd_get_device_list(struct libusb_context *,
static int obsd_open(struct libusb_device_handle *); static int obsd_open(struct libusb_device_handle *);
static void obsd_close(struct libusb_device_handle *); static void obsd_close(struct libusb_device_handle *);
static int obsd_get_device_descriptor(struct libusb_device *, unsigned char *,
int *);
static int obsd_get_active_config_descriptor(struct libusb_device *, static int obsd_get_active_config_descriptor(struct libusb_device *,
unsigned char *, size_t, int *); void *, size_t);
static int obsd_get_config_descriptor(struct libusb_device *, uint8_t, static int obsd_get_config_descriptor(struct libusb_device *, uint8_t,
unsigned char *, size_t, int *); void *, size_t);
static int obsd_get_configuration(struct libusb_device_handle *, int *); static int obsd_get_configuration(struct libusb_device_handle *, uint8_t *);
static int obsd_set_configuration(struct libusb_device_handle *, int); static int obsd_set_configuration(struct libusb_device_handle *, int);
static int obsd_claim_interface(struct libusb_device_handle *, int); static int obsd_claim_interface(struct libusb_device_handle *, uint8_t);
static int obsd_release_interface(struct libusb_device_handle *, int); static int obsd_release_interface(struct libusb_device_handle *, uint8_t);
static int obsd_set_interface_altsetting(struct libusb_device_handle *, int, static int obsd_set_interface_altsetting(struct libusb_device_handle *, uint8_t,
int); uint8_t);
static int obsd_clear_halt(struct libusb_device_handle *, unsigned char); static int obsd_clear_halt(struct libusb_device_handle *, unsigned char);
static int obsd_reset_device(struct libusb_device_handle *);
static void obsd_destroy_device(struct libusb_device *); static void obsd_destroy_device(struct libusb_device *);
static int obsd_submit_transfer(struct usbi_transfer *); static int obsd_submit_transfer(struct usbi_transfer *);
static int obsd_cancel_transfer(struct usbi_transfer *); static int obsd_cancel_transfer(struct usbi_transfer *);
static void obsd_clear_transfer_priv(struct usbi_transfer *);
static int obsd_handle_transfer_completion(struct usbi_transfer *); static int obsd_handle_transfer_completion(struct usbi_transfer *);
static int obsd_clock_gettime(int, struct timespec *);
/* /*
* Private functions * Private functions
@ -95,7 +89,6 @@ const struct usbi_os_backend usbi_backend = {
.open = obsd_open, .open = obsd_open,
.close = obsd_close, .close = obsd_close,
.get_device_descriptor = obsd_get_device_descriptor,
.get_active_config_descriptor = obsd_get_active_config_descriptor, .get_active_config_descriptor = obsd_get_active_config_descriptor,
.get_config_descriptor = obsd_get_config_descriptor, .get_config_descriptor = obsd_get_config_descriptor,
@ -107,16 +100,13 @@ const struct usbi_os_backend usbi_backend = {
.set_interface_altsetting = obsd_set_interface_altsetting, .set_interface_altsetting = obsd_set_interface_altsetting,
.clear_halt = obsd_clear_halt, .clear_halt = obsd_clear_halt,
.reset_device = obsd_reset_device,
.destroy_device = obsd_destroy_device, .destroy_device = obsd_destroy_device,
.submit_transfer = obsd_submit_transfer, .submit_transfer = obsd_submit_transfer,
.cancel_transfer = obsd_cancel_transfer, .cancel_transfer = obsd_cancel_transfer,
.clear_transfer_priv = obsd_clear_transfer_priv,
.handle_transfer_completion = obsd_handle_transfer_completion, .handle_transfer_completion = obsd_handle_transfer_completion,
.clock_gettime = obsd_clock_gettime,
.device_priv_size = sizeof(struct device_priv), .device_priv_size = sizeof(struct device_priv),
.device_handle_priv_size = sizeof(struct handle_priv), .device_handle_priv_size = sizeof(struct handle_priv),
}; };
@ -183,10 +173,10 @@ obsd_get_device_list(struct libusb_context * ctx,
dev->bus_number = di.udi_bus; dev->bus_number = di.udi_bus;
dev->device_address = di.udi_addr; dev->device_address = di.udi_addr;
dev->speed = di.udi_speed; dev->speed = di.udi_speed;
dev->port_number = di.udi_port;
dpriv = (struct device_priv *)dev->os_priv; dpriv = usbi_get_device_priv(dev);
dpriv->fd = -1; dpriv->fd = -1;
dpriv->cdesc = NULL;
dpriv->devname = udevname; dpriv->devname = udevname;
dd.udd_bus = di.udi_bus; dd.udd_bus = di.udi_bus;
@ -195,7 +185,11 @@ obsd_get_device_list(struct libusb_context * ctx,
libusb_unref_device(dev); libusb_unref_device(dev);
continue; continue;
} }
dpriv->ddesc = dd.udd_desc;
static_assert(sizeof(dev->device_descriptor) == sizeof(dd.udd_desc),
"mismatch between libusb and OS device descriptor sizes");
memcpy(&dev->device_descriptor, &dd.udd_desc, LIBUSB_DT_DEVICE_SIZE);
usbi_localize_device_descriptor(&dev->device_descriptor);
if (_cache_active_config_descriptor(dev)) { if (_cache_active_config_descriptor(dev)) {
libusb_unref_device(dev); libusb_unref_device(dev);
@ -228,19 +222,21 @@ obsd_get_device_list(struct libusb_context * ctx,
int int
obsd_open(struct libusb_device_handle *handle) obsd_open(struct libusb_device_handle *handle)
{ {
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
char devnode[16]; char devnode[16];
if (dpriv->devname) { if (dpriv->devname) {
int fd;
/* /*
* Only open ugen(4) attached devices read-write, all * Only open ugen(4) attached devices read-write, all
* read-only operations are done through the bus node. * read-only operations are done through the bus node.
*/ */
snprintf(devnode, sizeof(devnode), DEVPATH "%s.00", snprintf(devnode, sizeof(devnode), DEVPATH "%s.00",
dpriv->devname); dpriv->devname);
dpriv->fd = open(devnode, O_RDWR); fd = open(devnode, O_RDWR);
if (dpriv->fd < 0) if (fd < 0)
return _errno_to_libusb(errno); return _errno_to_libusb(errno);
dpriv->fd = fd;
usbi_dbg("open %s: fd %d", devnode, dpriv->fd); usbi_dbg("open %s: fd %d", devnode, dpriv->fd);
} }
@ -251,7 +247,7 @@ obsd_open(struct libusb_device_handle *handle)
void void
obsd_close(struct libusb_device_handle *handle) obsd_close(struct libusb_device_handle *handle)
{ {
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
if (dpriv->devname) { if (dpriv->devname) {
usbi_dbg("close: fd %d", dpriv->fd); usbi_dbg("close: fd %d", dpriv->fd);
@ -261,42 +257,24 @@ obsd_close(struct libusb_device_handle *handle)
} }
} }
int
obsd_get_device_descriptor(struct libusb_device *dev, unsigned char *buf,
int *host_endian)
{
struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
usbi_dbg("");
memcpy(buf, &dpriv->ddesc, DEVICE_DESC_LENGTH);
*host_endian = 0;
return (LIBUSB_SUCCESS);
}
int int
obsd_get_active_config_descriptor(struct libusb_device *dev, obsd_get_active_config_descriptor(struct libusb_device *dev,
unsigned char *buf, size_t len, int *host_endian) void *buf, size_t len)
{ {
struct device_priv *dpriv = (struct device_priv *)dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(dev);
usb_config_descriptor_t *ucd = (usb_config_descriptor_t *)dpriv->cdesc;
len = MIN(len, UGETW(ucd->wTotalLength)); len = MIN(len, (size_t)UGETW(dpriv->cdesc->wTotalLength));
usbi_dbg("len %zu", len); usbi_dbg("len %zu", len);
memcpy(buf, dpriv->cdesc, len); memcpy(buf, dpriv->cdesc, len);
*host_endian = 0; return ((int)len);
return (len);
} }
int int
obsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx, obsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
unsigned char *buf, size_t len, int *host_endian) void *buf, size_t len)
{ {
struct usb_device_fdesc udf; struct usb_device_fdesc udf;
int fd, err; int fd, err;
@ -319,20 +297,17 @@ obsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
} }
close(fd); close(fd);
*host_endian = 0; return ((int)len);
return (len);
} }
int int
obsd_get_configuration(struct libusb_device_handle *handle, int *config) obsd_get_configuration(struct libusb_device_handle *handle, uint8_t *config)
{ {
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
usb_config_descriptor_t *ucd = (usb_config_descriptor_t *)dpriv->cdesc;
*config = ucd->bConfigurationValue; *config = dpriv->cdesc->bConfigurationValue;
usbi_dbg("bConfigurationValue %d", *config); usbi_dbg("bConfigurationValue %u", *config);
return (LIBUSB_SUCCESS); return (LIBUSB_SUCCESS);
} }
@ -340,7 +315,7 @@ obsd_get_configuration(struct libusb_device_handle *handle, int *config)
int int
obsd_set_configuration(struct libusb_device_handle *handle, int config) obsd_set_configuration(struct libusb_device_handle *handle, int config)
{ {
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
if (dpriv->devname == NULL) if (dpriv->devname == NULL)
return (LIBUSB_ERROR_NOT_SUPPORTED); return (LIBUSB_ERROR_NOT_SUPPORTED);
@ -354,11 +329,13 @@ obsd_set_configuration(struct libusb_device_handle *handle, int config)
} }
int int
obsd_claim_interface(struct libusb_device_handle *handle, int iface) obsd_claim_interface(struct libusb_device_handle *handle, uint8_t iface)
{ {
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
int i; int i;
UNUSED(iface);
for (i = 0; i < USB_MAX_ENDPOINTS; i++) for (i = 0; i < USB_MAX_ENDPOINTS; i++)
hpriv->endpoints[i] = -1; hpriv->endpoints[i] = -1;
@ -366,11 +343,13 @@ obsd_claim_interface(struct libusb_device_handle *handle, int iface)
} }
int int
obsd_release_interface(struct libusb_device_handle *handle, int iface) obsd_release_interface(struct libusb_device_handle *handle, uint8_t iface)
{ {
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
int i; int i;
UNUSED(iface);
for (i = 0; i < USB_MAX_ENDPOINTS; i++) for (i = 0; i < USB_MAX_ENDPOINTS; i++)
if (hpriv->endpoints[i] >= 0) if (hpriv->endpoints[i] >= 0)
close(hpriv->endpoints[i]); close(hpriv->endpoints[i]);
@ -379,16 +358,16 @@ obsd_release_interface(struct libusb_device_handle *handle, int iface)
} }
int int
obsd_set_interface_altsetting(struct libusb_device_handle *handle, int iface, obsd_set_interface_altsetting(struct libusb_device_handle *handle, uint8_t iface,
int altsetting) uint8_t altsetting)
{ {
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
struct usb_alt_interface intf; struct usb_alt_interface intf;
if (dpriv->devname == NULL) if (dpriv->devname == NULL)
return (LIBUSB_ERROR_NOT_SUPPORTED); return (LIBUSB_ERROR_NOT_SUPPORTED);
usbi_dbg("iface %d, setting %d", iface, altsetting); usbi_dbg("iface %u, setting %u", iface, altsetting);
memset(&intf, 0, sizeof(intf)); memset(&intf, 0, sizeof(intf));
@ -429,18 +408,10 @@ obsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
return (LIBUSB_SUCCESS); return (LIBUSB_SUCCESS);
} }
int
obsd_reset_device(struct libusb_device_handle *handle)
{
usbi_dbg("");
return (LIBUSB_ERROR_NOT_SUPPORTED);
}
void void
obsd_destroy_device(struct libusb_device *dev) obsd_destroy_device(struct libusb_device *dev)
{ {
struct device_priv *dpriv = (struct device_priv *)dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(dev);
usbi_dbg(" "); usbi_dbg(" ");
@ -452,13 +423,11 @@ int
obsd_submit_transfer(struct usbi_transfer *itransfer) obsd_submit_transfer(struct usbi_transfer *itransfer)
{ {
struct libusb_transfer *transfer; struct libusb_transfer *transfer;
struct handle_priv *hpriv;
int err = 0; int err = 0;
usbi_dbg(" "); usbi_dbg(" ");
transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
hpriv = (struct handle_priv *)transfer->dev_handle->os_priv;
switch (transfer->type) { switch (transfer->type) {
case LIBUSB_TRANSFER_TYPE_CONTROL: case LIBUSB_TRANSFER_TYPE_CONTROL:
@ -497,37 +466,19 @@ obsd_submit_transfer(struct usbi_transfer *itransfer)
int int
obsd_cancel_transfer(struct usbi_transfer *itransfer) obsd_cancel_transfer(struct usbi_transfer *itransfer)
{ {
UNUSED(itransfer);
usbi_dbg(" "); usbi_dbg(" ");
return (LIBUSB_ERROR_NOT_SUPPORTED); return (LIBUSB_ERROR_NOT_SUPPORTED);
} }
void
obsd_clear_transfer_priv(struct usbi_transfer *itransfer)
{
usbi_dbg("");
/* Nothing to do */
}
int int
obsd_handle_transfer_completion(struct usbi_transfer *itransfer) obsd_handle_transfer_completion(struct usbi_transfer *itransfer)
{ {
return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED); return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
} }
int
obsd_clock_gettime(int clkid, struct timespec *tp)
{
if (clkid == USBI_CLOCK_REALTIME)
return clock_gettime(CLOCK_REALTIME, tp);
if (clkid == USBI_CLOCK_MONOTONIC)
return clock_gettime(CLOCK_MONOTONIC, tp);
return (LIBUSB_ERROR_INVALID_PARAM);
}
int int
_errno_to_libusb(int err) _errno_to_libusb(int err)
{ {
@ -552,10 +503,10 @@ _errno_to_libusb(int err)
int int
_cache_active_config_descriptor(struct libusb_device *dev) _cache_active_config_descriptor(struct libusb_device *dev)
{ {
struct device_priv *dpriv = (struct device_priv *)dev->os_priv; struct device_priv *dpriv = usbi_get_device_priv(dev);
struct usb_device_cdesc udc; struct usb_device_cdesc udc;
struct usb_device_fdesc udf; struct usb_device_fdesc udf;
unsigned char* buf; void *buf;
int fd, len, err; int fd, len, err;
if ((fd = _bus_open(dev->bus_number)) < 0) if ((fd = _bus_open(dev->bus_number)) < 0)
@ -575,7 +526,7 @@ _cache_active_config_descriptor(struct libusb_device *dev)
usbi_dbg("active bLength %d", udc.udc_desc.bLength); usbi_dbg("active bLength %d", udc.udc_desc.bLength);
len = UGETW(udc.udc_desc.wTotalLength); len = UGETW(udc.udc_desc.wTotalLength);
buf = malloc(len); buf = malloc((size_t)len);
if (buf == NULL) if (buf == NULL)
return (LIBUSB_ERROR_NO_MEM); return (LIBUSB_ERROR_NO_MEM);
@ -611,7 +562,7 @@ _sync_control_transfer(struct usbi_transfer *itransfer)
struct usb_ctl_request req; struct usb_ctl_request req;
transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv; dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
setup = (struct libusb_control_setup *)transfer->buffer; setup = (struct libusb_control_setup *)transfer->buffer;
usbi_dbg("type %x request %x value %x index %d length %d timeout %d", usbi_dbg("type %x request %x value %x index %d length %d timeout %d",
@ -673,8 +624,8 @@ _access_endpoint(struct libusb_transfer *transfer)
int fd, endpt; int fd, endpt;
mode_t mode; mode_t mode;
hpriv = (struct handle_priv *)transfer->dev_handle->os_priv; hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv; dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
endpt = UE_GET_ADDR(transfer->endpoint); endpt = UE_GET_ADDR(transfer->endpoint);
mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY; mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY;
@ -705,7 +656,7 @@ _sync_gen_transfer(struct usbi_transfer *itransfer)
int fd, nr = 1; int fd, nr = 1;
transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv; dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
if (dpriv->devname == NULL) if (dpriv->devname == NULL)
return (LIBUSB_ERROR_NOT_SUPPORTED); return (LIBUSB_ERROR_NOT_SUPPORTED);

File diff suppressed because it is too large Load diff

View file

@ -30,7 +30,6 @@
typedef struct sunos_device_priv { typedef struct sunos_device_priv {
uint8_t cfgvalue; /* active config value */ uint8_t cfgvalue; /* active config value */
uint8_t *raw_cfgdescr; /* active config descriptor */ uint8_t *raw_cfgdescr; /* active config descriptor */
struct libusb_device_descriptor dev_descr; /* usb device descriptor */
char *ugenpath; /* name of the ugen(4) node */ char *ugenpath; /* name of the ugen(4) node */
char *phypath; /* physical path */ char *phypath; /* physical path */
} sunos_dev_priv_t; } sunos_dev_priv_t;

View file

@ -19,62 +19,111 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <config.h>
#include <time.h>
#if defined(__linux__) || defined(__OpenBSD__)
# if defined(__OpenBSD__)
# define _BSD_SOURCE
# endif
# include <unistd.h>
# include <sys/syscall.h>
#elif defined(__APPLE__)
# include <pthread.h>
#elif defined(__CYGWIN__)
# include <windows.h>
#endif
#include "threads_posix.h"
#include "libusbi.h" #include "libusbi.h"
#include <errno.h>
#if defined(__ANDROID__)
# include <unistd.h>
#elif defined(__HAIKU__)
# include <os/kernel/OS.h>
#elif defined(__linux__)
# include <sys/syscall.h>
# include <unistd.h>
#elif defined(__NetBSD__)
# include <lwp.h>
#elif defined(__OpenBSD__)
# define _BSD_SOURCE
# include <sys/syscall.h>
# include <unistd.h>
#elif defined(__sun__)
# 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, int usbi_cond_timedwait(pthread_cond_t *cond,
pthread_mutex_t *mutex, const struct timeval *tv) pthread_mutex_t *mutex, const struct timeval *tv)
{ {
struct timespec timeout; struct timespec timeout;
int r; int r;
r = usbi_backend.clock_gettime(USBI_CLOCK_REALTIME, &timeout); #ifdef HAVE_PTHREAD_CONDATTR_SETCLOCK
if (r < 0) usbi_get_monotonic_time(&timeout);
return r; #else
usbi_get_real_time(&timeout);
#endif
timeout.tv_sec += tv->tv_sec; timeout.tv_sec += tv->tv_sec;
timeout.tv_nsec += tv->tv_usec * 1000; timeout.tv_nsec += tv->tv_usec * 1000L;
while (timeout.tv_nsec >= 1000000000L) { if (timeout.tv_nsec >= NSEC_PER_SEC) {
timeout.tv_nsec -= 1000000000L; timeout.tv_nsec -= NSEC_PER_SEC;
timeout.tv_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)
{ {
int ret; static _Thread_local unsigned int tl_tid;
int tid;
if (tl_tid)
return tl_tid;
#if defined(__ANDROID__) #if defined(__ANDROID__)
ret = gettid(); tid = gettid();
#elif defined(__APPLE__)
#ifdef HAVE_PTHREAD_THREADID_NP
uint64_t thread_id;
if (pthread_threadid_np(NULL, &thread_id) == 0)
tid = (int)thread_id;
else
tid = -1;
#else
tid = (int)pthread_mach_thread_np(pthread_self());
#endif
#elif defined(__HAIKU__)
tid = get_pthread_thread_id(pthread_self());
#elif defined(__linux__) #elif defined(__linux__)
ret = syscall(SYS_gettid); tid = (int)syscall(SYS_gettid);
#elif defined(__NetBSD__)
tid = _lwp_self();
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__)
/* The following only works with OpenBSD > 5.1 as it requires /* The following only works with OpenBSD > 5.1 as it requires
real thread support. For 5.1 and earlier, -1 is returned. */ * real thread support. For 5.1 and earlier, -1 is returned. */
ret = syscall(SYS_getthrid); tid = syscall(SYS_getthrid);
#elif defined(__APPLE__) #elif defined(__sun__)
ret = (int)pthread_mach_thread_np(pthread_self()); tid = _lwp_self();
#elif defined(__CYGWIN__)
ret = GetCurrentThreadId();
#else #else
ret = -1; tid = -1;
#endif #endif
/* TODO: NetBSD thread ID support */
return ret; if (tid == -1) {
/* If we don't have a thread ID, at least return a unique
* value that can be used to distinguish individual
* threads. */
tid = (int)(intptr_t)pthread_self();
}
return tl_tid = (unsigned int)tid;
} }

View file

@ -22,67 +22,63 @@
#define LIBUSB_THREADS_POSIX_H #define LIBUSB_THREADS_POSIX_H
#include <pthread.h> #include <pthread.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h> #define PTHREAD_CHECK(expression) ASSERT_EQ(expression, 0)
#endif
#define USBI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER #define USBI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
typedef pthread_mutex_t usbi_mutex_static_t; typedef pthread_mutex_t usbi_mutex_static_t;
static inline void usbi_mutex_static_lock(usbi_mutex_static_t *mutex) 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) 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; 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) 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) 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) 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) 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; typedef pthread_cond_t usbi_cond_t;
static inline void usbi_cond_init(pthread_cond_t *cond) 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_init(cond, NULL); PTHREAD_CHECK(pthread_cond_wait(cond, mutex));
}
static inline int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex)
{
return pthread_cond_wait(cond, mutex);
} }
int usbi_cond_timedwait(usbi_cond_t *cond, int usbi_cond_timedwait(usbi_cond_t *cond,
usbi_mutex_t *mutex, const struct timeval *tv); usbi_mutex_t *mutex, const struct timeval *tv);
static inline void usbi_cond_broadcast(usbi_cond_t *cond) 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) 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; typedef pthread_key_t usbi_tls_key_t;
static inline void usbi_tls_key_create(usbi_tls_key_t *key) 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) static inline void *usbi_tls_key_get(usbi_tls_key_t key)
{ {
@ -90,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) 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) 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 */ #endif /* LIBUSB_THREADS_POSIX_H */

View file

@ -2,6 +2,7 @@
* libusb synchronization on Microsoft Windows * libusb synchronization on Microsoft Windows
* *
* Copyright © 2010 Michael Plante <michael.plante@gmail.com> * Copyright © 2010 Michael Plante <michael.plante@gmail.com>
* Copyright © 2020 Chris Dickens <christopher.a.dickens@gmail.com>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -18,109 +19,22 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <config.h>
#include <errno.h>
#include "libusbi.h" #include "libusbi.h"
struct usbi_cond_perthread {
struct list_head list;
HANDLE event;
};
void usbi_mutex_static_lock(usbi_mutex_static_t *mutex)
{
while (InterlockedExchange(mutex, 1L) == 1L)
SleepEx(0, TRUE);
}
void usbi_cond_init(usbi_cond_t *cond)
{
list_init(&cond->waiters);
list_init(&cond->not_waiting);
}
static int usbi_cond_intwait(usbi_cond_t *cond,
usbi_mutex_t *mutex, DWORD timeout_ms)
{
struct usbi_cond_perthread *pos;
DWORD r;
// Same assumption as usbi_cond_broadcast() holds
if (list_empty(&cond->not_waiting)) {
pos = malloc(sizeof(*pos));
if (pos == NULL)
return ENOMEM; // This errno is not POSIX-allowed.
pos->event = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset.
if (pos->event == NULL) {
free(pos);
return ENOMEM;
}
} else {
pos = list_first_entry(&cond->not_waiting, struct usbi_cond_perthread, list);
list_del(&pos->list); // remove from not_waiting list.
// Ensure the event is clear before waiting
WaitForSingleObject(pos->event, 0);
}
list_add(&pos->list, &cond->waiters);
LeaveCriticalSection(mutex);
r = WaitForSingleObject(pos->event, timeout_ms);
EnterCriticalSection(mutex);
list_del(&pos->list);
list_add(&pos->list, &cond->not_waiting);
if (r == WAIT_OBJECT_0)
return 0;
else if (r == WAIT_TIMEOUT)
return ETIMEDOUT;
else
return EINVAL;
}
// N.B.: usbi_cond_*wait() can also return ENOMEM, even though pthread_cond_*wait cannot!
int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex)
{
return usbi_cond_intwait(cond, mutex, INFINITE);
}
int usbi_cond_timedwait(usbi_cond_t *cond, int usbi_cond_timedwait(usbi_cond_t *cond,
usbi_mutex_t *mutex, const struct timeval *tv) usbi_mutex_t *mutex, const struct timeval *tv)
{ {
DWORD millis; DWORD millis;
millis = (DWORD)(tv->tv_sec * 1000) + (tv->tv_usec / 1000); millis = (DWORD)(tv->tv_sec * 1000L) + (tv->tv_usec / 1000L);
/* round up to next millisecond */ /* round up to next millisecond */
if (tv->tv_usec % 1000) if (tv->tv_usec % 1000L)
millis++; millis++;
return usbi_cond_intwait(cond, mutex, millis);
}
void usbi_cond_broadcast(usbi_cond_t *cond) if (SleepConditionVariableCS(cond, mutex, millis))
{ return 0;
// Assumes mutex is locked; this is not in keeping with POSIX spec, but else if (GetLastError() == ERROR_TIMEOUT)
// libusb does this anyway, so we simplify by not adding more sync return LIBUSB_ERROR_TIMEOUT;
// primitives to the CV definition! else
struct usbi_cond_perthread *pos; return LIBUSB_ERROR_OTHER;
list_for_each_entry(pos, &cond->waiters, list, struct usbi_cond_perthread)
SetEvent(pos->event);
// The wait function will remove its respective item from the list.
}
void usbi_cond_destroy(usbi_cond_t *cond)
{
// This assumes no one is using this anymore. The check MAY NOT BE safe.
struct usbi_cond_perthread *pos, *next;
if (!list_empty(&cond->waiters))
return; // (!see above!)
list_for_each_entry_safe(pos, next, &cond->not_waiting, list, struct usbi_cond_perthread) {
CloseHandle(pos->event);
list_del(&pos->list);
free(pos);
}
} }

View file

@ -21,23 +21,24 @@
#ifndef LIBUSB_THREADS_WINDOWS_H #ifndef LIBUSB_THREADS_WINDOWS_H
#define LIBUSB_THREADS_WINDOWS_H #define LIBUSB_THREADS_WINDOWS_H
#define WINAPI_CHECK(expression) ASSERT_NE(expression, 0)
#define USBI_MUTEX_INITIALIZER 0L #define USBI_MUTEX_INITIALIZER 0L
#ifdef _WIN32_WCE
typedef LONG usbi_mutex_static_t; typedef LONG usbi_mutex_static_t;
#else static inline void usbi_mutex_static_lock(usbi_mutex_static_t *mutex)
typedef volatile LONG usbi_mutex_static_t; {
#endif while (InterlockedExchange(mutex, 1L) == 1L)
void usbi_mutex_static_lock(usbi_mutex_static_t *mutex); SleepEx(0, TRUE);
}
static inline void usbi_mutex_static_unlock(usbi_mutex_static_t *mutex) static inline void usbi_mutex_static_unlock(usbi_mutex_static_t *mutex)
{ {
InterlockedExchange(mutex, 0L); InterlockedExchange(mutex, 0L);
} }
typedef CRITICAL_SECTION usbi_mutex_t; 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); InitializeCriticalSection(mutex);
return 0;
} }
static inline void usbi_mutex_lock(usbi_mutex_t *mutex) static inline void usbi_mutex_lock(usbi_mutex_t *mutex)
{ {
@ -49,46 +50,47 @@ static inline void usbi_mutex_unlock(usbi_mutex_t *mutex)
} }
static inline int usbi_mutex_trylock(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) static inline void usbi_mutex_destroy(usbi_mutex_t *mutex)
{ {
DeleteCriticalSection(mutex); DeleteCriticalSection(mutex);
} }
// We *were* getting timespec from pthread.h: #if !defined(HAVE_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED)
#if (!defined(HAVE_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED))
#define HAVE_STRUCT_TIMESPEC 1 #define HAVE_STRUCT_TIMESPEC 1
#define _TIMESPEC_DEFINED 1 #define _TIMESPEC_DEFINED 1
struct timespec { struct timespec {
long tv_sec; long tv_sec;
long tv_nsec; long tv_nsec;
}; };
#endif /* HAVE_STRUCT_TIMESPEC | _TIMESPEC_DEFINED */ #endif /* HAVE_STRUCT_TIMESPEC || _TIMESPEC_DEFINED */
// We *were* getting ETIMEDOUT from pthread.h: typedef CONDITION_VARIABLE usbi_cond_t;
#ifndef ETIMEDOUT static inline void usbi_cond_init(usbi_cond_t *cond)
#define ETIMEDOUT 10060 /* This is the value in winsock.h. */ {
#endif InitializeConditionVariable(cond);
}
typedef struct usbi_cond { static inline void usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex)
// Every time a thread touches the CV, it winds up in one of these lists. {
// It stays there until the CV is destroyed, even if the thread terminates. WINAPI_CHECK(SleepConditionVariableCS(cond, mutex, INFINITE));
struct list_head waiters; }
struct list_head not_waiting;
} usbi_cond_t;
void usbi_cond_init(usbi_cond_t *cond);
int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex);
int usbi_cond_timedwait(usbi_cond_t *cond, int usbi_cond_timedwait(usbi_cond_t *cond,
usbi_mutex_t *mutex, const struct timeval *tv); usbi_mutex_t *mutex, const struct timeval *tv);
void usbi_cond_broadcast(usbi_cond_t *cond); static inline void usbi_cond_broadcast(usbi_cond_t *cond)
void usbi_cond_destroy(usbi_cond_t *cond); {
WakeAllConditionVariable(cond);
}
static inline void usbi_cond_destroy(usbi_cond_t *cond)
{
UNUSED(cond);
}
typedef DWORD usbi_tls_key_t; typedef DWORD usbi_tls_key_t;
static inline void usbi_tls_key_create(usbi_tls_key_t *key) static inline void usbi_tls_key_create(usbi_tls_key_t *key)
{ {
*key = TlsAlloc(); *key = TlsAlloc();
assert(*key != TLS_OUT_OF_INDEXES);
} }
static inline void *usbi_tls_key_get(usbi_tls_key_t key) static inline void *usbi_tls_key_get(usbi_tls_key_t key)
{ {
@ -96,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) 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) 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 */ #endif /* LIBUSB_THREADS_WINDOWS_H */

View file

@ -0,0 +1,886 @@
/*
* windows backend for libusb 1.0
* Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
* With contributions from Michael Plante, Orin Eman et al.
* Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
* HID Reports IOCTLs inspired from HIDAPI by Alan Ott, Signal 11 Software
* Hash table functions adapted from glibc, by Ulrich Drepper et al.
* Major code testing contribution by Xiaofan Chen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <config.h>
#include <process.h>
#include <stdio.h>
#include "libusbi.h"
#include "windows_common.h"
#define EPOCH_TIME UINT64_C(116444736000000000) // 1970.01.01 00:00:000 in MS Filetime
#define STATUS_SUCCESS ((ULONG_PTR)0UL)
// Public
enum windows_version windows_version = WINDOWS_UNDEFINED;
// Global variables for init/exit
static unsigned int init_count;
static bool usbdk_available;
/*
* Converts a windows error to human readable string
* uses retval as errorcode, or, if 0, use GetLastError()
*/
#if defined(ENABLE_LOGGING)
const char *windows_error_str(DWORD error_code)
{
static char err_string[256];
DWORD size;
int len;
if (error_code == 0)
error_code = GetLastError();
len = sprintf(err_string, "[%lu] ", ULONG_CAST(error_code));
// Translate codes returned by SetupAPI. The ones we are dealing with are either
// in 0x0000xxxx or 0xE000xxxx and can be distinguished from standard error codes.
// See http://msdn.microsoft.com/en-us/library/windows/hardware/ff545011.aspx
switch (error_code & 0xE0000000) {
case 0:
error_code = HRESULT_FROM_WIN32(error_code); // Still leaves ERROR_SUCCESS unmodified
break;
case 0xE0000000:
error_code = 0x80000000 | (FACILITY_SETUPAPI << 16) | (error_code & 0x0000FFFF);
break;
default:
break;
}
size = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
&err_string[len], sizeof(err_string) - len, NULL);
if (size == 0) {
DWORD format_error = GetLastError();
if (format_error)
snprintf(err_string, sizeof(err_string),
"Windows error code %lu (FormatMessage error code %lu)",
ULONG_CAST(error_code), ULONG_CAST(format_error));
else
snprintf(err_string, sizeof(err_string), "Unknown error code %lu",
ULONG_CAST(error_code));
} else {
// Remove CRLF from end of message, if present
size_t pos = len + size - 2;
if (err_string[pos] == '\r')
err_string[pos] = '\0';
}
return err_string;
}
#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) */
#define HTAB_SIZE 1021UL // *MUST* be a prime number!!
typedef struct htab_entry {
unsigned long used;
char *str;
} htab_entry;
static htab_entry *htab_table;
static usbi_mutex_t htab_mutex;
static unsigned long htab_filled;
/* Before using the hash table we must allocate memory for it.
We allocate one element more as the found prime number says.
This is done for more effective indexing as explained in the
comment for the hash function. */
static bool htab_create(struct libusb_context *ctx)
{
if (htab_table != NULL) {
usbi_err(ctx, "program assertion failed - hash table already allocated");
return true;
}
// Create a mutex
usbi_mutex_init(&htab_mutex);
usbi_dbg("using %lu entries hash table", HTAB_SIZE);
htab_filled = 0;
// allocate memory and zero out.
htab_table = calloc(HTAB_SIZE + 1, sizeof(htab_entry));
if (htab_table == NULL) {
usbi_err(ctx, "could not allocate space for hash table");
return false;
}
return true;
}
/* After using the hash table it has to be destroyed. */
static void htab_destroy(void)
{
unsigned long i;
if (htab_table == NULL)
return;
for (i = 0; i < HTAB_SIZE; i++)
free(htab_table[i].str);
safe_free(htab_table);
usbi_mutex_destroy(&htab_mutex);
}
/* This is the search function. It uses double hashing with open addressing.
We use a trick to speed up the lookup. The table is created with one
more element available. This enables us to use the index zero special.
This index will never be used because we store the first hash index in
the field used where zero means not used. Every other value means used.
The used field can be used as a first fast comparison for equality of
the stored and the parameter value. This helps to prevent unnecessary
expensive calls of strcmp. */
unsigned long htab_hash(const char *str)
{
unsigned long hval, hval2;
unsigned long idx;
unsigned long r = 5381UL;
int c;
const char *sz = str;
if (str == NULL)
return 0;
// Compute main hash value (algorithm suggested by Nokia)
while ((c = *sz++) != 0)
r = ((r << 5) + r) + c;
if (r == 0)
++r;
// compute table hash: simply take the modulus
hval = r % HTAB_SIZE;
if (hval == 0)
++hval;
// Try the first index
idx = hval;
// Mutually exclusive access (R/W lock would be better)
usbi_mutex_lock(&htab_mutex);
if (htab_table[idx].used) {
if ((htab_table[idx].used == hval) && (strcmp(str, htab_table[idx].str) == 0))
goto out_unlock; // existing hash
usbi_dbg("hash collision ('%s' vs '%s')", str, htab_table[idx].str);
// Second hash function, as suggested in [Knuth]
hval2 = 1UL + hval % (HTAB_SIZE - 2);
do {
// Because size is prime this guarantees to step through all available indexes
if (idx <= hval2)
idx = HTAB_SIZE + idx - hval2;
else
idx -= hval2;
// If we visited all entries leave the loop unsuccessfully
if (idx == hval)
break;
// If entry is found use it.
if ((htab_table[idx].used == hval) && (strcmp(str, htab_table[idx].str) == 0))
goto out_unlock;
} while (htab_table[idx].used);
}
// Not found => New entry
// If the table is full return an error
if (htab_filled >= HTAB_SIZE) {
usbi_err(NULL, "hash table is full (%lu entries)", HTAB_SIZE);
idx = 0UL;
goto out_unlock;
}
htab_table[idx].str = _strdup(str);
if (htab_table[idx].str == NULL) {
usbi_err(NULL, "could not duplicate string for hash table");
idx = 0UL;
goto out_unlock;
}
htab_table[idx].used = hval;
++htab_filled;
out_unlock:
usbi_mutex_unlock(&htab_mutex);
return idx;
}
enum libusb_transfer_status usbd_status_to_libusb_transfer_status(USBD_STATUS status)
{
if (USBD_SUCCESS(status))
return LIBUSB_TRANSFER_COMPLETED;
switch (status) {
case USBD_STATUS_TIMEOUT:
return LIBUSB_TRANSFER_TIMED_OUT;
case USBD_STATUS_CANCELED:
return LIBUSB_TRANSFER_CANCELLED;
case USBD_STATUS_ENDPOINT_HALTED:
return LIBUSB_TRANSFER_STALL;
case USBD_STATUS_DEVICE_GONE:
return LIBUSB_TRANSFER_NO_DEVICE;
default:
usbi_dbg("USBD_STATUS 0x%08lx translated to LIBUSB_TRANSFER_ERROR", ULONG_CAST(status));
return LIBUSB_TRANSFER_ERROR;
}
}
/*
* 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;
usbi_signal_transfer_completion(itransfer);
}
/* Windows version detection */
static BOOL is_x64(void)
{
BOOL ret = FALSE;
// Detect if we're running a 32 or 64 bit system
if (sizeof(uintptr_t) < 8) {
IsWow64Process(GetCurrentProcess(), &ret);
} else {
ret = TRUE;
}
return ret;
}
static enum windows_version get_windows_version(void)
{
enum windows_version winver;
OSVERSIONINFOEXA vi, vi2;
unsigned major, minor, version;
ULONGLONG major_equal, minor_equal;
const char *w, *arch;
bool ws;
memset(&vi, 0, sizeof(vi));
vi.dwOSVersionInfoSize = sizeof(vi);
if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
memset(&vi, 0, sizeof(vi));
vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
if (!GetVersionExA((OSVERSIONINFOA *)&vi))
return WINDOWS_UNDEFINED;
}
if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT)
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
// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
for (major = vi.dwMajorVersion; major <= 9; major++) {
memset(&vi2, 0, sizeof(vi2));
vi2.dwOSVersionInfoSize = sizeof(vi2);
vi2.dwMajorVersion = major;
if (!VerifyVersionInfoA(&vi2, VER_MAJORVERSION, major_equal))
continue;
if (vi.dwMajorVersion < major) {
vi.dwMajorVersion = major;
vi.dwMinorVersion = 0;
}
minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL);
for (minor = vi.dwMinorVersion; minor <= 9; minor++) {
memset(&vi2, 0, sizeof(vi2));
vi2.dwOSVersionInfoSize = sizeof(vi2);
vi2.dwMinorVersion = minor;
if (!VerifyVersionInfoA(&vi2, VER_MINORVERSION, minor_equal))
continue;
vi.dwMinorVersion = minor;
break;
}
break;
}
}
if ((vi.dwMajorVersion > 0xf) || (vi.dwMinorVersion > 0xf))
return WINDOWS_UNDEFINED;
ws = (vi.wProductType <= VER_NT_WORKSTATION);
version = vi.dwMajorVersion << 4 | vi.dwMinorVersion;
switch (version) {
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: winver = WINDOWS_10; w = (ws ? "10" : "2016"); break;
default:
if (version < 0x50)
return WINDOWS_UNDEFINED;
winver = WINDOWS_11_OR_LATER;
w = "11 or later";
}
arch = is_x64() ? "64-bit" : "32-bit";
if (vi.wServicePackMinor)
usbi_dbg("Windows %s SP%u.%u %s", w, vi.wServicePackMajor, vi.wServicePackMinor, arch);
else if (vi.wServicePackMajor)
usbi_dbg("Windows %s SP%u %s", w, vi.wServicePackMajor, arch);
else
usbi_dbg("Windows %s %s", w, arch);
return winver;
}
static unsigned __stdcall windows_iocp_thread(void *arg)
{
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("I/O completion thread started");
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;
}
if (overlapped == NULL) {
// Signal to quit
if (completion_key != (ULONG_PTR)ctx)
usbi_err(ctx, "program assertion failed - overlapped is NULL");
break;
}
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);
}
usbi_dbg("I/O completion thread exiting");
return 0;
}
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;
bool winusb_backend_init = false;
int r;
sprintf(mutex_name, "libusb_init%08lX", ULONG_CAST(GetCurrentProcessId() & 0xFFFFFFFFU));
mutex = CreateMutexA(NULL, FALSE, mutex_name);
if (mutex == NULL) {
usbi_err(ctx, "could not create mutex: %s", windows_error_str(0));
return LIBUSB_ERROR_NO_MEM;
}
// A successful wait gives this thread ownership of the mutex
// => 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);
return LIBUSB_ERROR_NO_MEM;
}
// NB: concurrent usage supposes that init calls are equally balanced with
// exit calls. If init is called more than exit, we will not exit properly
if (++init_count == 1) { // First init?
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;
}
if (!htab_create(ctx)) {
r = LIBUSB_ERROR_NO_MEM;
goto init_exit;
}
r = winusb_backend.init(ctx);
if (r != LIBUSB_SUCCESS)
goto init_exit;
winusb_backend_init = true;
r = usbdk_backend.init(ctx);
if (r == LIBUSB_SUCCESS) {
usbi_dbg("UsbDk backend is available");
usbdk_available = true;
} else {
usbi_info(ctx, "UsbDk backend is not available");
// Do not report this as an error
}
}
// 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();
--init_count;
}
ReleaseMutex(mutex);
CloseHandle(mutex);
return r;
}
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;
sprintf(mutex_name, "libusb_init%08lX", ULONG_CAST(GetCurrentProcessId() & 0xFFFFFFFFU));
mutex = CreateMutexA(NULL, FALSE, mutex_name);
if (mutex == NULL)
return;
// A successful wait gives this thread ownership of the mutex
// => 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) {
usbdk_backend.exit(ctx);
usbdk_available = false;
}
winusb_backend.exit(ctx);
htab_destroy();
}
ReleaseMutex(mutex);
CloseHandle(mutex);
}
static int windows_set_option(struct libusb_context *ctx, enum libusb_option option, va_list ap)
{
struct windows_context_priv *priv = usbi_get_context_priv(ctx);
UNUSED(ap);
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;
}
return LIBUSB_ERROR_NOT_SUPPORTED;
}
static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **discdevs)
{
struct windows_context_priv *priv = usbi_get_context_priv(ctx);
return priv->backend->get_device_list(ctx, discdevs);
}
static int windows_open(struct libusb_device_handle *dev_handle)
{
struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
return priv->backend->open(dev_handle);
}
static void windows_close(struct libusb_device_handle *dev_handle)
{
struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
priv->backend->close(dev_handle);
}
static int windows_get_active_config_descriptor(struct libusb_device *dev,
void *buffer, size_t len)
{
struct windows_context_priv *priv = usbi_get_context_priv(DEVICE_CTX(dev));
return priv->backend->get_active_config_descriptor(dev, buffer, len);
}
static int windows_get_config_descriptor(struct libusb_device *dev,
uint8_t config_index, void *buffer, size_t len)
{
struct windows_context_priv *priv = usbi_get_context_priv(DEVICE_CTX(dev));
return priv->backend->get_config_descriptor(dev, config_index, buffer, len);
}
static int windows_get_config_descriptor_by_value(struct libusb_device *dev,
uint8_t bConfigurationValue, void **buffer)
{
struct windows_context_priv *priv = usbi_get_context_priv(DEVICE_CTX(dev));
return priv->backend->get_config_descriptor_by_value(dev, bConfigurationValue, buffer);
}
static int windows_get_configuration(struct libusb_device_handle *dev_handle, uint8_t *config)
{
struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
return priv->backend->get_configuration(dev_handle, config);
}
static int windows_set_configuration(struct libusb_device_handle *dev_handle, int config)
{
struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
if (config == -1)
config = 0;
return priv->backend->set_configuration(dev_handle, (uint8_t)config);
}
static int windows_claim_interface(struct libusb_device_handle *dev_handle, uint8_t interface_number)
{
struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
return priv->backend->claim_interface(dev_handle, interface_number);
}
static int windows_release_interface(struct libusb_device_handle *dev_handle, uint8_t interface_number)
{
struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
return priv->backend->release_interface(dev_handle, interface_number);
}
static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle,
uint8_t interface_number, uint8_t altsetting)
{
struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
return priv->backend->set_interface_altsetting(dev_handle, interface_number, altsetting);
}
static int windows_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
{
struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
return priv->backend->clear_halt(dev_handle, endpoint);
}
static int windows_reset_device(struct libusb_device_handle *dev_handle)
{
struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
return priv->backend->reset_device(dev_handle);
}
static void windows_destroy_device(struct libusb_device *dev)
{
struct windows_context_priv *priv = usbi_get_context_priv(DEVICE_CTX(dev));
priv->backend->destroy_device(dev);
}
static int windows_submit_transfer(struct usbi_transfer *itransfer)
{
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_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);
int r;
switch (transfer->type) {
case LIBUSB_TRANSFER_TYPE_CONTROL:
case LIBUSB_TRANSFER_TYPE_BULK:
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
break;
case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
usbi_warn(ctx, "bulk stream transfers are not yet supported on this platform");
return LIBUSB_ERROR_NOT_SUPPORTED;
default:
usbi_err(ctx, "unknown endpoint type %d", transfer->type);
return LIBUSB_ERROR_INVALID_PARAM;
}
if (transfer_priv->handle != NULL) {
usbi_err(ctx, "program assertion failed - transfer HANDLE is not NULL");
transfer_priv->handle = NULL;
}
r = priv->backend->submit_transfer(itransfer);
if (r != LIBUSB_SUCCESS) {
// Always call the backend's clear_transfer_priv() function on failure
priv->backend->clear_transfer_priv(itransfer);
transfer_priv->handle = NULL;
return r;
}
// The backend should set the HANDLE used for each submitted transfer
// by calling set_transfer_priv_handle()
if (transfer_priv->handle == NULL)
usbi_err(ctx, "program assertion failed - transfer HANDLE is NULL after transfer was submitted");
return r;
}
static int windows_cancel_transfer(struct usbi_transfer *itransfer)
{
struct windows_context_priv *priv = usbi_get_context_priv(ITRANSFER_CTX(itransfer));
struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(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->overlapped))
return LIBUSB_SUCCESS;
else if (GetLastError() == ERROR_NOT_FOUND)
return LIBUSB_ERROR_NOT_FOUND;
if (priv->backend->cancel_transfer)
return priv->backend->cancel_transfer(itransfer);
usbi_warn(ITRANSFER_CTX(itransfer), "cancellation not supported for this transfer's driver");
return LIBUSB_ERROR_NOT_SUPPORTED;
}
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);
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;
if (GetOverlappedResult(transfer_priv->handle, &transfer_priv->overlapped, &bytes_transferred, FALSE))
result = NO_ERROR;
else
result = GetLastError();
usbi_dbg("handling transfer %p completion with errcode %lu, length %lu",
USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer), ULONG_CAST(result), ULONG_CAST(bytes_transferred));
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_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;
}
transfer_priv->handle = NULL;
// Backend-specific cleanup
backend->clear_transfer_priv(itransfer);
if (status == LIBUSB_TRANSFER_CANCELLED)
return usbi_handle_transfer_cancellation(itransfer);
else
return usbi_handle_transfer_completion(itransfer, status);
}
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 (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));
}
// NB: MSVC6 does not support named initializers.
const struct usbi_os_backend usbi_backend = {
"Windows",
USBI_CAP_HAS_HID_ACCESS,
windows_init,
windows_exit,
windows_set_option,
windows_get_device_list,
NULL, /* hotplug_poll */
NULL, /* wrap_sys_device */
windows_open,
windows_close,
windows_get_active_config_descriptor,
windows_get_config_descriptor,
windows_get_config_descriptor_by_value,
windows_get_configuration,
windows_set_configuration,
windows_claim_interface,
windows_release_interface,
windows_set_interface_altsetting,
windows_clear_halt,
windows_reset_device,
NULL, /* alloc_streams */
NULL, /* free_streams */
NULL, /* dev_mem_alloc */
NULL, /* dev_mem_free */
NULL, /* kernel_driver_active */
NULL, /* detach_kernel_driver */
NULL, /* attach_kernel_driver */
windows_destroy_device,
windows_submit_transfer,
windows_cancel_transfer,
NULL, /* clear_transfer_priv */
NULL, /* handle_events */
windows_handle_transfer_completion,
sizeof(struct windows_context_priv),
sizeof(union windows_device_priv),
sizeof(union windows_device_handle_priv),
sizeof(struct windows_transfer_priv),
};

View file

@ -2,9 +2,10 @@
* Windows backend common header for libusb 1.0 * Windows backend common header for libusb 1.0
* *
* This file brings together header code common between * This file brings together header code common between
* the desktop Windows and Windows CE backends. * the desktop Windows backends.
* Copyright © 2012-2013 RealVNC Ltd. * Copyright © 2012-2013 RealVNC Ltd.
* Copyright © 2009-2012 Pete Batard <pete@akeo.ie> * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
* Copyright © 2014-2020 Chris Dickens <christopher.a.dickens@gmail.com>
* With contributions from Michael Plante, Orin Eman et al. * With contributions from Michael Plante, Orin Eman et al.
* Parts of this code adapted from libusb-win32-v1 by Stephan Meyer * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
* Major code testing contribution by Xiaofan Chen * Major code testing contribution by Xiaofan Chen
@ -24,20 +25,27 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#pragma once #ifndef LIBUSB_WINDOWS_COMMON_H
#define LIBUSB_WINDOWS_COMMON_H
// Windows API default is uppercase - ugh! #include <stdbool.h>
#if !defined(bool)
#define bool BOOL
#endif
#if !defined(true)
#define true TRUE
#endif
#if !defined(false)
#define false FALSE
#endif
#define EPOCH_TIME UINT64_C(116444736000000000) // 1970.01.01 00:00:000 in MS Filetime /*
* Workaround for the mess that exists with the DWORD and ULONG types.
* Visual Studio unconditionally defines these types as 'unsigned long'
* and a long is always 32-bits, even on 64-bit builds. GCC on the other
* hand varies the width of a long, matching it to the build. To make
* matters worse, the platform headers for these GCC builds define a
* DWORD/ULONG to be 'unsigned long' on 32-bit builds and 'unsigned int'
* on 64-bit builds. This creates a great deal of warnings for compilers
* that support printf format checking since it will never actually be
* an unsigned long.
*/
#if defined(_MSC_VER)
#define ULONG_CAST(x) (x)
#else
#define ULONG_CAST(x) ((unsigned long)(x))
#endif
#if defined(__CYGWIN__) #if defined(__CYGWIN__)
#define _stricmp strcasecmp #define _stricmp strcasecmp
@ -48,22 +56,10 @@
#define safe_free(p) do {if (p != NULL) {free((void *)p); p = NULL;}} while (0) #define safe_free(p) do {if (p != NULL) {free((void *)p); p = NULL;}} while (0)
#ifndef ARRAYSIZE
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif
#define ERR_BUFFER_SIZE 256
/* /*
* API macros - leveraged from libusb-win32 1.x * API macros - leveraged from libusb-win32 1.x
*/ */
#ifndef _WIN32_WCE
#define DLL_STRINGIFY(s) #s #define DLL_STRINGIFY(s) #s
#define DLL_LOAD_LIBRARY(name) LoadLibraryA(DLL_STRINGIFY(name))
#else
#define DLL_STRINGIFY(s) L#s
#define DLL_LOAD_LIBRARY(name) LoadLibrary(DLL_STRINGIFY(name))
#endif
/* /*
* Macros for handling DLL themselves * Macros for handling DLL themselves
@ -71,13 +67,14 @@
#define DLL_HANDLE_NAME(name) __dll_##name##_handle #define DLL_HANDLE_NAME(name) __dll_##name##_handle
#define DLL_DECLARE_HANDLE(name) \ #define DLL_DECLARE_HANDLE(name) \
static HMODULE DLL_HANDLE_NAME(name) = NULL static HMODULE DLL_HANDLE_NAME(name)
#define DLL_GET_HANDLE(name) \ #define DLL_GET_HANDLE(ctx, name) \
do { \ do { \
DLL_HANDLE_NAME(name) = DLL_LOAD_LIBRARY(name); \ DLL_HANDLE_NAME(name) = load_system_library(ctx, \
DLL_STRINGIFY(name)); \
if (!DLL_HANDLE_NAME(name)) \ if (!DLL_HANDLE_NAME(name)) \
return FALSE; \ return false; \
} while (0) } while (0)
#define DLL_FREE_HANDLE(name) \ #define DLL_FREE_HANDLE(name) \
@ -88,7 +85,6 @@
} \ } \
} while (0) } while (0)
/* /*
* Macros for handling functions within a DLL * Macros for handling functions within a DLL
*/ */
@ -96,7 +92,7 @@
#define DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefixname, name, args) \ #define DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefixname, name, args) \
typedef ret (api * DLL_FUNC_NAME(name))args; \ typedef ret (api * DLL_FUNC_NAME(name))args; \
static DLL_FUNC_NAME(name) prefixname = NULL static DLL_FUNC_NAME(name) prefixname
#define DLL_DECLARE_FUNC(api, ret, name, args) \ #define DLL_DECLARE_FUNC(api, ret, name, args) \
DLL_DECLARE_FUNC_PREFIXNAME(api, ret, name, name, args) DLL_DECLARE_FUNC_PREFIXNAME(api, ret, name, name, args)
@ -119,10 +115,275 @@
if (prefixname) \ if (prefixname) \
break; \ break; \
if (ret_on_failure) \ if (ret_on_failure) \
return FALSE; \ return false; \
} while (0) } while (0)
#define DLL_LOAD_FUNC(dll, name, ret_on_failure) \ #define DLL_LOAD_FUNC(dll, name, ret_on_failure) \
DLL_LOAD_FUNC_PREFIXNAME(dll, name, name, ret_on_failure) DLL_LOAD_FUNC_PREFIXNAME(dll, name, name, ret_on_failure)
#define DLL_LOAD_FUNC_PREFIXED(dll, prefix, name, ret_on_failure) \ #define DLL_LOAD_FUNC_PREFIXED(dll, prefix, name, ret_on_failure) \
DLL_LOAD_FUNC_PREFIXNAME(dll, prefix##name, name, ret_on_failure) DLL_LOAD_FUNC_PREFIXNAME(dll, prefix##name, name, ret_on_failure)
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff539136(v=vs.85).aspx
#if !defined(USBD_SUCCESS)
typedef LONG USBD_STATUS;
#define USBD_SUCCESS(Status) ((USBD_STATUS)(Status) >= 0)
#define USBD_STATUS_ENDPOINT_HALTED ((USBD_STATUS)0xC0000030L)
#define USBD_STATUS_TIMEOUT ((USBD_STATUS)0xC0006000L)
#define USBD_STATUS_DEVICE_GONE ((USBD_STATUS)0xC0007000L)
#define USBD_STATUS_CANCELED ((USBD_STATUS)0xC0010000L)
#endif
// error code added with Windows SDK 10.0.18362
#ifndef ERROR_NO_SUCH_DEVICE
#define ERROR_NO_SUCH_DEVICE 433L
#endif
/* Windows versions */
enum windows_version {
WINDOWS_UNDEFINED,
WINDOWS_2000,
WINDOWS_XP,
WINDOWS_2003, // Also XP x64
WINDOWS_VISTA,
WINDOWS_7,
WINDOWS_8,
WINDOWS_8_1,
WINDOWS_10,
WINDOWS_11_OR_LATER
};
extern enum windows_version windows_version;
#include <pshpack1.h>
typedef struct USB_DEVICE_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
USHORT bcdUSB;
UCHAR bDeviceClass;
UCHAR bDeviceSubClass;
UCHAR bDeviceProtocol;
UCHAR bMaxPacketSize0;
USHORT idVendor;
USHORT idProduct;
USHORT bcdDevice;
UCHAR iManufacturer;
UCHAR iProduct;
UCHAR iSerialNumber;
UCHAR bNumConfigurations;
} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
typedef struct USB_CONFIGURATION_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
USHORT wTotalLength;
UCHAR bNumInterfaces;
UCHAR bConfigurationValue;
UCHAR iConfiguration;
UCHAR bmAttributes;
UCHAR MaxPower;
} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;
#include <poppack.h>
#define MAX_DEVICE_ID_LEN 200
typedef struct USB_DK_DEVICE_ID {
WCHAR DeviceID[MAX_DEVICE_ID_LEN];
WCHAR InstanceID[MAX_DEVICE_ID_LEN];
} USB_DK_DEVICE_ID, *PUSB_DK_DEVICE_ID;
typedef struct USB_DK_DEVICE_INFO {
USB_DK_DEVICE_ID ID;
ULONG64 FilterID;
ULONG64 Port;
ULONG64 Speed;
USB_DEVICE_DESCRIPTOR DeviceDescriptor;
} USB_DK_DEVICE_INFO, *PUSB_DK_DEVICE_INFO;
typedef struct USB_DK_ISO_TRANSFER_RESULT {
ULONG64 ActualLength;
ULONG64 TransferResult;
} USB_DK_ISO_TRANSFER_RESULT, *PUSB_DK_ISO_TRANSFER_RESULT;
typedef struct USB_DK_GEN_TRANSFER_RESULT {
ULONG64 BytesTransferred;
ULONG64 UsbdStatus; // USBD_STATUS code
} USB_DK_GEN_TRANSFER_RESULT, *PUSB_DK_GEN_TRANSFER_RESULT;
typedef struct USB_DK_TRANSFER_RESULT {
USB_DK_GEN_TRANSFER_RESULT GenResult;
PVOID64 IsochronousResultsArray; // array of USB_DK_ISO_TRANSFER_RESULT
} USB_DK_TRANSFER_RESULT, *PUSB_DK_TRANSFER_RESULT;
typedef struct USB_DK_TRANSFER_REQUEST {
ULONG64 EndpointAddress;
PVOID64 Buffer;
ULONG64 BufferLength;
ULONG64 TransferType;
ULONG64 IsochronousPacketsArraySize;
PVOID64 IsochronousPacketsArray;
USB_DK_TRANSFER_RESULT Result;
} USB_DK_TRANSFER_REQUEST, *PUSB_DK_TRANSFER_REQUEST;
struct usbdk_device_priv {
USB_DK_DEVICE_ID ID;
PUSB_CONFIGURATION_DESCRIPTOR *config_descriptors;
HANDLE redirector_handle;
HANDLE system_handle;
uint8_t active_configuration;
};
struct winusb_device_priv {
bool initialized;
bool root_hub;
uint8_t active_config;
uint8_t depth; // distance to HCD
const struct windows_usb_api_backend *apib;
char *dev_id;
char *path; // device interface path
int sub_api; // for WinUSB-like APIs
struct {
char *path; // each interface needs a device interface path,
const struct windows_usb_api_backend *apib; // an API backend (multiple drivers support),
int sub_api;
int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS)
uint8_t *endpoint;
int current_altsetting;
bool restricted_functionality; // indicates if the interface functionality is restricted
// by Windows (eg. HID keyboards or mice cannot do R/W)
} usb_interface[USB_MAXINTERFACES];
struct hid_device_priv *hid;
PUSB_CONFIGURATION_DESCRIPTOR *config_descriptor; // list of pointers to the cached config descriptors
};
struct usbdk_device_handle_priv {
// Not currently used
char dummy;
};
struct winusb_device_handle_priv {
int active_interface;
struct {
HANDLE dev_handle; // WinUSB needs an extra handle for the file
HANDLE api_handle; // used by the API to communicate with the device
} interface_handle[USB_MAXINTERFACES];
int autoclaim_count[USB_MAXINTERFACES]; // For auto-release
};
struct usbdk_transfer_priv {
USB_DK_TRANSFER_REQUEST request;
PULONG64 IsochronousPacketsArray;
PUSB_DK_ISO_TRANSFER_RESULT IsochronousResultsArray;
};
struct winusb_transfer_priv {
uint8_t interface_number;
uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID
uint8_t *hid_dest; // transfer buffer destination, required for HID
size_t hid_expected_size;
// For isochronous transfers with LibUSBk driver:
void *iso_context;
// For isochronous transfers with Microsoft WinUSB driver:
void *isoch_buffer_handle; // The isoch_buffer_handle to free at the end of the transfer
BOOL iso_break_stream; // Whether the isoch. stream was to be continued in the last call of libusb_submit_transfer.
// As we this structure is zeroed out upon initialization, we need to use inverse logic here.
libusb_transfer_cb_fn iso_user_callback; // Original transfer callback of the user. Might be used for isochronous transfers.
};
struct windows_backend {
int (*init)(struct libusb_context *ctx);
void (*exit)(struct libusb_context *ctx);
int (*get_device_list)(struct libusb_context *ctx,
struct discovered_devs **discdevs);
int (*open)(struct libusb_device_handle *dev_handle);
void (*close)(struct libusb_device_handle *dev_handle);
int (*get_active_config_descriptor)(struct libusb_device *device,
void *buffer, size_t len);
int (*get_config_descriptor)(struct libusb_device *device,
uint8_t config_index, void *buffer, size_t len);
int (*get_config_descriptor_by_value)(struct libusb_device *device,
uint8_t bConfigurationValue, void **buffer);
int (*get_configuration)(struct libusb_device_handle *dev_handle, uint8_t *config);
int (*set_configuration)(struct libusb_device_handle *dev_handle, uint8_t config);
int (*claim_interface)(struct libusb_device_handle *dev_handle, uint8_t interface_number);
int (*release_interface)(struct libusb_device_handle *dev_handle, uint8_t interface_number);
int (*set_interface_altsetting)(struct libusb_device_handle *dev_handle,
uint8_t interface_number, uint8_t altsetting);
int (*clear_halt)(struct libusb_device_handle *dev_handle,
unsigned char endpoint);
int (*reset_device)(struct libusb_device_handle *dev_handle);
void (*destroy_device)(struct libusb_device *dev);
int (*submit_transfer)(struct usbi_transfer *itransfer);
int (*cancel_transfer)(struct usbi_transfer *itransfer);
void (*clear_transfer_priv)(struct usbi_transfer *itransfer);
enum libusb_transfer_status (*copy_transfer_data)(struct usbi_transfer *itransfer, DWORD length);
};
struct windows_context_priv {
const struct windows_backend *backend;
HANDLE completion_port;
HANDLE completion_port_thread;
};
union windows_device_priv {
struct usbdk_device_priv usbdk_priv;
struct winusb_device_priv winusb_priv;
};
union windows_device_handle_priv {
struct usbdk_device_handle_priv usbdk_priv;
struct winusb_device_handle_priv winusb_priv;
};
struct windows_transfer_priv {
OVERLAPPED overlapped;
HANDLE handle;
union {
struct usbdk_transfer_priv usbdk_priv;
struct winusb_transfer_priv winusb_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->overlapped;
}
static inline void set_transfer_priv_handle(struct usbi_transfer *itransfer, HANDLE handle)
{
struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
transfer_priv->handle = handle;
}
static inline struct usbdk_transfer_priv *get_usbdk_transfer_priv(struct usbi_transfer *itransfer)
{
struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
return &transfer_priv->usbdk_priv;
}
static inline struct winusb_transfer_priv *get_winusb_transfer_priv(struct usbi_transfer *itransfer)
{
struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
return &transfer_priv->winusb_priv;
}
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(struct usbi_transfer *itransfer, ULONG size);
#if defined(ENABLE_LOGGING)
const char *windows_error_str(DWORD error_code);
#endif
#endif

View file

@ -28,7 +28,6 @@
#include "libusbi.h" #include "libusbi.h"
#include "windows_common.h" #include "windows_common.h"
#include "windows_nt_common.h"
#include "windows_usbdk.h" #include "windows_usbdk.h"
#if !defined(STATUS_SUCCESS) #if !defined(STATUS_SUCCESS)
@ -44,28 +43,6 @@ typedef LONG NTSTATUS;
#define STATUS_REQUEST_CANCELED ((NTSTATUS)0xC0000703L) #define STATUS_REQUEST_CANCELED ((NTSTATUS)0xC0000703L)
#endif #endif
#if !defined(USBD_SUCCESS)
typedef LONG USBD_STATUS;
#define USBD_SUCCESS(Status) ((USBD_STATUS) (Status) >= 0)
#define USBD_PENDING(Status) ((ULONG) (Status) >> 30 == 1)
#define USBD_ERROR(Status) ((USBD_STATUS) (Status) < 0)
#define USBD_STATUS_STALL_PID ((USBD_STATUS) 0xc0000004)
#define USBD_STATUS_ENDPOINT_HALTED ((USBD_STATUS) 0xc0000030)
#define USBD_STATUS_BAD_START_FRAME ((USBD_STATUS) 0xc0000a00)
#define USBD_STATUS_TIMEOUT ((USBD_STATUS) 0xc0006000)
#define USBD_STATUS_CANCELED ((USBD_STATUS) 0xc0010000)
#endif
static inline struct usbdk_device_priv *_usbdk_device_priv(struct libusb_device *dev)
{
return (struct usbdk_device_priv *)dev->os_priv;
}
static inline struct usbdk_transfer_priv *_usbdk_transfer_priv(struct usbi_transfer *itransfer)
{
return (struct usbdk_transfer_priv *)usbi_transfer_get_os_priv(itransfer);
}
static struct { static struct {
HMODULE module; HMODULE module;
@ -104,7 +81,7 @@ static void unload_usbdk_helper_dll(void)
static int load_usbdk_helper_dll(struct libusb_context *ctx) 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) { if (usbdk_helper.module == NULL) {
usbi_err(ctx, "Failed to load UsbDkHelper.dll: %s", windows_error_str(0)); usbi_err(ctx, "Failed to load UsbDkHelper.dll: %s", windows_error_str(0));
return LIBUSB_ERROR_NOT_FOUND; return LIBUSB_ERROR_NOT_FOUND;
@ -170,29 +147,65 @@ error_unload:
return LIBUSB_ERROR_NOT_FOUND; return LIBUSB_ERROR_NOT_FOUND;
} }
typedef SC_HANDLE (WINAPI *POPENSCMANAGERA)(LPCSTR, LPCSTR, DWORD);
typedef SC_HANDLE (WINAPI *POPENSERVICEA)(SC_HANDLE, LPCSTR, DWORD);
typedef BOOL (WINAPI *PCLOSESERVICEHANDLE)(SC_HANDLE);
static int usbdk_init(struct libusb_context *ctx) static int usbdk_init(struct libusb_context *ctx)
{ {
POPENSCMANAGERA pOpenSCManagerA;
POPENSERVICEA pOpenServiceA;
PCLOSESERVICEHANDLE pCloseServiceHandle;
SC_HANDLE managerHandle; SC_HANDLE managerHandle;
SC_HANDLE serviceHandle; SC_HANDLE serviceHandle;
HMODULE h;
managerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); h = load_system_library(ctx, "Advapi32");
if (managerHandle == NULL) { if (h == NULL) {
usbi_warn(ctx, "failed to open service control manager: %s", windows_error_str(0)); usbi_warn(ctx, "failed to open Advapi32\n");
return LIBUSB_ERROR_OTHER; return LIBUSB_ERROR_OTHER;
} }
serviceHandle = OpenServiceA(managerHandle, "UsbDk", GENERIC_READ); pOpenSCManagerA = (POPENSCMANAGERA)GetProcAddress(h, "OpenSCManagerA");
CloseServiceHandle(managerHandle); if (pOpenSCManagerA == NULL) {
usbi_warn(ctx, "failed to find %s in Advapi32\n", "OpenSCManagerA");
goto error_free_library;
}
pOpenServiceA = (POPENSERVICEA)GetProcAddress(h, "OpenServiceA");
if (pOpenServiceA == NULL) {
usbi_warn(ctx, "failed to find %s in Advapi32\n", "OpenServiceA");
goto error_free_library;
}
pCloseServiceHandle = (PCLOSESERVICEHANDLE)GetProcAddress(h, "CloseServiceHandle");
if (pCloseServiceHandle == NULL) {
usbi_warn(ctx, "failed to find %s in Advapi32\n", "CloseServiceHandle");
goto error_free_library;
}
managerHandle = pOpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
if (managerHandle == NULL) {
usbi_warn(ctx, "failed to open service control manager: %s", windows_error_str(0));
goto error_free_library;
}
serviceHandle = pOpenServiceA(managerHandle, "UsbDk", GENERIC_READ);
pCloseServiceHandle(managerHandle);
if (serviceHandle == NULL) { if (serviceHandle == NULL) {
if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST) if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
usbi_warn(ctx, "failed to open UsbDk service: %s", windows_error_str(0)); usbi_warn(ctx, "failed to open UsbDk service: %s", windows_error_str(0));
FreeLibrary(h);
return LIBUSB_ERROR_NOT_FOUND; return LIBUSB_ERROR_NOT_FOUND;
} }
CloseServiceHandle(serviceHandle); pCloseServiceHandle(serviceHandle);
FreeLibrary(h);
return load_usbdk_helper_dll(ctx); return load_usbdk_helper_dll(ctx);
error_free_library:
FreeLibrary(h);
return LIBUSB_ERROR_OTHER;
} }
static void usbdk_exit(struct libusb_context *ctx) static void usbdk_exit(struct libusb_context *ctx)
@ -216,26 +229,26 @@ static int usbdk_get_session_id_for_device(struct libusb_context *ctx,
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
static void usbdk_release_config_descriptors(struct usbdk_device_priv *p, uint8_t count) static void usbdk_release_config_descriptors(struct usbdk_device_priv *priv, uint8_t count)
{ {
uint8_t i; uint8_t i;
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
usbdk_helper.ReleaseConfigurationDescriptor(p->config_descriptors[i]); usbdk_helper.ReleaseConfigurationDescriptor(priv->config_descriptors[i]);
free(p->config_descriptors); free(priv->config_descriptors);
p->config_descriptors = NULL; priv->config_descriptors = NULL;
} }
static int usbdk_cache_config_descriptors(struct libusb_context *ctx, static int usbdk_cache_config_descriptors(struct libusb_context *ctx,
struct usbdk_device_priv *p, PUSB_DK_DEVICE_INFO info) struct usbdk_device_priv *priv, PUSB_DK_DEVICE_INFO info)
{ {
uint8_t i; uint8_t i;
USB_DK_CONFIG_DESCRIPTOR_REQUEST Request; USB_DK_CONFIG_DESCRIPTOR_REQUEST Request;
Request.ID = info->ID; Request.ID = info->ID;
p->config_descriptors = calloc(info->DeviceDescriptor.bNumConfigurations, sizeof(PUSB_CONFIGURATION_DESCRIPTOR)); priv->config_descriptors = calloc(info->DeviceDescriptor.bNumConfigurations, sizeof(PUSB_CONFIGURATION_DESCRIPTOR));
if (p->config_descriptors == NULL) { if (priv->config_descriptors == NULL) {
usbi_err(ctx, "failed to allocate configuration descriptors holder"); usbi_err(ctx, "failed to allocate configuration descriptors holder");
return LIBUSB_ERROR_NO_MEM; return LIBUSB_ERROR_NO_MEM;
} }
@ -244,9 +257,9 @@ static int usbdk_cache_config_descriptors(struct libusb_context *ctx,
ULONG Length; ULONG Length;
Request.Index = i; Request.Index = i;
if (!usbdk_helper.GetConfigurationDescriptor(&Request, &p->config_descriptors[i], &Length)) { if (!usbdk_helper.GetConfigurationDescriptor(&Request, &priv->config_descriptors[i], &Length)) {
usbi_err(ctx, "failed to retrieve configuration descriptors"); usbi_err(ctx, "failed to retrieve configuration descriptors");
usbdk_release_config_descriptors(p, i); usbdk_release_config_descriptors(priv, i);
return LIBUSB_ERROR_OTHER; return LIBUSB_ERROR_OTHER;
} }
} }
@ -256,15 +269,15 @@ static int usbdk_cache_config_descriptors(struct libusb_context *ctx,
static inline int usbdk_device_priv_init(struct libusb_context *ctx, struct libusb_device *dev, PUSB_DK_DEVICE_INFO info) static inline int usbdk_device_priv_init(struct libusb_context *ctx, struct libusb_device *dev, PUSB_DK_DEVICE_INFO info)
{ {
struct usbdk_device_priv *p = _usbdk_device_priv(dev); struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
p->info = *info; priv->ID = info->ID;
p->active_configuration = 0; priv->active_configuration = 0;
return usbdk_cache_config_descriptors(ctx, p, info); return usbdk_cache_config_descriptors(ctx, priv, info);
} }
static void usbdk_device_init(libusb_device *dev, PUSB_DK_DEVICE_INFO info) static void usbdk_device_init(struct libusb_device *dev, PUSB_DK_DEVICE_INFO info)
{ {
dev->bus_number = (uint8_t)info->FilterID; dev->bus_number = (uint8_t)info->FilterID;
dev->port_number = (uint8_t)info->Port; dev->port_number = (uint8_t)info->Port;
@ -273,8 +286,10 @@ static void usbdk_device_init(libusb_device *dev, PUSB_DK_DEVICE_INFO info)
// Addresses in libusb are 1-based // Addresses in libusb are 1-based
dev->device_address = (uint8_t)(info->Port + 1); dev->device_address = (uint8_t)(info->Port + 1);
dev->num_configurations = info->DeviceDescriptor.bNumConfigurations; static_assert(sizeof(dev->device_descriptor) == sizeof(info->DeviceDescriptor),
"mismatch between libusb and OS device descriptor sizes");
memcpy(&dev->device_descriptor, &info->DeviceDescriptor, LIBUSB_DT_DEVICE_SIZE); memcpy(&dev->device_descriptor, &info->DeviceDescriptor, LIBUSB_DT_DEVICE_SIZE);
usbi_localize_device_descriptor(&dev->device_descriptor);
switch (info->Speed) { switch (info->Speed) {
case LowSpeed: case LowSpeed:
@ -345,24 +360,12 @@ func_exit:
return r; return r;
} }
static int usbdk_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer) static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, void *buffer, size_t len)
{ {
struct usbdk_device_priv *priv = _usbdk_device_priv(dev); struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
memcpy(buffer, &priv->info.DeviceDescriptor, DEVICE_DESC_LENGTH);
return LIBUSB_SUCCESS;
}
static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len)
{
struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
PUSB_CONFIGURATION_DESCRIPTOR config_header; PUSB_CONFIGURATION_DESCRIPTOR config_header;
size_t size; size_t size;
if (config_index >= dev->num_configurations)
return LIBUSB_ERROR_INVALID_PARAM;
config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptors[config_index]; config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptors[config_index];
size = min(config_header->wTotalLength, len); size = min(config_header->wTotalLength, len);
@ -371,16 +374,16 @@ static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config
} }
static int usbdk_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue, static int usbdk_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue,
unsigned char **buffer) void **buffer)
{ {
struct usbdk_device_priv *priv = _usbdk_device_priv(dev); struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
PUSB_CONFIGURATION_DESCRIPTOR config_header; PUSB_CONFIGURATION_DESCRIPTOR config_header;
uint8_t index; uint8_t index;
for (index = 0; index < dev->num_configurations; index++) { for (index = 0; index < dev->device_descriptor.bNumConfigurations; index++) {
config_header = priv->config_descriptors[index]; config_header = priv->config_descriptors[index];
if (config_header->bConfigurationValue == bConfigurationValue) { if (config_header->bConfigurationValue == bConfigurationValue) {
*buffer = (unsigned char *)priv->config_descriptors[index]; *buffer = priv->config_descriptors[index];
return (int)config_header->wTotalLength; return (int)config_header->wTotalLength;
} }
} }
@ -388,70 +391,87 @@ static int usbdk_get_config_descriptor_by_value(struct libusb_device *dev, uint8
return LIBUSB_ERROR_NOT_FOUND; return LIBUSB_ERROR_NOT_FOUND;
} }
static int usbdk_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len) static int usbdk_get_active_config_descriptor(struct libusb_device *dev, void *buffer, size_t len)
{ {
return usbdk_get_config_descriptor(dev, _usbdk_device_priv(dev)->active_configuration, struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
buffer, len);
return usbdk_get_config_descriptor(dev, priv->active_configuration, buffer, len);
} }
static int usbdk_open(struct libusb_device_handle *dev_handle) static int usbdk_open(struct libusb_device_handle *dev_handle)
{ {
struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev); 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);
priv->redirector_handle = usbdk_helper.StartRedirect(&priv->info.ID); device_priv->redirector_handle = usbdk_helper.StartRedirect(&device_priv->ID);
if (priv->redirector_handle == INVALID_HANDLE_VALUE) { if (device_priv->redirector_handle == INVALID_HANDLE_VALUE) {
usbi_err(DEVICE_CTX(dev_handle->dev), "Redirector startup failed"); usbi_err(ctx, "Redirector startup failed");
device_priv->redirector_handle = NULL;
return LIBUSB_ERROR_OTHER; 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; return LIBUSB_SUCCESS;
} }
static void usbdk_close(struct libusb_device_handle *dev_handle) static void usbdk_close(struct libusb_device_handle *dev_handle)
{ {
struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev); struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
if (!usbdk_helper.StopRedirect(priv->redirector_handle)) if (!usbdk_helper.StopRedirect(priv->redirector_handle))
usbi_err(HANDLE_CTX(dev_handle), "Redirector shutdown failed"); 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, int *config) static int usbdk_get_configuration(struct libusb_device_handle *dev_handle, uint8_t *config)
{ {
*config = _usbdk_device_priv(dev_handle->dev)->active_configuration; struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
*config = priv->active_configuration;
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
static int usbdk_set_configuration(struct libusb_device_handle *dev_handle, int config) static int usbdk_set_configuration(struct libusb_device_handle *dev_handle, uint8_t config)
{ {
UNUSED(dev_handle); UNUSED(dev_handle);
UNUSED(config); UNUSED(config);
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, int iface) static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, uint8_t iface)
{ {
UNUSED(dev_handle); UNUSED(dev_handle);
UNUSED(iface); UNUSED(iface);
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting)
{ {
struct libusb_context *ctx = HANDLE_CTX(dev_handle); struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
if (!usbdk_helper.SetAltsetting(priv->redirector_handle, iface, altsetting)) { if (!usbdk_helper.SetAltsetting(priv->redirector_handle, iface, altsetting)) {
usbi_err(ctx, "SetAltsetting failed: %s", windows_error_str(0)); usbi_err(HANDLE_CTX(dev_handle), "SetAltsetting failed: %s", windows_error_str(0));
return LIBUSB_ERROR_NO_DEVICE; return LIBUSB_ERROR_NO_DEVICE;
} }
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
static int usbdk_release_interface(struct libusb_device_handle *dev_handle, int iface) static int usbdk_release_interface(struct libusb_device_handle *dev_handle, uint8_t iface)
{ {
UNUSED(dev_handle); UNUSED(dev_handle);
UNUSED(iface); UNUSED(iface);
@ -460,11 +480,10 @@ static int usbdk_release_interface(struct libusb_device_handle *dev_handle, int
static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
{ {
struct libusb_context *ctx = HANDLE_CTX(dev_handle); struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
if (!usbdk_helper.ResetPipe(priv->redirector_handle, endpoint)) { if (!usbdk_helper.ResetPipe(priv->redirector_handle, endpoint)) {
usbi_err(ctx, "ResetPipe failed: %s", windows_error_str(0)); usbi_err(HANDLE_CTX(dev_handle), "ResetPipe failed: %s", windows_error_str(0));
return LIBUSB_ERROR_NO_DEVICE; return LIBUSB_ERROR_NO_DEVICE;
} }
@ -473,11 +492,10 @@ static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned ch
static int usbdk_reset_device(struct libusb_device_handle *dev_handle) static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
{ {
struct libusb_context *ctx = HANDLE_CTX(dev_handle); struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
if (!usbdk_helper.ResetDevice(priv->redirector_handle)) { if (!usbdk_helper.ResetDevice(priv->redirector_handle)) {
usbi_err(ctx, "ResetDevice failed: %s", windows_error_str(0)); usbi_err(HANDLE_CTX(dev_handle), "ResetDevice failed: %s", windows_error_str(0));
return LIBUSB_ERROR_NO_DEVICE; return LIBUSB_ERROR_NO_DEVICE;
} }
@ -486,21 +504,17 @@ static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
static void usbdk_destroy_device(struct libusb_device *dev) static void usbdk_destroy_device(struct libusb_device *dev)
{ {
struct usbdk_device_priv* p = _usbdk_device_priv(dev); struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
if (p->config_descriptors != NULL) if (priv->config_descriptors != NULL)
usbdk_release_config_descriptors(p, p->info.DeviceDescriptor.bNumConfigurations); usbdk_release_config_descriptors(priv, dev->device_descriptor.bNumConfigurations);
} }
static void usbdk_clear_transfer_priv(struct usbi_transfer *itransfer) static void usbdk_clear_transfer_priv(struct usbi_transfer *itransfer)
{ {
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
usbi_close(transfer_priv->pollable_fd.fd);
transfer_priv->pollable_fd = INVALID_WINFD;
transfer_priv->system_handle = NULL;
if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
safe_free(transfer_priv->IsochronousPacketsArray); safe_free(transfer_priv->IsochronousPacketsArray);
safe_free(transfer_priv->IsochronousResultsArray); safe_free(transfer_priv->IsochronousResultsArray);
@ -510,16 +524,17 @@ static void usbdk_clear_transfer_priv(struct usbi_transfer *itransfer)
static int usbdk_do_control_transfer(struct usbi_transfer *itransfer) static int usbdk_do_control_transfer(struct usbi_transfer *itransfer)
{ {
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev); struct usbdk_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
struct libusb_context *ctx = TRANSFER_CTX(transfer); OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer);
OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
TransferResult transResult; TransferResult transResult;
transfer_priv->request.Buffer = (PVOID64)transfer->buffer; transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
transfer_priv->request.BufferLength = transfer->length; transfer_priv->request.BufferLength = transfer->length;
transfer_priv->request.TransferType = ControlTransferType; transfer_priv->request.TransferType = ControlTransferType;
set_transfer_priv_handle(itransfer, priv->system_handle);
if (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) if (transfer->buffer[0] & LIBUSB_ENDPOINT_IN)
transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped); transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
else else
@ -527,12 +542,12 @@ static int usbdk_do_control_transfer(struct usbi_transfer *itransfer)
switch (transResult) { switch (transResult) {
case TransferSuccess: 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; break;
case TransferSuccessAsync: case TransferSuccessAsync:
break; break;
case TransferFailure: case TransferFailure:
usbi_err(ctx, "ControlTransfer failed: %s", windows_error_str(0)); usbi_err(TRANSFER_CTX(transfer), "ControlTransfer failed: %s", windows_error_str(0));
return LIBUSB_ERROR_IO; return LIBUSB_ERROR_IO;
} }
@ -542,10 +557,9 @@ static int usbdk_do_control_transfer(struct usbi_transfer *itransfer)
static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer) static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
{ {
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev); struct usbdk_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
struct libusb_context *ctx = TRANSFER_CTX(transfer); OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer);
OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
TransferResult transferRes; TransferResult transferRes;
transfer_priv->request.Buffer = (PVOID64)transfer->buffer; transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
@ -559,11 +573,10 @@ static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
case LIBUSB_TRANSFER_TYPE_INTERRUPT: case LIBUSB_TRANSFER_TYPE_INTERRUPT:
transfer_priv->request.TransferType = InterruptTransferType; transfer_priv->request.TransferType = InterruptTransferType;
break; break;
default:
usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer", transfer->type);
return LIBUSB_ERROR_INVALID_PARAM;
} }
set_transfer_priv_handle(itransfer, priv->system_handle);
if (IS_XFERIN(transfer)) if (IS_XFERIN(transfer))
transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped); transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
else else
@ -571,12 +584,12 @@ static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
switch (transferRes) { switch (transferRes) {
case TransferSuccess: 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; break;
case TransferSuccessAsync: case TransferSuccessAsync:
break; break;
case TransferFailure: case TransferFailure:
usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0)); usbi_err(TRANSFER_CTX(transfer), "ReadPipe/WritePipe failed: %s", windows_error_str(0));
return LIBUSB_ERROR_IO; return LIBUSB_ERROR_IO;
} }
@ -586,10 +599,9 @@ static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer) static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
{ {
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev); struct usbdk_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
struct libusb_context *ctx = TRANSFER_CTX(transfer); OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer);
OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
TransferResult transferRes; TransferResult transferRes;
int i; int i;
@ -601,20 +613,22 @@ static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
transfer_priv->IsochronousPacketsArray = malloc(transfer->num_iso_packets * sizeof(ULONG64)); transfer_priv->IsochronousPacketsArray = malloc(transfer->num_iso_packets * sizeof(ULONG64));
transfer_priv->request.IsochronousPacketsArray = (PVOID64)transfer_priv->IsochronousPacketsArray; transfer_priv->request.IsochronousPacketsArray = (PVOID64)transfer_priv->IsochronousPacketsArray;
if (!transfer_priv->IsochronousPacketsArray) { if (!transfer_priv->IsochronousPacketsArray) {
usbi_err(ctx, "Allocation of IsochronousPacketsArray failed"); usbi_err(TRANSFER_CTX(transfer), "Allocation of IsochronousPacketsArray failed");
return LIBUSB_ERROR_NO_MEM; return LIBUSB_ERROR_NO_MEM;
} }
transfer_priv->IsochronousResultsArray = malloc(transfer->num_iso_packets * sizeof(USB_DK_ISO_TRANSFER_RESULT)); transfer_priv->IsochronousResultsArray = malloc(transfer->num_iso_packets * sizeof(USB_DK_ISO_TRANSFER_RESULT));
transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)transfer_priv->IsochronousResultsArray; transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)transfer_priv->IsochronousResultsArray;
if (!transfer_priv->IsochronousResultsArray) { if (!transfer_priv->IsochronousResultsArray) {
usbi_err(ctx, "Allocation of isochronousResultsArray failed"); usbi_err(TRANSFER_CTX(transfer), "Allocation of isochronousResultsArray failed");
return LIBUSB_ERROR_NO_MEM; return LIBUSB_ERROR_NO_MEM;
} }
for (i = 0; i < transfer->num_iso_packets; i++) for (i = 0; i < transfer->num_iso_packets; i++)
transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length; transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length;
set_transfer_priv_handle(itransfer, priv->system_handle);
if (IS_XFERIN(transfer)) if (IS_XFERIN(transfer))
transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped); transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
else else
@ -622,7 +636,7 @@ static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
switch (transferRes) { switch (transferRes) {
case TransferSuccess: 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; break;
case TransferSuccessAsync: case TransferSuccessAsync:
break; break;
@ -633,151 +647,38 @@ static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
static int usbdk_do_submit_transfer(struct usbi_transfer *itransfer,
short events, int (*transfer_fn)(struct usbi_transfer *))
{
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct libusb_context *ctx = TRANSFER_CTX(transfer);
struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
struct winfd wfd;
int r;
wfd = usbi_create_fd();
if (wfd.fd < 0)
return LIBUSB_ERROR_NO_MEM;
r = usbi_add_pollfd(ctx, wfd.fd, events);
if (r) {
usbi_close(wfd.fd);
return r;
}
// Use transfer_priv to store data needed for async polling
transfer_priv->pollable_fd = wfd;
transfer_priv->system_handle = priv->system_handle;
r = transfer_fn(itransfer);
if (r != LIBUSB_SUCCESS) {
usbi_remove_pollfd(ctx, wfd.fd);
usbdk_clear_transfer_priv(itransfer);
return r;
}
return LIBUSB_SUCCESS;
}
static int usbdk_submit_transfer(struct usbi_transfer *itransfer) static int usbdk_submit_transfer(struct usbi_transfer *itransfer)
{ {
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
int (*transfer_fn)(struct usbi_transfer *);
short events;
switch (transfer->type) { switch (transfer->type) {
case LIBUSB_TRANSFER_TYPE_CONTROL: case LIBUSB_TRANSFER_TYPE_CONTROL:
events = (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) ? POLLIN : POLLOUT; return usbdk_do_control_transfer(itransfer);
transfer_fn = usbdk_do_control_transfer;
break;
case LIBUSB_TRANSFER_TYPE_BULK: case LIBUSB_TRANSFER_TYPE_BULK:
case LIBUSB_TRANSFER_TYPE_INTERRUPT: case LIBUSB_TRANSFER_TYPE_INTERRUPT:
if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET)) if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
return LIBUSB_ERROR_NOT_SUPPORTED; //TODO: Check whether we can support this in UsbDk return LIBUSB_ERROR_NOT_SUPPORTED; //TODO: Check whether we can support this in UsbDk
events = IS_XFERIN(transfer) ? POLLIN : POLLOUT; return usbdk_do_bulk_transfer(itransfer);
transfer_fn = usbdk_do_bulk_transfer;
break;
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
events = IS_XFERIN(transfer) ? POLLIN : POLLOUT; return usbdk_do_iso_transfer(itransfer);
transfer_fn = usbdk_do_iso_transfer;
break;
default: default:
usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); // Should not get here since windows_submit_transfer() validates
return LIBUSB_ERROR_INVALID_PARAM; // the transfer->type field
usbi_err(TRANSFER_CTX(transfer), "unsupported endpoint type %d", transfer->type);
return LIBUSB_ERROR_NOT_SUPPORTED;
}
} }
return usbdk_do_submit_transfer(itransfer, events, transfer_fn); static enum libusb_transfer_status usbdk_copy_transfer_data(struct usbi_transfer *itransfer, DWORD length)
}
static int usbdk_abort_transfers(struct usbi_transfer *itransfer)
{ {
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct libusb_context *ctx = TRANSFER_CTX(transfer); struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
struct winfd *pollable_fd = &transfer_priv->pollable_fd;
if (pCancelIoEx != NULL) { UNUSED(length);
// Use CancelIoEx if available to cancel just a single transfer
if (!pCancelIoEx(priv->system_handle, pollable_fd->overlapped)) {
usbi_err(ctx, "CancelIoEx failed: %s", windows_error_str(0));
return LIBUSB_ERROR_NO_DEVICE;
}
} else {
if (!usbdk_helper.AbortPipe(priv->redirector_handle, transfer->endpoint)) {
usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0));
return LIBUSB_ERROR_NO_DEVICE;
}
}
return LIBUSB_SUCCESS;
}
static int usbdk_cancel_transfer(struct usbi_transfer *itransfer)
{
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
switch (transfer->type) {
case LIBUSB_TRANSFER_TYPE_CONTROL:
// Control transfers cancelled by IoCancelXXX() API
// No special treatment needed
return LIBUSB_SUCCESS;
case LIBUSB_TRANSFER_TYPE_BULK:
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
return usbdk_abort_transfers(itransfer);
default:
usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
return LIBUSB_ERROR_INVALID_PARAM;
}
}
static int usbdk_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
{
itransfer->transferred += io_size;
return LIBUSB_TRANSFER_COMPLETED;
}
static int usbdk_get_transfer_fd(struct usbi_transfer *itransfer)
{
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
return transfer_priv->pollable_fd.fd;
}
static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus)
{
if (USBD_SUCCESS(UsbdStatus))
return NO_ERROR;
switch (UsbdStatus) {
case USBD_STATUS_TIMEOUT:
return ERROR_SEM_TIMEOUT;
case USBD_STATUS_CANCELED:
return ERROR_OPERATION_ABORTED;
default:
return ERROR_GEN_FAILURE;
}
}
static void usbdk_get_overlapped_result(struct usbi_transfer *itransfer, DWORD *io_result, DWORD *io_size)
{
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
struct winfd *pollable_fd = &transfer_priv->pollable_fd;
if (HasOverlappedIoCompletedSync(pollable_fd->overlapped) // Handle async requests that completed synchronously first
|| GetOverlappedResult(transfer_priv->system_handle, pollable_fd->overlapped, io_size, FALSE)) { // Regular async overlapped
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
ULONG64 i; ULONG64 i;
for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) { for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) {
struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i]; struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i];
@ -796,11 +697,8 @@ static void usbdk_get_overlapped_result(struct usbi_transfer *itransfer, DWORD *
} }
} }
*io_size = (DWORD)transfer_priv->request.Result.GenResult.BytesTransferred; itransfer->transferred += (int)transfer_priv->request.Result.GenResult.BytesTransferred;
*io_result = usbdk_translate_usbd_status((USBD_STATUS)transfer_priv->request.Result.GenResult.UsbdStatus); return usbd_status_to_libusb_transfer_status((USBD_STATUS)transfer_priv->request.Result.GenResult.UsbdStatus);
} else {
*io_result = GetLastError();
}
} }
const struct windows_backend usbdk_backend = { const struct windows_backend usbdk_backend = {
@ -809,7 +707,6 @@ const struct windows_backend usbdk_backend = {
usbdk_get_device_list, usbdk_get_device_list,
usbdk_open, usbdk_open,
usbdk_close, usbdk_close,
usbdk_get_device_descriptor,
usbdk_get_active_config_descriptor, usbdk_get_active_config_descriptor,
usbdk_get_config_descriptor, usbdk_get_config_descriptor,
usbdk_get_config_descriptor_by_value, usbdk_get_config_descriptor_by_value,
@ -822,9 +719,7 @@ const struct windows_backend usbdk_backend = {
usbdk_reset_device, usbdk_reset_device,
usbdk_destroy_device, usbdk_destroy_device,
usbdk_submit_transfer, usbdk_submit_transfer,
usbdk_cancel_transfer, NULL, /* cancel_transfer */
usbdk_clear_transfer_priv, usbdk_clear_transfer_priv,
usbdk_copy_transfer_data, usbdk_copy_transfer_data,
usbdk_get_transfer_fd,
usbdk_get_overlapped_result,
}; };

View file

@ -21,9 +21,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#pragma once #ifndef LIBUSB_WINDOWS_USBDK_H
#define LIBUSB_WINDOWS_USBDK_H
#include "windows_nt_common.h" #include "windows_common.h"
typedef struct USB_DK_CONFIG_DESCRIPTOR_REQUEST { typedef struct USB_DK_CONFIG_DESCRIPTOR_REQUEST {
USB_DK_DEVICE_ID ID; USB_DK_DEVICE_ID ID;
@ -101,3 +102,5 @@ typedef BOOL (__cdecl *USBDK_RESET_DEVICE)(
typedef HANDLE (__cdecl *USBDK_GET_REDIRECTOR_SYSTEM_HANDLE)( typedef HANDLE (__cdecl *USBDK_GET_REDIRECTOR_SYSTEM_HANDLE)(
HANDLE DeviceHandle HANDLE DeviceHandle
); );
#endif

File diff suppressed because it is too large Load diff

View file

@ -20,19 +20,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#pragma once #ifndef LIBUSB_WINDOWS_WINUSB_H
#define LIBUSB_WINDOWS_WINUSB_H
#include "windows_common.h" #include "windows_common.h"
#include "windows_nt_common.h"
#if defined(_MSC_VER) #if defined(_MSC_VER)
// disable /W4 MSVC warnings that are benign // disable /W4 MSVC warnings that are benign
#pragma warning(disable:4100) // unreferenced formal parameter
#pragma warning(disable:4127) // conditional expression is constant
#pragma warning(disable:4201) // nameless struct/union
#pragma warning(disable:4214) // bit field types other than int #pragma warning(disable:4214) // bit field types other than int
#pragma warning(disable:4996) // deprecated API calls
#pragma warning(disable:28159) // more deprecated API calls
#endif #endif
// Missing from MSVC6 setupapi.h // Missing from MSVC6 setupapi.h
@ -48,7 +43,7 @@
#define MAX_HID_REPORT_SIZE 1024 #define MAX_HID_REPORT_SIZE 1024
#define MAX_HID_DESCRIPTOR_SIZE 256 #define MAX_HID_DESCRIPTOR_SIZE 256
#define MAX_GUID_STRING_LENGTH 40 #define MAX_GUID_STRING_LENGTH 40
#define MAX_PATH_LENGTH 128 #define MAX_PATH_LENGTH 256
#define MAX_KEY_LENGTH 256 #define MAX_KEY_LENGTH 256
#define LIST_SEPARATOR ';' #define LIST_SEPARATOR ';'
@ -73,6 +68,8 @@ const GUID GUID_DEVINTERFACE_USB_HUB = {0xF18A0E88, 0xC30C, 0x11D0, {0x88, 0x15,
const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = {0xF9F3FF14, 0xAE21, 0x48A0, {0x8A, 0x25, 0x80, 0x11, 0xA7, 0xA9, 0x31, 0xD9}}; const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = {0xF9F3FF14, 0xAE21, 0x48A0, {0x8A, 0x25, 0x80, 0x11, 0xA7, 0xA9, 0x31, 0xD9}};
#endif #endif
// The following define MUST be == sizeof(USB_DESCRIPTOR_REQUEST)
#define USB_DESCRIPTOR_REQUEST_SIZE 12U
/* /*
* Multiple USB API backend support * Multiple USB API backend support
@ -97,22 +94,21 @@ struct windows_usb_api_backend {
const char * const designation; const char * const designation;
const char * const * const driver_name_list; // Driver name, without .sys, e.g. "usbccgp" const char * const * const driver_name_list; // Driver name, without .sys, e.g. "usbccgp"
const uint8_t nb_driver_names; const uint8_t nb_driver_names;
int (*init)(struct libusb_context *ctx); bool (*init)(struct libusb_context *ctx);
void (*exit)(void); void (*exit)(void);
int (*open)(int sub_api, struct libusb_device_handle *dev_handle); int (*open)(int sub_api, struct libusb_device_handle *dev_handle);
void (*close)(int sub_api, struct libusb_device_handle *dev_handle); void (*close)(int sub_api, struct libusb_device_handle *dev_handle);
int (*configure_endpoints)(int sub_api, struct libusb_device_handle *dev_handle, int iface); int (*configure_endpoints)(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
int (*claim_interface)(int sub_api, struct libusb_device_handle *dev_handle, int iface); int (*claim_interface)(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
int (*set_interface_altsetting)(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting); int (*set_interface_altsetting)(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting);
int (*release_interface)(int sub_api, struct libusb_device_handle *dev_handle, int iface); int (*release_interface)(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
int (*clear_halt)(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint); int (*clear_halt)(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
int (*reset_device)(int sub_api, struct libusb_device_handle *dev_handle); int (*reset_device)(int sub_api, struct libusb_device_handle *dev_handle);
int (*submit_bulk_transfer)(int sub_api, struct usbi_transfer *itransfer); int (*submit_bulk_transfer)(int sub_api, struct usbi_transfer *itransfer);
int (*submit_iso_transfer)(int sub_api, struct usbi_transfer *itransfer); int (*submit_iso_transfer)(int sub_api, struct usbi_transfer *itransfer);
int (*submit_control_transfer)(int sub_api, struct usbi_transfer *itransfer); int (*submit_control_transfer)(int sub_api, struct usbi_transfer *itransfer);
int (*abort_control)(int sub_api, struct usbi_transfer *itransfer); int (*cancel_transfer)(int sub_api, struct usbi_transfer *itransfer);
int (*abort_transfers)(int sub_api, struct usbi_transfer *itransfer); enum libusb_transfer_status (*copy_transfer_data)(int sub_api, struct usbi_transfer *itransfer, DWORD length);
int (*copy_transfer_data)(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size);
}; };
extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX]; extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX];
@ -202,51 +198,43 @@ struct hid_device_priv {
uint8_t string_index[3]; // man, prod, ser uint8_t string_index[3]; // man, prod, ser
}; };
static inline struct winusb_device_priv *_device_priv(struct libusb_device *dev)
{
return (struct winusb_device_priv *)dev->os_priv;
}
static inline struct winusb_device_priv *winusb_device_priv_init(struct libusb_device *dev) static inline struct winusb_device_priv *winusb_device_priv_init(struct libusb_device *dev)
{ {
struct winusb_device_priv *p = _device_priv(dev); struct winusb_device_priv *priv = usbi_get_device_priv(dev);
int i; int i;
p->apib = &usb_api_backend[USB_API_UNSUPPORTED]; priv->apib = &usb_api_backend[USB_API_UNSUPPORTED];
p->sub_api = SUB_API_NOTSET; priv->sub_api = SUB_API_NOTSET;
for (i = 0; i < USB_MAXINTERFACES; i++) { for (i = 0; i < USB_MAXINTERFACES; i++) {
p->usb_interface[i].apib = &usb_api_backend[USB_API_UNSUPPORTED]; priv->usb_interface[i].apib = &usb_api_backend[USB_API_UNSUPPORTED];
p->usb_interface[i].sub_api = SUB_API_NOTSET; priv->usb_interface[i].sub_api = SUB_API_NOTSET;
} }
return p; return priv;
} }
static inline void winusb_device_priv_release(struct libusb_device *dev) static inline void winusb_device_priv_release(struct libusb_device *dev)
{ {
struct winusb_device_priv *p = _device_priv(dev); struct winusb_device_priv *priv = usbi_get_device_priv(dev);
int i; int i;
free(p->dev_id); free(priv->dev_id);
free(p->path); free(priv->path);
if ((dev->num_configurations > 0) && (p->config_descriptor != NULL)) { if ((dev->device_descriptor.bNumConfigurations > 0) && (priv->config_descriptor != NULL)) {
for (i = 0; i < dev->num_configurations; i++) for (i = 0; i < dev->device_descriptor.bNumConfigurations; i++) {
free(p->config_descriptor[i]); if (priv->config_descriptor[i] == NULL)
continue;
free((UCHAR *)priv->config_descriptor[i] - USB_DESCRIPTOR_REQUEST_SIZE);
} }
free(p->config_descriptor); }
free(p->hid); free(priv->config_descriptor);
free(priv->hid);
for (i = 0; i < USB_MAXINTERFACES; i++) { for (i = 0; i < USB_MAXINTERFACES; i++) {
free(p->usb_interface[i].path); free(priv->usb_interface[i].path);
free(p->usb_interface[i].endpoint); free(priv->usb_interface[i].endpoint);
} }
} }
static inline struct winusb_device_handle_priv *_device_handle_priv(
struct libusb_device_handle *handle)
{
return (struct winusb_device_handle_priv *)handle->os_priv;
}
// used to match a device driver (including filter drivers) against a supported API // used to match a device driver (including filter drivers) against a supported API
struct driver_lookup { struct driver_lookup {
char list[MAX_KEY_LENGTH + 1]; // REG_MULTI_SZ list of services (driver) names char list[MAX_KEY_LENGTH + 1]; // REG_MULTI_SZ list of services (driver) names
@ -295,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)); 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 #ifndef USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION
#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260 #define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260
#endif #endif
@ -312,6 +303,9 @@ DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDeviceInterfaceRegKey, (HD
#define USB_CTL_CODE(id) \ #define USB_CTL_CODE(id) \
CTL_CODE(FILE_DEVICE_USB, (id), METHOD_BUFFERED, FILE_ANY_ACCESS) 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 \ #define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \
USB_CTL_CODE(USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION) USB_CTL_CODE(USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION)
@ -321,7 +315,7 @@ DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDeviceInterfaceRegKey, (HD
#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 \ #define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 \
USB_CTL_CODE(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, NoDeviceConnected,
DeviceConnected, DeviceConnected,
DeviceFailedEnumeration, DeviceFailedEnumeration,
@ -330,10 +324,20 @@ typedef enum USB_CONNECTION_STATUS {
DeviceNotEnoughPower, DeviceNotEnoughPower,
DeviceNotEnoughBandwidth, DeviceNotEnoughBandwidth,
DeviceHubNestedTooDeeply, DeviceHubNestedTooDeeply,
DeviceInLegacyHub DeviceInLegacyHub,
} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS; DeviceEnumerating,
DeviceReset
} USB_CONNECTION_STATUS;
typedef enum USB_HUB_NODE { typedef enum _USB_DEVICE_SPEED {
UsbLowSpeed = 0,
UsbFullSpeed,
UsbHighSpeed,
UsbSuperSpeed,
UsbSuperSpeedPlus // Not in Microsoft headers
} USB_DEVICE_SPEED;
typedef enum _USB_HUB_NODE {
UsbHub, UsbHub,
UsbMIParent UsbMIParent
} USB_HUB_NODE; } USB_HUB_NODE;
@ -341,6 +345,29 @@ typedef enum USB_HUB_NODE {
// Most of the structures below need to be packed // Most of the structures below need to be packed
#include <pshpack1.h> #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 { typedef struct _USB_DESCRIPTOR_REQUEST {
ULONG ConnectionIndex; ULONG ConnectionIndex;
struct { struct {
@ -426,6 +453,12 @@ typedef struct _USB_NODE_CONNECTION_INFORMATION_EX_V2 {
/* libusbK */ /* libusbK */
#define ISO_ALWAYS_START_ASAP 0x21 #define ISO_ALWAYS_START_ASAP 0x21
typedef struct _USBD_ISO_PACKET_DESCRIPTOR {
ULONG Offset;
ULONG Length;
USBD_STATUS Status;
} USBD_ISO_PACKET_DESCRIPTOR, *PUSBD_ISO_PACKET_DESCRIPTOR;
typedef enum _USBD_PIPE_TYPE { typedef enum _USBD_PIPE_TYPE {
UsbdPipeTypeControl, UsbdPipeTypeControl,
UsbdPipeTypeIsochronous, UsbdPipeTypeIsochronous,
@ -433,6 +466,14 @@ typedef enum _USBD_PIPE_TYPE {
UsbdPipeTypeInterrupt UsbdPipeTypeInterrupt
} USBD_PIPE_TYPE; } USBD_PIPE_TYPE;
typedef struct {
USBD_PIPE_TYPE PipeType;
UCHAR PipeId;
USHORT MaximumPacketSize;
UCHAR Interval;
ULONG MaximumBytesPerInterval;
} WINUSB_PIPE_INFORMATION_EX, *PWINUSB_PIPE_INFORMATION_EX;
#include <pshpack1.h> #include <pshpack1.h>
typedef struct _WINUSB_SETUP_PACKET { typedef struct _WINUSB_SETUP_PACKET {
@ -445,7 +486,8 @@ typedef struct _WINUSB_SETUP_PACKET {
#include <poppack.h> #include <poppack.h>
typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE; typedef PVOID WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE;
typedef PVOID WINUSB_ISOCH_BUFFER_HANDLE, *PWINUSB_ISOCH_BUFFER_HANDLE;
typedef BOOL (WINAPI *WinUsb_AbortPipe_t)( typedef BOOL (WINAPI *WinUsb_AbortPipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle, WINUSB_INTERFACE_HANDLE InterfaceHandle,
@ -475,6 +517,21 @@ typedef BOOL (WINAPI *WinUsb_Initialize_t)(
HANDLE DeviceHandle, HANDLE DeviceHandle,
PWINUSB_INTERFACE_HANDLE InterfaceHandle PWINUSB_INTERFACE_HANDLE InterfaceHandle
); );
typedef BOOL (WINAPI *WinUsb_QueryPipeEx_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR AlternateInterfaceHandle,
UCHAR PipeIndex,
PWINUSB_PIPE_INFORMATION_EX PipeInformationEx
);
typedef BOOL (WINAPI *WinUsb_ReadIsochPipeAsap_t)(
PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
ULONG Offset,
ULONG Length,
BOOL ContinueStream,
ULONG NumberOfPackets,
PUSBD_ISO_PACKET_DESCRIPTOR IsoPacketDescriptors,
LPOVERLAPPED Overlapped
);
typedef BOOL (WINAPI *WinUsb_ReadPipe_t)( typedef BOOL (WINAPI *WinUsb_ReadPipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle, WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID, UCHAR PipeID,
@ -483,8 +540,12 @@ typedef BOOL (WINAPI *WinUsb_ReadPipe_t)(
PULONG LengthTransferred, PULONG LengthTransferred,
LPOVERLAPPED Overlapped LPOVERLAPPED Overlapped
); );
typedef BOOL (WINAPI *WinUsb_ResetDevice_t)( typedef BOOL (WINAPI *WinUsb_RegisterIsochBuffer_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
PVOID Buffer,
ULONG BufferLength,
PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle
); );
typedef BOOL (WINAPI *WinUsb_ResetPipe_t)( typedef BOOL (WINAPI *WinUsb_ResetPipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle, WINUSB_INTERFACE_HANDLE InterfaceHandle,
@ -501,29 +562,9 @@ typedef BOOL (WINAPI *WinUsb_SetPipePolicy_t)(
ULONG ValueLength, ULONG ValueLength,
PVOID Value PVOID Value
); );
typedef BOOL (WINAPI *WinUsb_WritePipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
PUCHAR Buffer,
ULONG BufferLength,
PULONG LengthTransferred,
LPOVERLAPPED Overlapped
);
typedef PVOID WINUSB_ISOCH_BUFFER_HANDLE, *PWINUSB_ISOCH_BUFFER_HANDLE;
typedef BOOL (WINAPI *WinUsb_RegisterIsochBuffer_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
PVOID Buffer,
ULONG BufferLength,
PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle
);
typedef BOOL (WINAPI *WinUsb_UnregisterIsochBuffer_t)( typedef BOOL (WINAPI *WinUsb_UnregisterIsochBuffer_t)(
WINUSB_ISOCH_BUFFER_HANDLE BufferHandle WINUSB_ISOCH_BUFFER_HANDLE BufferHandle
); );
typedef BOOL (WINAPI *WinUsb_WriteIsochPipeAsap_t)( typedef BOOL (WINAPI *WinUsb_WriteIsochPipeAsap_t)(
WINUSB_ISOCH_BUFFER_HANDLE BufferHandle, WINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
ULONG Offset, ULONG Offset,
@ -531,37 +572,13 @@ typedef BOOL (WINAPI *WinUsb_WriteIsochPipeAsap_t)(
BOOL ContinueStream, BOOL ContinueStream,
LPOVERLAPPED Overlapped LPOVERLAPPED Overlapped
); );
typedef BOOL (WINAPI *WinUsb_WritePipe_t)(
typedef LONG USBD_STATUS;
typedef struct {
ULONG Offset;
ULONG Length;
USBD_STATUS Status;
} USBD_ISO_PACKET_DESCRIPTOR, *PUSBD_ISO_PACKET_DESCRIPTOR;
typedef BOOL (WINAPI *WinUsb_ReadIsochPipeAsap_t)(
PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
ULONG Offset,
ULONG Length,
BOOL ContinueStream,
ULONG NumberOfPackets,
PUSBD_ISO_PACKET_DESCRIPTOR IsoPacketDescriptors,
LPOVERLAPPED Overlapped
);
typedef struct {
USBD_PIPE_TYPE PipeType;
UCHAR PipeId;
USHORT MaximumPacketSize;
UCHAR Interval;
ULONG MaximumBytesPerInterval;
} WINUSB_PIPE_INFORMATION_EX, *PWINUSB_PIPE_INFORMATION_EX;
typedef BOOL (WINAPI *WinUsb_QueryPipeEx_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle, WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR AlternateInterfaceHandle, UCHAR PipeID,
UCHAR PipeIndex, PUCHAR Buffer,
PWINUSB_PIPE_INFORMATION_EX PipeInformationEx ULONG BufferLength,
PULONG LengthTransferred,
LPOVERLAPPED Overlapped
); );
/* /!\ These must match the ones from the official libusbk.h */ /* /!\ These must match the ones from the official libusbk.h */
@ -611,15 +628,19 @@ typedef struct _KLIB_VERSION {
} KLIB_VERSION, *PKLIB_VERSION; } KLIB_VERSION, *PKLIB_VERSION;
typedef BOOL (WINAPI *LibK_GetProcAddress_t)( typedef BOOL (WINAPI *LibK_GetProcAddress_t)(
PVOID *ProcAddress, PVOID ProcAddress,
ULONG DriverID, INT DriverID,
ULONG FunctionID INT FunctionID
); );
typedef VOID (WINAPI *LibK_GetVersion_t)( typedef VOID (WINAPI *LibK_GetVersion_t)(
PKLIB_VERSION Version PKLIB_VERSION Version
); );
typedef BOOL (WINAPI *LibK_ResetDevice_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle
);
//KISO_PACKET is equivalent of libusb_iso_packet_descriptor except uses absolute "offset" field instead of sequential Lengths //KISO_PACKET is equivalent of libusb_iso_packet_descriptor except uses absolute "offset" field instead of sequential Lengths
typedef struct _KISO_PACKET { typedef struct _KISO_PACKET {
UINT offset; UINT offset;
@ -642,7 +663,7 @@ typedef struct _KISO_CONTEXT {
KISO_PACKET IsoPackets[0]; KISO_PACKET IsoPackets[0];
} KISO_CONTEXT, *PKISO_CONTEXT; } KISO_CONTEXT, *PKISO_CONTEXT;
typedef BOOL(WINAPI *WinUsb_IsoReadPipe_t)( typedef BOOL(WINAPI *LibK_IsoReadPipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle, WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID, UCHAR PipeID,
PUCHAR Buffer, PUCHAR Buffer,
@ -651,7 +672,7 @@ typedef BOOL(WINAPI *WinUsb_IsoReadPipe_t)(
PKISO_CONTEXT IsoContext PKISO_CONTEXT IsoContext
); );
typedef BOOL(WINAPI *WinUsb_IsoWritePipe_t)( typedef BOOL(WINAPI *LibK_IsoWritePipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle, WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID, UCHAR PipeID,
PUCHAR Buffer, PUCHAR Buffer,
@ -661,8 +682,7 @@ typedef BOOL(WINAPI *WinUsb_IsoWritePipe_t)(
); );
struct winusb_interface { struct winusb_interface {
bool initialized; HMODULE hDll;
bool CancelIoEx_supported;
WinUsb_AbortPipe_t AbortPipe; WinUsb_AbortPipe_t AbortPipe;
WinUsb_ControlTransfer_t ControlTransfer; WinUsb_ControlTransfer_t ControlTransfer;
WinUsb_FlushPipe_t FlushPipe; WinUsb_FlushPipe_t FlushPipe;
@ -670,22 +690,27 @@ struct winusb_interface {
WinUsb_GetAssociatedInterface_t GetAssociatedInterface; WinUsb_GetAssociatedInterface_t GetAssociatedInterface;
WinUsb_Initialize_t Initialize; WinUsb_Initialize_t Initialize;
WinUsb_ReadPipe_t ReadPipe; WinUsb_ReadPipe_t ReadPipe;
WinUsb_ResetDevice_t ResetDevice;
WinUsb_ResetPipe_t ResetPipe; WinUsb_ResetPipe_t ResetPipe;
WinUsb_SetCurrentAlternateSetting_t SetCurrentAlternateSetting; WinUsb_SetCurrentAlternateSetting_t SetCurrentAlternateSetting;
WinUsb_SetPipePolicy_t SetPipePolicy; WinUsb_SetPipePolicy_t SetPipePolicy;
WinUsb_WritePipe_t WritePipe; WinUsb_WritePipe_t WritePipe;
union {
// Isochoronous functions for LibUSBk sub api: struct {
WinUsb_IsoReadPipe_t IsoReadPipe; // Isochoronous functions for libusbK sub api:
WinUsb_IsoWritePipe_t IsoWritePipe; LibK_IsoReadPipe_t IsoReadPipe;
LibK_IsoWritePipe_t IsoWritePipe;
// Isochronous functions for Microsoft WinUSB sub api (native WinUSB): // Reset device function for libusbK sub api:
LibK_ResetDevice_t ResetDevice;
};
struct {
// Isochronous functions for WinUSB sub api:
WinUsb_QueryPipeEx_t QueryPipeEx;
WinUsb_ReadIsochPipeAsap_t ReadIsochPipeAsap;
WinUsb_RegisterIsochBuffer_t RegisterIsochBuffer; WinUsb_RegisterIsochBuffer_t RegisterIsochBuffer;
WinUsb_UnregisterIsochBuffer_t UnregisterIsochBuffer; WinUsb_UnregisterIsochBuffer_t UnregisterIsochBuffer;
WinUsb_WriteIsochPipeAsap_t WriteIsochPipeAsap; WinUsb_WriteIsochPipeAsap_t WriteIsochPipeAsap;
WinUsb_ReadIsochPipeAsap_t ReadIsochPipeAsap; };
WinUsb_QueryPipeEx_t QueryPipeEx; };
}; };
/* hid.dll interface */ /* hid.dll interface */
@ -781,3 +806,5 @@ DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetNumInputBuffers, (HANDLE, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetPhysicalDescriptor, (HANDLE, PVOID, ULONG)); DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetPhysicalDescriptor, (HANDLE, PVOID, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_FlushQueue, (HANDLE)); DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_FlushQueue, (HANDLE));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidP_GetValueCaps, (HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PULONG, PHIDP_PREPARSED_DATA)); DLL_DECLARE_FUNC(WINAPI, BOOL, HidP_GetValueCaps, (HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PULONG, PHIDP_PREPARSED_DATA));
#endif

View file

@ -17,22 +17,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <config.h>
#include <locale.h>
#include <stdlib.h>
#include <string.h>
#if defined(HAVE_STRINGS_H)
#include <strings.h>
#endif
#include "libusbi.h" #include "libusbi.h"
#if defined(_MSC_VER) #include <ctype.h>
#define strncasecmp _strnicmp #include <string.h>
#endif
static size_t usbi_locale = 0;
/** \ingroup libusb_misc /** \ingroup libusb_misc
* How to add a new \ref libusb_strerror() translation: * How to add a new \ref libusb_strerror() translation:
@ -53,15 +41,15 @@ static size_t usbi_locale = 0;
* "Success", * "Success",
* ... * ...
* "Other error", * "Other error",
* } * },
* };\endcode </li> * };\endcode </li>
* <li> Translate each of the English messages from the section you copied into your language </li> * <li> Translate each of the English messages from the section you copied into your language </li>
* <li> Save the file (in UTF-8 format) and send it to \c libusb-devel\@lists.sourceforge.net </li> * <li> Save the file (in UTF-8 format) and send it to \c libusb-devel\@lists.sourceforge.net </li>
* </ol> * </ol>
*/ */
static const char* usbi_locale_supported[] = { "en", "nl", "fr", "ru", "de", "hu" }; static const char * const usbi_locale_supported[] = { "en", "nl", "fr", "ru", "de", "hu" };
static const char* usbi_localized_errors[ARRAYSIZE(usbi_locale_supported)][LIBUSB_ERROR_COUNT] = { static const char * const usbi_localized_errors[ARRAYSIZE(usbi_locale_supported)][LIBUSB_ERROR_COUNT] = {
{ /* English (en) */ { /* English (en) */
"Success", "Success",
"Input/Output Error", "Input/Output Error",
@ -122,7 +110,6 @@ static const char* usbi_localized_errors[ARRAYSIZE(usbi_locale_supported)][LIBUS
"Память исчерпана", "Память исчерпана",
"Операция не поддерживается данной платформой", "Операция не поддерживается данной платформой",
"Неизвестная ошибка" "Неизвестная ошибка"
}, { /* German (de) */ }, { /* German (de) */
"Erfolgreich", "Erfolgreich",
"Eingabe-/Ausgabefehler", "Eingabe-/Ausgabefehler",
@ -153,9 +140,11 @@ static const char* usbi_localized_errors[ARRAYSIZE(usbi_locale_supported)][LIBUS
"Nincs elég memória", "Nincs elég memória",
"A művelet nem támogatott ezen a rendszeren", "A művelet nem támogatott ezen a rendszeren",
"Általános hiba", "Általános hiba",
} },
}; };
static const char * const (*usbi_error_strings)[LIBUSB_ERROR_COUNT] = &usbi_localized_errors[0];
/** \ingroup libusb_misc /** \ingroup libusb_misc
* Set the language, and only the language, not the encoding! used for * Set the language, and only the language, not the encoding! used for
* translatable libusb messages. * translatable libusb messages.
@ -190,19 +179,20 @@ int API_EXPORTED libusb_setlocale(const char *locale)
{ {
size_t i; size_t i;
if ( (locale == NULL) || (strlen(locale) < 2) if (!locale || strlen(locale) < 2
|| ((strlen(locale) > 2) && (locale[2] != '-') && (locale[2] != '_') && (locale[2] != '.')) ) || (locale[2] != '\0' && locale[2] != '-' && locale[2] != '_' && locale[2] != '.'))
return LIBUSB_ERROR_INVALID_PARAM; return LIBUSB_ERROR_INVALID_PARAM;
for (i = 0; i < ARRAYSIZE(usbi_locale_supported); i++) { for (i = 0; i < ARRAYSIZE(usbi_locale_supported); i++) {
if (strncasecmp(usbi_locale_supported[i], locale, 2) == 0) if (usbi_locale_supported[i][0] == tolower((unsigned char)locale[0])
&& usbi_locale_supported[i][1] == tolower((unsigned char)locale[1]))
break; break;
} }
if (i >= ARRAYSIZE(usbi_locale_supported)) {
return LIBUSB_ERROR_NOT_FOUND;
}
usbi_locale = i; if (i == ARRAYSIZE(usbi_locale_supported))
return LIBUSB_ERROR_NOT_FOUND;
usbi_error_strings = &usbi_localized_errors[i];
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} }
@ -220,14 +210,14 @@ int API_EXPORTED libusb_setlocale(const char *locale)
* \param errcode the error code whose description is desired * \param errcode the error code whose description is desired
* \returns a short description of the error code in UTF-8 encoding * \returns a short description of the error code in UTF-8 encoding
*/ */
DEFAULT_VISIBILITY const char* LIBUSB_CALL libusb_strerror(enum libusb_error errcode) DEFAULT_VISIBILITY const char * LIBUSB_CALL libusb_strerror(int errcode)
{ {
int errcode_index = -errcode; int errcode_index = -errcode;
if ((errcode_index < 0) || (errcode_index >= LIBUSB_ERROR_COUNT)) { if (errcode_index < 0 || errcode_index >= LIBUSB_ERROR_COUNT) {
/* "Other Error", which should always be our last message, is returned */ /* "Other Error", which should always be our last message, is returned */
errcode_index = LIBUSB_ERROR_COUNT - 1; errcode_index = LIBUSB_ERROR_COUNT - 1;
} }
return usbi_localized_errors[usbi_locale][errcode_index]; return (*usbi_error_strings)[errcode_index];
} }

View file

@ -20,15 +20,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <config.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "libusbi.h" #include "libusbi.h"
#include <string.h>
/** /**
* @defgroup libusb_syncio Synchronous device I/O * @defgroup libusb_syncio Synchronous device I/O
* *
@ -62,7 +57,7 @@ static void sync_transfer_wait_for_completion(struct libusb_transfer *transfer)
} }
if (NULL == transfer->dev_handle) { if (NULL == transfer->dev_handle) {
/* transfer completion after libusb_close() */ /* transfer completion after libusb_close() */
transfer->status = LIBUSB_ERROR_NO_DEVICE; transfer->status = LIBUSB_TRANSFER_NO_DEVICE;
*completed = 1; *completed = 1;
} }
} }
@ -86,7 +81,7 @@ static void sync_transfer_wait_for_completion(struct libusb_transfer *transfer)
* (depending on direction bits within bmRequestType) * (depending on direction bits within bmRequestType)
* \param wLength the length field for the setup packet. The data buffer should * \param wLength the length field for the setup packet. The data buffer should
* be at least this size. * 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 * before giving up due to no response being received. For an unlimited
* timeout, use value 0. * timeout, use value 0.
* \returns on success, the number of bytes actually transferred * \returns on success, the number of bytes actually transferred
@ -96,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_NO_DEVICE if the device has been disconnected
* \returns LIBUSB_ERROR_BUSY if called from event handling context * \returns LIBUSB_ERROR_BUSY if called from event handling context
* \returns LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than * \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 * \returns another LIBUSB_ERROR code on other failures
*/ */
int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle, int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle,
@ -115,7 +110,7 @@ int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle,
if (!transfer) if (!transfer)
return LIBUSB_ERROR_NO_MEM; return LIBUSB_ERROR_NO_MEM;
buffer = (unsigned char*) malloc(LIBUSB_CONTROL_SETUP_SIZE + wLength); buffer = malloc(LIBUSB_CONTROL_SETUP_SIZE + wLength);
if (!buffer) { if (!buffer) {
libusb_free_transfer(transfer); libusb_free_transfer(transfer);
return LIBUSB_ERROR_NO_MEM; return LIBUSB_ERROR_NO_MEM;
@ -248,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 * 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 * 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 * 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 dev_handle a handle for the device to communicate with
* \param endpoint the address of a valid endpoint to communicate with * \param endpoint the address of a valid endpoint to communicate with
@ -260,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), * 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 * it is legal to pass a NULL pointer if you do not wish to receive this
* information. * 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 * before giving up due to no response being received. For an unlimited
* timeout, use value 0. * timeout, use value 0.
* *
@ -272,11 +267,13 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle,
* \ref libusb_packetoverflow * \ref libusb_packetoverflow
* \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
* \returns LIBUSB_ERROR_BUSY if called from event handling context * \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 * \returns another LIBUSB_ERROR code on other failures
*/ */
int API_EXPORTED libusb_bulk_transfer(struct libusb_device_handle *dev_handle, int API_EXPORTED libusb_bulk_transfer(libusb_device_handle *dev_handle,
unsigned char endpoint, unsigned char *data, int length, int *transferred, unsigned char endpoint, unsigned char *data, int length,
unsigned int timeout) int *transferred, unsigned int timeout)
{ {
return do_sync_bulk_transfer(dev_handle, endpoint, data, length, return do_sync_bulk_transfer(dev_handle, endpoint, data, length,
transferred, timeout, LIBUSB_TRANSFER_TYPE_BULK); transferred, timeout, LIBUSB_TRANSFER_TYPE_BULK);
@ -299,7 +296,7 @@ int API_EXPORTED libusb_bulk_transfer(struct libusb_device_handle *dev_handle,
* underlying O/S requirements, meaning that the timeout may expire after * 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 * 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 * 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. * The default endpoint bInterval value is used as the polling interval.
* *
@ -313,7 +310,7 @@ int API_EXPORTED libusb_bulk_transfer(struct libusb_device_handle *dev_handle,
* transferred. Since version 1.0.21 (\ref LIBUSB_API_VERSION >= 0x01000105), * 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 * it is legal to pass a NULL pointer if you do not wish to receive this
* information. * 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 * before giving up due to no response being received. For an unlimited
* timeout, use value 0. * timeout, use value 0.
* *
@ -324,11 +321,13 @@ int API_EXPORTED libusb_bulk_transfer(struct libusb_device_handle *dev_handle,
* \ref libusb_packetoverflow * \ref libusb_packetoverflow
* \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
* \returns LIBUSB_ERROR_BUSY if called from event handling context * \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 * \returns another LIBUSB_ERROR code on other error
*/ */
int API_EXPORTED libusb_interrupt_transfer( int API_EXPORTED libusb_interrupt_transfer(libusb_device_handle *dev_handle,
struct libusb_device_handle *dev_handle, unsigned char endpoint, unsigned char endpoint, unsigned char *data, int length,
unsigned char *data, int length, int *transferred, unsigned int timeout) int *transferred, unsigned int timeout)
{ {
return do_sync_bulk_transfer(dev_handle, endpoint, data, length, return do_sync_bulk_transfer(dev_handle, endpoint, data, length,
transferred, timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT); transferred, timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);

View file

@ -7,7 +7,7 @@
#define LIBUSB_MINOR 0 #define LIBUSB_MINOR 0
#endif #endif
#ifndef LIBUSB_MICRO #ifndef LIBUSB_MICRO
#define LIBUSB_MICRO 23 #define LIBUSB_MICRO 24
#endif #endif
#ifndef LIBUSB_NANO #ifndef LIBUSB_NANO
#define LIBUSB_NANO 0 #define LIBUSB_NANO 0

View file

@ -1 +1 @@
#define LIBUSB_NANO 11397 #define LIBUSB_NANO 11584

3
externals/libusb/libusb/msvc/.gitattributes vendored Executable file
View file

@ -0,0 +1,3 @@
*.sln eol=crlf
*.vcxproj eol=crlf
*.vcxproj.filters eol=crlf

View file

@ -5,18 +5,30 @@
#error "Please make sure the msvc/ directory is removed from your build path." #error "Please make sure the msvc/ directory is removed from your build path."
#endif #endif
/* Visual Studio 2013 or later is required */
#if (_MSC_VER < 1800)
#error "Visual Studio 2013 or later is required."
#endif
/* Visual Studio 2013 does not support __func__ */
#if (_MSC_VER < 1900)
#define __func__ __FUNCTION__
#endif
/* Visual Studio 2015 and later defines timespec */ /* Visual Studio 2015 and later defines timespec */
#if (_MSC_VER >= 1900) #if (_MSC_VER >= 1900)
#define _TIMESPEC_DEFINED 1 #define _TIMESPEC_DEFINED 1
#endif #endif
/* Disable: warning C4127: conditional expression is constant */
#pragma warning(disable:4127)
/* Disable: warning C4200: nonstandard extension used : zero-sized array in struct/union */ /* Disable: warning C4200: nonstandard extension used : zero-sized array in struct/union */
#pragma warning(disable:4200) #pragma warning(disable:4200)
/* Disable: warning C4201: nonstandard extension used : nameless struct/union */
#pragma warning(disable:4201)
/* Disable: warning C4324: structure was padded due to __declspec(align()) */ /* Disable: warning C4324: structure was padded due to __declspec(align()) */
#pragma warning(disable:4324) #pragma warning(disable:4324)
/* Disable: warning C6258: Using TerminateThread does not allow proper thread clean up */ /* Disable: warning C4996: 'GetVersionExA': was declared deprecated */
#pragma warning(disable:6258)
/* Disable: warning C4996: 'GetVersionA': was declared deprecated */
#pragma warning(disable:4996) #pragma warning(disable:4996)
#if defined(_PREFAST_) #if defined(_PREFAST_)
@ -26,26 +38,21 @@
#pragma warning(disable:28125) #pragma warning(disable:28125)
#endif #endif
/* Default visibility */ /* Define to the attribute for default visibility. */
#define DEFAULT_VISIBILITY /**/ #define DEFAULT_VISIBILITY /**/
/* Enable global message logging */ /* Define to 1 to start with debug message logging enabled. */
/* #undef ENABLE_DEBUG_LOGGING */
/* Define to 1 to enable message logging. */
#define ENABLE_LOGGING 1 #define ENABLE_LOGGING 1
/* Uncomment to start with debug message logging enabled */ /* Define to 1 if compiling for a Windows platform. */
// #define ENABLE_DEBUG_LOGGING 1 #define PLATFORM_WINDOWS 1
/* Uncomment to enabling logging to system log */ /* Define to the attribute for enabling parameter checks on printf-like
// #define USE_SYSTEM_LOGGING_FACILITY functions. */
#define PRINTF_FORMAT(a, b) /**/
/* type of second poll() argument */ /* Define to 1 to output logging messages to the systemwide log. */
#define POLL_NFDS_TYPE unsigned int /* #undef USE_SYSTEM_LOGGING_FACILITY */
/* Windows/WinCE backend */
#if defined(_WIN32_WCE)
#define OS_WINCE 1
#define HAVE_MISSING_H
#else
#define OS_WINDOWS 1
#define HAVE_SYS_TYPES_H 1
#endif

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

106
externals/libusb/libusb/msvc/dpfp_2017.vcxproj vendored Executable file
View file

@ -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>

View file

@ -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>

106
externals/libusb/libusb/msvc/dpfp_2019.vcxproj vendored Executable file
View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

Some files were not shown because too many files have changed in this diff Show more